diff --git a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C
index 3779ff20d3c396679e015bf4d922a478330b1aa7..48b65330f9e093dd2a119ced4c10b9f292529fa7 100644
--- a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C
+++ b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C
@@ -32,6 +32,7 @@ License
 #include "mapPolyMesh.H"
 #include "volFields.H"
 #include "HashOps.H"
+#include "ListOps.H"
 #include "Time.H"
 #include "UIndirectList.H"
 #include "addToRunTimeSelectionTable.H"
@@ -168,12 +169,18 @@ void Foam::sampledSurfaces::countFields()
     forAll(*this, surfi)
     {
         const sampledSurface& s = (*this)[surfi];
+        surfaceWriter& outWriter = writers_[surfi];
 
-        writers_[surfi].nFields() =
+        outWriter.nFields() =
         (
             nVolumeFields
           + (s.withSurfaceFields() ? nSurfaceFields : 0)
-          + ((s.hasFaceIds() && !s.interpolate()) ? 1 : 0)
+          +
+            (
+                // Face-id field, but not if the writer manages that itself
+                !s.interpolate() && s.hasFaceIds() && !outWriter.usesFaceIds()
+              ? 1 : 0
+            )
         );
     }
 }
@@ -319,7 +326,7 @@ bool Foam::sampledSurfaces::read(const dictionary& dict)
             const dictionary& surfDict = dEntry.dict();
 
             autoPtr<sampledSurface> surf =
-            sampledSurface::New
+                sampledSurface::New
                 (
                     dEntry.keyword(),
                     mesh_,
@@ -555,20 +562,29 @@ bool Foam::sampledSurfaces::performAction(unsigned request)
 
             outWriter.beginTime(obr_.time());
 
-            // Write original ids
-            if (s.hasFaceIds() && !s.interpolate())
+            // Face-id field, but not if the writer manages that itself
+            if (!s.interpolate() && s.hasFaceIds() && !outWriter.usesFaceIds())
             {
                 // This is still quite horrible.
 
                 Field<label> ids(s.faceIds());
-                ids += label(1);  // From 0-based to 1-based
 
-                writeSurface
+                if
                 (
-                    outWriter,
-                    ids,
-                    "Ids"
-                );
+                    returnReduce
+                    (
+                        !ListOps::found(ids, lessOp1<label>(0)),
+                        andOp<bool>()
+                    )
+                )
+                {
+                    // From 0-based to 1-based, provided there are no
+                    // negative ids (eg, encoded solid/side)
+
+                    ids += label(1);
+                }
+
+                writeSurface(outWriter, ids, "Ids");
             }
         }
     }
diff --git a/src/surfMesh/surfaceFormats/abaqus/ABAQUSsurfaceFormat.C b/src/surfMesh/surfaceFormats/abaqus/ABAQUSsurfaceFormat.C
index 810fb2c17968cf5cfcf15a8aa06629e439cb25af..72ebcfc65e22452b43cec5d370a70f06ff335091 100644
--- a/src/surfMesh/surfaceFormats/abaqus/ABAQUSsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/abaqus/ABAQUSsurfaceFormat.C
@@ -26,10 +26,10 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "ABAQUSsurfaceFormat.H"
+#include "ListOps.H"
 #include "IFstream.H"
 #include "IOmanip.H"
 #include "faceTraits.H"
-#include "stringOps.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -267,13 +267,17 @@ void Foam::fileFormats::ABAQUSsurfaceFormat<Face>::write
     const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
 
     // Possible to use faceIds?
+    // - cannot if there are negative ids (eg, encoded solid/side)
     bool useOrigFaceIds =
-        (!useFaceMap && elemIds.size() == faceLst.size());
+    (
+        !useFaceMap
+     && elemIds.size() == faceLst.size()
+     && !ListOps::found(elemIds, lessOp1<label>(0))
+    );
 
