diff --git a/src/surfMesh/Make/files b/src/surfMesh/Make/files
index 52966fd300..9d786fb75a 100644
--- a/src/surfMesh/Make/files
+++ b/src/surfMesh/Make/files
@@ -67,6 +67,7 @@ writers = writers
$(writers)/common/surfaceWriter.C
$(writers)/abaqus/abaqusSurfaceWriter.C
$(writers)/boundary/boundaryDataSurfaceWriter.C
+$(writers)/debug/debugSurfaceWriter.C
$(writers)/ensight/ensightSurfaceWriter.C
$(writers)/foam/foamSurfaceWriter.C
$(writers)/nastran/nastranSurfaceWriter.C
diff --git a/src/surfMesh/writers/debug/debugSurfaceWriter.C b/src/surfMesh/writers/debug/debugSurfaceWriter.C
new file mode 100644
index 0000000000..231d397ea0
--- /dev/null
+++ b/src/surfMesh/writers/debug/debugSurfaceWriter.C
@@ -0,0 +1,410 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2022 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 "debugSurfaceWriter.H"
+#include "globalIndex.H"
+#include "argList.H"
+#include "OFstream.H"
+#include "OSspecific.H"
+#include "IOmanip.H"
+#include "Time.H"
+#include "pointIOField.H"
+#include "primitivePatch.H"
+#include "profiling.H"
+#include "surfaceWriterMethods.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace surfaceWriters
+{
+ defineTypeName(debugWriter);
+ addToRunTimeSelectionTable(surfaceWriter, debugWriter, word);
+ addToRunTimeSelectionTable(surfaceWriter, debugWriter, wordDict);
+}
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
+
+template
+Foam::tmp>
+Foam::surfaceWriters::debugWriter::mergeField
+(
+ const Field& fld
+) const
+{
+ addProfiling
+ (
+ merge,
+ "debugWriter::merge-field"
+ );
+
+ if (parallel_ && Pstream::parRun())
+ {
+ // Ensure geometry is also merged
+ merge();
+
+ // Gather all values
+ auto tfield = tmp>::New();
+ auto& allFld = tfield.ref();
+
+ if (mpiGatherv_)
+ {
+ globalIndex::mpiGatherOp
+ (
+ fld,
+ allFld,
+ UPstream::worldComm,
+ commType_,
+ (UPstream::msgType() + msgTag_)
+ );
+ }
+ else
+ {
+ globalIndex::gatherOp
+ (
+ fld,
+ allFld,
+ UPstream::worldComm,
+ commType_,
+ (UPstream::msgType() + msgTag_)
+ );
+ }
+
+ // Renumber (point data) to correspond to merged points
+ if
+ (
+ Pstream::master()
+ && this->isPointData()
+ && mergedSurf_.pointsMap().size()
+ )
+ {
+ inplaceReorder(mergedSurf_.pointsMap(), allFld);
+ allFld.resize(mergedSurf_.points().size());
+ }
+
+ return tfield;
+ }
+
+ // Mark that any geometry changes have been taken care of
+ upToDate_ = true;
+
+ return fld;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::surfaceWriters::debugWriter::debugWriter()
+:
+ surfaceWriter(),
+ commType_(UPstream::commsTypes::nonBlocking),
+ mpiGatherv_(false),
+ enableWrite_(false),
+ header_(true),
+ msgTag_(0),
+ streamOpt_(IOstreamOption::BINARY)
+{}
+
+
+Foam::surfaceWriters::debugWriter::debugWriter
+(
+ const dictionary& options
+)
+:
+ surfaceWriter(options),
+ commType_
+ (
+ UPstream::commsTypeNames.getOrDefault
+ (
+ "commsType",
+ options,
+ UPstream::commsTypes::nonBlocking
+ )
+ ),
+ mpiGatherv_(options.getOrDefault("gatherv", false)),
+ enableWrite_(options.getOrDefault("write", false)),
+ header_(true),
+ msgTag_(options.getOrDefault("msgTag", 0)),
+ streamOpt_(IOstreamOption::BINARY)
+{
+ Info<< "Using debug surface writer ("
+ << (this->isPointData() ? "point" : "face") << " data):"
+ << " commsType=" << UPstream::commsTypeNames[commType_]
+ << " msgTag=" << msgTag_
+ << " gatherv=" << Switch::name(mpiGatherv_)
+ << " write=" << Switch::name(enableWrite_) << endl;
+}
+
+
+Foam::surfaceWriters::debugWriter::debugWriter
+(
+ const meshedSurf& surf,
+ const fileName& outputPath,
+ bool parallel,
+ const dictionary& options
+)
+:
+ debugWriter(options)
+{
+ open(surf, outputPath, parallel);
+}
+
+
+Foam::surfaceWriters::debugWriter::debugWriter
+(
+ const pointField& points,
+ const faceList& faces,
+ const fileName& outputPath,
+ bool parallel,
+ const dictionary& options
+)
+:
+ debugWriter(options)
+{
+ open(points, faces, outputPath, parallel);
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+void Foam::surfaceWriters::debugWriter::serialWriteGeometry
+(
+ const regIOobject& iopts,
+ const meshedSurf& surf
+)
+{
+ const pointField& points = surf.points();
+ const faceList& faces = surf.faces();
+
+ if (verbose_)
+ {
+ if (this->isPointData())
+ {
+ Info<< "Writing points: " << iopts.objectPath() << endl;
+ }
+ else
+ {
+ Info<< "Writing face centres: " << iopts.objectPath() << endl;
+ }
+ }
+
+ // Like regIOobject::writeObject without instance() adaptation
+ // since this would write to e.g. 0/ instead of postProcessing/
+
+ autoPtr ppPtr;
+
+ {
+ OFstream os(iopts.objectPath(), streamOpt_);
+
+ if (header_)
+ {
+ iopts.writeHeader(os);
+ }
+
+ if (this->isPointData())
+ {
+ // Just like writeData, but without copying beforehand
+ os << points;
+ }
+ else
+ {
+ ppPtr.reset(new primitivePatch(SubList(faces), points));
+
+ // Just like writeData, but without copying beforehand
+ os << ppPtr().faceCentres();
+ }
+
+ if (header_)
+ {
+ IOobject::writeEndDivider(os);
+ }
+ }
+}
+
+
+Foam::fileName Foam::surfaceWriters::debugWriter::write()
+{
+ checkOpen();
+
+ // Geometry: rootdir/surfaceName/"points"
+ // Field: rootdir/surfaceName/