diff --git a/src/functionObjects/utilities/Make/files b/src/functionObjects/utilities/Make/files
index aed6a6fa70..9da1341dfa 100644
--- a/src/functionObjects/utilities/Make/files
+++ b/src/functionObjects/utilities/Make/files
@@ -9,6 +9,17 @@ areaWrite/areaWrite.C
ensightWrite/ensightWrite.C
ensightWrite/ensightWriteUpdate.C
+foamReport/foamReport.C
+foamReport/substitutionModels/substitutionModel/substitutionModel.C
+foamReport/substitutionModels/substitutionModel/substitutionModelNew.C
+foamReport/substitutionModels/dictionaryValue/dictionaryValue.C
+foamReport/substitutionModels/functionObjectValue/functionObjectValue.C
+foamReport/substitutionModels/fileRegEx/fileRegEx.C
+foamReport/substitutionModels/environmentVariable/environmentVariable.C
+foamReport/substitutionModels/userValue/userValue.C
+
+graphFunctionObject/graphFunctionObject.C
+
vtkWrite/vtkWrite.C
vtkWrite/vtkWriteUpdate.C
diff --git a/src/functionObjects/utilities/foamReport/foamReport.C b/src/functionObjects/utilities/foamReport/foamReport.C
new file mode 100644
index 0000000000..349fbf777b
--- /dev/null
+++ b/src/functionObjects/utilities/foamReport/foamReport.C
@@ -0,0 +1,350 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2024 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamReport.H"
+#include "addToRunTimeSelectionTable.H"
+#include "argList.H"
+#include "clock.H"
+#include "cloud.H"
+#include "foamVersion.H"
+#include "fvMesh.H"
+#include "IFstream.H"
+#include "stringOps.H"
+#include "substitutionModel.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace functionObjects
+{
+ defineTypeNameAndDebug(foamReport, 0);
+ addToRunTimeSelectionTable(functionObject, foamReport, dictionary);
+}
+}
+
+
+// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
+
+void Foam::functionObjects::foamReport::setStaticBuiltins()
+{
+ substitutionModel::addBuiltinStr("OF_HOST", Foam::hostName());
+ substitutionModel::addBuiltinStr
+ (
+ "OF_PROC_ZERO_DIR",
+ Pstream::parRun() ? "processor0" : ""
+ );
+
+ substitutionModel::addBuiltin("OF_API", foamVersion::api);
+ substitutionModel::addBuiltinStr("OF_PATCH", foamVersion::patch);
+ substitutionModel::addBuiltinStr("OF_BUILD", foamVersion::build);
+ substitutionModel::addBuiltinStr("OF_BUILD_ARCH", foamVersion::buildArch);
+ substitutionModel::addBuiltinStr("OF_VERSION", foamVersion::version);
+
+ substitutionModel::addBuiltinStr("OF_DATE_START", clock::date());
+ substitutionModel::addBuiltinStr("OF_CLOCK_START", clock::clockTime());
+
+ substitutionModel::addBuiltinStr("OF_EXECUTABLE", argList::envExecutable());
+ substitutionModel::addBuiltinStr("OF_CASE_PATH", argList::envGlobalPath());
+ substitutionModel::addBuiltinStr("OF_CASE_NAME", time().globalCaseName());
+
+ substitutionModel::addBuiltin("OF_NPROCS", Pstream::nProcs());
+
+ // Set mesh builtins when there is only 1 mesh
+ const auto meshes = time_.lookupClass();
+ if (meshes.size() == 1)
+ {
+ const auto& mesh = *(meshes.begin().val());
+ substitutionModel::addBuiltin("OF_MESH_NCELLS", mesh.nCells());
+ substitutionModel::addBuiltin("OF_MESH_NFACES", mesh.nFaces());
+ substitutionModel::addBuiltin("OF_MESH_NEDGES", mesh.nEdges());
+ substitutionModel::addBuiltin("OF_MESH_NPOINTS", mesh.nPoints());
+ substitutionModel::addBuiltin
+ (
+ "OF_MESH_NINTERNALFACES",
+ mesh.nInternalFaces()
+ );
+ substitutionModel::addBuiltin
+ (
+ "OF_MESH_NBOUNDARYFACES",
+ mesh.nBoundaryFaces()
+ );
+ substitutionModel::addBuiltin
+ (
+ "OF_MESH_NPATCHES",
+ mesh.boundaryMesh().nNonProcessor()
+ );
+ substitutionModel::addBuiltin
+ (
+ "OF_MESH_BOUNDS_MIN",
+ mesh.bounds().min()
+ );
+ substitutionModel::addBuiltin
+ (
+ "OF_MESH_BOUNDS_MAX",
+ mesh.bounds().max()
+ );
+ }
+}
+
+
+void Foam::functionObjects::foamReport::setDynamicBuiltins()
+{
+ // Overwrite existing entries
+ substitutionModel::setBuiltinStr("OF_TIME", time().timeName());
+ substitutionModel::setBuiltin("OF_NTIMES", time().times().size());
+ substitutionModel::setBuiltin("OF_TIME_INDEX", time().timeIndex());
+ substitutionModel::setBuiltin("OF_TIME_DELTAT", time().deltaTValue());
+
+ substitutionModel::setBuiltinStr("OF_DATE_NOW", clock::date());
+ substitutionModel::setBuiltinStr("OF_CLOCK_NOW", clock::clockTime());
+
+ substitutionModel::setBuiltin("OF_NREGIONS", time().names().size());
+ substitutionModel::setBuiltin("OF_NCLOUDS", time().names().size());
+}
+
+
+bool Foam::functionObjects::foamReport::parseTemplate(const fileName& fName)
+{
+ Info<< " Reading template from " << fName << endl;
+
+ IFstream is(fName);
+
+ if (!is.good())
+ {
+ FatalErrorInFunction
+ << "Unable to open file " << fName << endl;
+ }
+
+ DynamicList contents;
+ string buffer;
+
+ label lineNo = 0;
+ while (is.good())
+ {
+ is.getLine(buffer);
+
+ // Collect keys for this line and clean the buffer
+ const wordList keys(substitutionModel::getKeys(buffer));
+
+ Tuple2