+    // Not possible with on-the-fly face decomposition
     if (useOrigFaceIds)
     {
-        // Not possible with on-the-fly face decomposition
-
         for (const auto& f : faceLst)
         {
             if (f.size() > 4)
diff --git a/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C b/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C
index b76b3562e7a0d5a39f4bb78ee63119e76aadcab3..ad4e03eab61ddd369f2ce7a5eab087f2518bc959 100644
--- a/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C
@@ -27,6 +27,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "NASsurfaceFormat.H"
+#include "ListOps.H"
 #include "IFstream.H"
 #include "IOmanip.H"
 #include "faceTraits.H"
@@ -458,13 +459,17 @@ void Foam::fileFormats::NASsurfaceFormat<Face>::write
     const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
 
     // Possible to use faceIds?
+    // - cannot if there are negative ids (eg, encoded solid/side)
     bool useOrigFaceIds =
-        (!useFaceMap && elemIds.size() == faceLst.size());
+    (
+        !useFaceMap
+     && elemIds.size() == faceLst.size()
+     && !ListOps::found(elemIds, lessOp1<label>(0))
+    );
 
+    // Not possible with on-the-fly face decomposition
     if (useOrigFaceIds)
     {
-        // Not possible with on-the-fly face decomposition
-
         for (const auto& f : faceLst)
         {
             if (f.size() > 4)
diff --git a/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormat.C b/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormat.C
index d1db77d26f7601b64d697dba228e6bf372241c8b..3914fa32566d3a11a6bae213da508e6268b85cf7 100644
--- a/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormat.C
@@ -284,11 +284,12 @@ void Foam::fileFormats::STARCDsurfaceFormat<Face>::write
     const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
 
     // Possible to use faceIds?
+    // - cannot if there are negative ids (eg, encoded solid/side)
     const bool useOrigFaceIds =
     (
         !useFaceMap
-     && surf.useFaceIds()
      && elemIds.size() == faceLst.size()
+     && !ListOps::found(elemIds, lessOp1<label>(0))
     );
 
 
diff --git a/src/surfMesh/writers/nastran/nastranSurfaceWriter.C b/src/surfMesh/writers/nastran/nastranSurfaceWriter.C
index c5c4dfbb2d270ce9803cecfb76e0cfd6b0d73811..5f377ab46b89a252117eafe2b702a6ab1d52cc74 100644
--- a/src/surfMesh/writers/nastran/nastranSurfaceWriter.C
+++ b/src/surfMesh/writers/nastran/nastranSurfaceWriter.C
@@ -29,6 +29,7 @@ License
 #include "nastranSurfaceWriter.H"
 #include "Pair.H"
 #include "IOmanip.H"
+#include "ListOps.H"
 #include "OSspecific.H"
 #include "surfaceWriterMethods.H"
 #include "addToRunTimeSelectionTable.H"
@@ -214,11 +215,15 @@ void Foam::surfaceWriters::nastranWriter::writeGeometry
     const labelList& elemIds = surf.faceIds();
 
     // Possible to use faceIds?
-    bool useOrigFaceIds = (elemIds.size() == faces.size());
+    bool useOrigFaceIds =
+    (
+        elemIds.size() == faces.size()
+     && !ListOps::found(elemIds, lessOp1<label>(0))
+    );
 
+    // Not possible with on-the-fly face decomposition
     if (useOrigFaceIds)
     {
-        // Not possible with on-the-fly face decomposition
         for (const auto& f : faces)
         {
             if (f.size() > 4)
@@ -258,7 +263,6 @@ void Foam::surfaceWriters::nastranWriter::writeGeometry
 
         if (useOrigFaceIds)
         {
-            // When available and not decomposed
             elemId = elemIds[facei];
         }
 
diff --git a/src/surfMesh/writers/nastran/nastranSurfaceWriter.H b/src/surfMesh/writers/nastran/nastranSurfaceWriter.H
index a56169167bedfef3e549d2a9aee33f4d2b055fb6..c22c082cb97a385c96086d024d9a46deb8024949 100644
--- a/src/surfMesh/writers/nastran/nastranSurfaceWriter.H
+++ b/src/surfMesh/writers/nastran/nastranSurfaceWriter.H
@@ -254,6 +254,12 @@ public:
 
     // Member Functions
 
+        //- Format uses faceIds as part of its output
+        virtual bool usesFaceIds() const // override
+        {
+            return true;
+        }
+
         //- Write surface geometry to file.
         virtual fileName write(); // override
 
diff --git a/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C b/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C
index bcffc522e3047040ca55c6e4804143a9f401267c..a417f374c2599a69e5bc570ed58faf561f8ab6df 100644
--- a/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C
+++ b/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C
@@ -28,6 +28,7 @@ License
 
 #include "OFstream.H"
 #include "IOmanip.H"
+#include "ListOps.H"
 #include "OSspecific.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
@@ -254,13 +255,13 @@ Foam::fileName Foam::surfaceWriters::nastranWriter::writeTemplate
 
         // Regular (undecomposed) faces
         const faceList& faces = surf.faces();
-        const labelList& elemIds = surf.faceIds();
+        const labelUList& elemIds = surf.faceIds();
 
         // Possible to use faceIds?
-        // Not possible with on-the-fly face decomposition
         const bool useOrigFaceIds =
         (
             elemIds.size() == faces.size()
+         && !ListOps::found(elemIds, lessOp1<label>(0))
          && decompFaces.empty()
         );
 
@@ -273,7 +274,6 @@ Foam::fileName Foam::surfaceWriters::nastranWriter::writeTemplate
             {
                 if (useOrigFaceIds)
                 {
-                    // When available and not decomposed
                     elemId = elemIds[facei];
                 }
 
@@ -324,7 +324,6 @@ Foam::fileName Foam::surfaceWriters::nastranWriter::writeTemplate
             {
                 if (useOrigFaceIds)
                 {
-                    // When available and not decomposed
                     elemId = elemIds[facei];
                 }
 
diff --git a/src/surfMesh/writers/starcd/starcdSurfaceWriter.C b/src/surfMesh/writers/starcd/starcdSurfaceWriter.C
index 0aa30d2a81171078ceb3518f63f223fb466f1c28..b036e14d284a6c4b312a94b1af536a0253dda317 100644
--- a/src/surfMesh/writers/starcd/starcdSurfaceWriter.C
+++ b/src/surfMesh/writers/starcd/starcdSurfaceWriter.C
@@ -27,6 +27,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "starcdSurfaceWriter.H"
+#include "ListOps.H"
 #include "OFstream.H"
 #include "OSspecific.H"
 #include "MeshedSurfaceProxy.H"
@@ -53,7 +54,7 @@ namespace Foam
     template<class Type>
     static inline void writeData(Ostream& os, const Type& val)
     {
-        for (direction cmpt=0; cmpt <  pTraits<Type>::nComponents; ++cmpt)
+        for (direction cmpt=0; cmpt < pTraits<Type>::nComponents; ++cmpt)
         {
             os  << ' ' << component(val, cmpt);
         }
@@ -145,13 +146,23 @@ Foam::fileName Foam::surfaceWriters::starcdWriter::write()
             mkDir(outputFile.path());
         }
 
+        const labelUList& origFaceIds = surf.faceIds();
+
+        // Face ids (if possible)
+        const labelUList& elemIds =
+        (
+            !ListOps::found(origFaceIds, lessOp1<label>(0))
+          ? origFaceIds
+          : labelUList::null()
+        );
+
         MeshedSurfaceProxy<face>
         (
             surf.points(),
             surf.faces(),
             UList<surfZone>::null(), // one zone
             labelUList::null(),      // no faceMap
-            surf.faceIds()           // with face ids (if possible)
+            elemIds                  // face ids
         ).write
         (
             outputFile,
@@ -204,6 +215,8 @@ Foam::fileName Foam::surfaceWriters::starcdWriter::writeTemplate
     // geometry merge() implicit
     tmp<Field<Type>> tfield = mergeField(localValues);
 
+    const meshedSurf& surf = surface();
+
     if (Pstream::master() || !parallel_)
     {
         const auto& values = tfield();
@@ -215,16 +228,26 @@ Foam::fileName Foam::surfaceWriters::starcdWriter::writeTemplate
 
         OFstream os(outputFile, streamOpt_);
 
-        // 1-based ids
-        label elemId = 1;
+        const labelUList& elemIds = surf.faceIds();
+
+        // Possible to use faceIds?
+        const bool useOrigFaceIds =
+        (
+            elemIds.size() == values.size()
+         && !ListOps::found(elemIds, lessOp1<label>(0))
+        );
+
+        label faceIndex = 0;
 
         // No header, just write values
         for (const Type& val : values)
         {
-            os  << elemId;
-            writeData(os, val);
+            const label elemId =
+                (useOrigFaceIds ? elemIds[faceIndex] : faceIndex);
 
-            ++elemId;
+            os  << (elemId + 1);  // 1-based ids
+            writeData(os, val);
+            ++faceIndex;
         }
     }
 
diff --git a/src/surfMesh/writers/starcd/starcdSurfaceWriter.H b/src/surfMesh/writers/starcd/starcdSurfaceWriter.H
index 4e3b525029895e4bb1fdbfe7a58c9faf3fcc63b8..0955d210370b512b6ca18310d8bbb534e141745c 100644
--- a/src/surfMesh/writers/starcd/starcdSurfaceWriter.H
+++ b/src/surfMesh/writers/starcd/starcdSurfaceWriter.H
@@ -159,6 +159,12 @@ public:
             return true;
         }
 
+        //- Format uses faceIds as part of its output
+        virtual bool usesFaceIds() const // override
+        {
+            return true;
+        }
+
         //- Write surface geometry to file.
         virtual fileName write(); // override
 
diff --git a/src/surfMesh/writers/surfaceWriter.H b/src/surfMesh/writers/surfaceWriter.H
index 7813347d3be287c8cfa249da857f66ed55470cbf..c1142e88b86352f2705ea189c8ca8262d1e580e9 100644
--- a/src/surfMesh/writers/surfaceWriter.H
+++ b/src/surfMesh/writers/surfaceWriter.H
@@ -300,6 +300,14 @@ public:
             return false;
         }
 
+        //- True if the writer format uses faceIds as part of its output.
+        //  Element ids are used by various CAE formats
+        //  (abaqus, nastran, starcd, ...)
+        virtual bool usesFaceIds() const
+        {
+            return false;
+        }
+
 
     // Bookkeeping