diff --git a/src/sampling/Make/files b/src/sampling/Make/files
index 649f05523d..118a48cab4 100644
--- a/src/sampling/Make/files
+++ b/src/sampling/Make/files
@@ -55,6 +55,7 @@ $(surfWriters)/surfaceWriter.C
$(surfWriters)/dx/dxSurfaceWriter.C
$(surfWriters)/ensight/ensightSurfaceWriter.C
$(surfWriters)/foamFile/foamFileSurfaceWriter.C
+$(surfWriters)/nastran/nastranSurfaceWriter.C
$(surfWriters)/proxy/proxySurfaceWriter.C
$(surfWriters)/raw/rawSurfaceWriter.C
$(surfWriters)/starcd/starcdSurfaceWriter.C
diff --git a/src/sampling/sampledSurface/writers/nastran/nastranSurfaceWriter.C b/src/sampling/sampledSurface/writers/nastran/nastranSurfaceWriter.C
new file mode 100644
index 0000000000..3a67a8dd23
--- /dev/null
+++ b/src/sampling/sampledSurface/writers/nastran/nastranSurfaceWriter.C
@@ -0,0 +1,372 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+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 "nastranSurfaceWriter.H"
+#include "IOmanip.H"
+#include "Tuple2.H"
+#include "makeSurfaceWriterMethods.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+ makeSurfaceWriterType(nastranSurfaceWriter);
+ addToRunTimeSelectionTable(surfaceWriter, nastranSurfaceWriter, wordDict);
+
+ // create write methods
+ defineSurfaceWriterWriteFields(nastranSurfaceWriter);
+
+ template<>
+ const char* NamedEnum::names[] =
+ {
+ "short",
+ "long",
+ "free"
+ };
+
+ const NamedEnum
+ nastranSurfaceWriter::writeFormatNames_;
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
+
+void Foam::nastranSurfaceWriter::formatOS(OFstream& os) const
+{
+ os.setf(ios_base::scientific);
+
+ // capitalise the E marker
+ os.setf(ios_base::uppercase);
+
+ label prec = 0;
+ label offset = 7;
+ switch (writeFormat_)
+ {
+ case (wfShort):
+ case (wfFree):
+ {
+ prec = 8 - offset;
+ break;
+ }
+ case (wfLong):
+ {
+ prec = 16 - offset;
+ break;
+ }
+ default:
+ {
+ }
+ }
+
+ os.precision(prec);
+}
+
+
+void Foam::nastranSurfaceWriter::writeCoord
+(
+ const point& p,
+ label& nPoint,
+ label& continuation,
+ Ostream& os
+) const
+{
+ // Fixed short/long formats:
+ // 1 GRID
+ // 2 ID : point ID
+ // 3 CP : co-ordinate system ID (blank)
+ // 4 X1 : point x cp-ordinate
+ // 5 X2 : point x cp-ordinate
+ // 6 X3 : point x cp-ordinate
+ // 7 CD : co-ordinate system for displacements (blank)
+ // 8 PS : single point constraints (blank)
+ // 9 SEID : super-element ID
+
+ switch (writeFormat_)
+ {
+ case wfShort:
+ {
+ os << setw(8) << "GRID"
+ << setw(8) << ++nPoint
+ << " "
+ << setw(8) << p.x()
+ << setw(8) << p.y()
+ << setw(8) << p.z()
+ << nl;
+
+ break;
+ }
+ case wfLong:
+ {
+ os << setw(8) << "GRID*"
+ << setw(16) << ++nPoint
+ << " "
+ << setw(16) << p.x()
+ << setw(16) << p.y()
+ << setw(8) << ++continuation
+ << nl
+ << setw(8) << continuation
+ << setw(16) << p.z()
+ << nl;
+
+ break;
+ }
+ case wfFree:
+ {
+ os << "GRID"
+ << ',' << ++nPoint
+ << ','
+ << ',' << p.x()
+ << ',' << p.y()
+ << ',' << p.z()
+ << nl;
+
+ break;
+ }
+ default:
+ {
+ FatalErrorIn
+ (
+ "void Foam::nastranSurfaceWriter::writeCoord"
+ "("
+ "Ostream&, "
+ "const point&"
+ ") const"
+ ) << "Unknown writeFormat enumeration" << abort(FatalError);
+ }
+ }
+}
+
+void Foam::nastranSurfaceWriter::writeFace
+(
+ const word& faceType,
+ const labelList& facePts,
+ label& nFace,
+ Ostream& os
+) const
+{
+ // Only valid surface elements are CTRIA3 and CQUAD4
+
+ // Fixed short/long formats:
+ // 1 CQUAD4
+ // 2 EID : element ID
+ // 3 PID : property element ID; default = EID (blank)
+ // 4 G1 : grid point index
+ // 5 G2 : grid point index
+ // 6 G3 : grid point index
+ // 7 G4 : grid point index
+ // 8 onwards - not used
+
+ // For CTRIA3 elements, cols 7 onwards are not used
+
+ switch (writeFormat_)
+ {
+ case wfShort:
+ case wfLong:
+ {
+ os << setw(8) << faceType
+ << setw(8) << ++nFace
+ << " ";
+
+ forAll(facePts, i)
+ {
+ os << setw(8) << facePts[i];
+ }
+
+ os << nl;
+
+ break;
+ }
+ case wfFree:
+ {
+ os << faceType << ','
+ << ++nFace << ',';
+
+ forAll(facePts, i)
+ {
+ os << ',' << facePts[i];
+ }
+
+ os << nl;
+
+ break;
+ }
+ default:
+ {
+ FatalErrorIn
+ (
+ "void Foam::nastranSurfaceWriter::writeFace"
+ "("
+ "const word&"
+ "const labelList&"
+ "label&"
+ "Ostream&, "
+ ") const"
+ ) << "Unknown writeFormat enumeration" << abort(FatalError);
+ }
+ }
+
+}
+
+
+void Foam::nastranSurfaceWriter::writeGeometry
+(
+ const pointField& points,
+ const faceList& faces,
+ List >& decomposedFaces,
+ Ostream& os
+) const
+{
+ // write points
+
+ os << "$" << nl
+ << "$ Points" << nl
+ << "$" << nl;
+
+ label nPoint = 0;
+ label continuation = 0;
+
+ forAll(points, pointI)
+ {
+ writeCoord(points[pointI], nPoint, continuation, os);
+ }
+
+
+ // write faces
+
+ os << "$" << nl
+ << "$ Faces" << nl
+ << "$" << nl;
+
+ label nFace = 0;
+
+ forAll(faces, faceI)
+ {
+ const face& f = faces[faceI];
+
+ if (f.size() == 3)
+ {
+ writeFace("CTRIA3", faces[faceI], nFace, os);
+ decomposedFaces[faceI].append(faces[faceI]);
+ }
+ else if (f.size() == 4)
+ {
+ writeFace("CQUAD4", faces[faceI], nFace, os);
+ decomposedFaces[faceI].append(faces[faceI]);
+ }
+ else
+ {
+ // decompose poly face into tris
+ label nTri = 0;
+ faceList triFaces;
+ f.triangles(points, nTri, triFaces);
+
+ forAll(triFaces, triI)
+ {
+ writeFace("CTRIA3", triFaces[triI], nFace, os);
+ decomposedFaces[faceI].append(triFaces[triI]);
+ }
+ }
+ }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::nastranSurfaceWriter::nastranSurfaceWriter()
+:
+ surfaceWriter(),
+ writeFormat_(wfShort),
+ fieldMap_()
+{}
+
+
+Foam::nastranSurfaceWriter::nastranSurfaceWriter(const dictionary& options)
+:
+ surfaceWriter(),
+ writeFormat_(wfShort),
+ fieldMap_()
+{
+ if (options.found("format"))
+ {
+ writeFormat_ = writeFormatNames_.read(options.lookup("format"));
+ }
+
+ List > fieldSet(options.lookup("fields"));
+
+ forAll(fieldSet, i)
+ {
+ fieldMap_.insert(fieldSet[i].first(), fieldSet[i].second());
+ }
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
+
+Foam::nastranSurfaceWriter::~nastranSurfaceWriter()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+void Foam::nastranSurfaceWriter::write
+(
+ const fileName& outputDir,
+ const fileName& surfaceName,
+ const pointField& points,
+ const faceList& faces,
+ const bool verbose
+) const
+{
+ if (!isDir(outputDir))
+ {
+ mkDir(outputDir);
+ }
+
+ OFstream os(outputDir/surfaceName + ".dat");
+ formatOS(os);
+
+ if (verbose)
+ {
+ Info<< "Writing nastran file to " << os.name() << endl;
+ }
+
+ os << "TITLE=OpeNFOAM " << surfaceName.c_str() << " mesh" << nl
+ << "$" << nl
+ << "BEGIN BULK" << nl;
+
+ List > decomposedFaces(faces.size());
+
+ writeGeometry(points, faces, decomposedFaces, os);
+
+ if (!isDir(outputDir))
+ {
+ mkDir(outputDir);
+ }
+
+ os << "ENDDATA" << endl;
+}
+
+
+// ************************************************************************* //
diff --git a/src/sampling/sampledSurface/writers/nastran/nastranSurfaceWriter.H b/src/sampling/sampledSurface/writers/nastran/nastranSurfaceWriter.H
new file mode 100644
index 0000000000..3667173d65
--- /dev/null
+++ b/src/sampling/sampledSurface/writers/nastran/nastranSurfaceWriter.H
@@ -0,0 +1,260 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+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 .
+
+Class
+ Foam::nastranSurfaceWriter
+
+Description
+ A surface writer for the Nastran file format - both surface mesh and fields
+
+SourceFiles
+ nastranSurfaceWriter.C
+ nastranSurfaceWriterTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef nastranSurfaceWriter_H
+#define nastranSurfaceWriter_H
+
+#include "surfaceWriter.H"
+#include "NamedEnum.H"
+#include "OFstream.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+ Class nastranSurfaceWriter Declaration
+\*---------------------------------------------------------------------------*/
+
+class nastranSurfaceWriter
+:
+ public surfaceWriter
+{
+public:
+
+ enum writeFormat
+ {
+ wfShort,
+ wfLong,
+ wfFree
+ };
+
+ static const NamedEnum writeFormatNames_;
+
+
+private:
+
+ // Private data
+
+ //- Write option
+ writeFormat writeFormat_;
+
+ //- Map of OpenFOAM field name vs nastran field name
+ HashTable fieldMap_;
+
+
+ // Private Member Functions
+
+ //- Initialise the output stream format params
+ void formatOS(OFstream& os) const;
+
+ //- Write a co-ordinate
+ void writeCoord
+ (
+ const point& p,
+ label& nPoint,
+ label& continuation,
+ Ostream& os
+ ) const;
+
+ //- Write a face element (CTRIA3 or CQUAD4)
+ void writeFace
+ (
+ const word& faceType,
+ const labelList& facePts,
+ label& nFace,
+ Ostream& os
+ ) const;
+
+ //- Main driver to write the surface mesh geometry
+ void writeGeometry
+ (
+ const pointField& points,
+ const faceList& faces,
+ List >& decomposedFaces,
+ Ostream& os
+ ) const;
+
+ //- Write a face-based value
+ template
+ void writeFaceValue
+ (
+ const word& nasFieldName,
+ const Type& value,
+ const label EID,
+ Ostream& os
+ ) const;
+
+ //- Templated write operation
+ template
+ void writeTemplate
+ (
+ const fileName& outputDir,
+ const fileName& surfaceName,
+ const pointField& points,
+ const faceList& faces,
+ const word& fieldName,
+ const Field& values,
+ const bool isNodeValues,
+ const bool verbose
+ ) const;
+
+
+public:
+
+ //- Runtime type information
+ TypeName("nastran");
+
+
+ // Constructors
+
+ //- Construct null
+ nastranSurfaceWriter();
+
+ //- Construct with some output options
+ nastranSurfaceWriter(const dictionary& options);
+
+
+ //- Destructor
+ virtual ~nastranSurfaceWriter();
+
+
+ // Member Functions
+
+ //- True if the surface format supports geometry in a separate file.
+ // False if geometry and field must be in a single file
+ virtual bool separateGeometry()
+ {
+ return false;
+ }
+
+ //- Write single surface geometry to file.
+ virtual void write
+ (
+ const fileName& outputDir,
+ const fileName& surfaceName,
+ const pointField& points,
+ const faceList& faces,
+ const bool verbose = false
+ ) const;
+
+ //- Write scalarField for a single surface to file.
+ // One value per face or vertex (isNodeValues = true)
+ virtual void write
+ (
+ const fileName& outputDir,
+ const fileName& surfaceName,
+ const pointField& points,
+ const faceList& faces,
+ const word& fieldName,
+ const Field& values,
+ const bool isNodeValues,
+ const bool verbose = false
+ ) const;
+
+ //- Write vectorField for a single surface to file.
+ // One value per face or vertex (isNodeValues = true)
+ virtual void write
+ (
+ const fileName& outputDir,
+ const fileName& surfaceName,
+ const pointField& points,
+ const faceList& faces,
+ const word& fieldName,
+ const Field& values,
+ const bool isNodeValues,
+ const bool verbose = false
+ ) const;
+
+ //- Write sphericalTensorField for a single surface to file.
+ // One value per face or vertex (isNodeValues = true)
+ virtual void write
+ (
+ const fileName& outputDir,
+ const fileName& surfaceName,
+ const pointField& points,
+ const faceList& faces,
+ const word& fieldName,
+ const Field& values,
+ const bool isNodeValues,
+ const bool verbose = false
+ ) const;
+
+ //- Write symmTensorField for a single surface to file.
+ // One value per face or vertex (isNodeValues = true)
+ virtual void write
+ (
+ const fileName& outputDir,
+ const fileName& surfaceName,
+ const pointField& points,
+ const faceList& faces,
+ const word& fieldName,
+ const Field& values,
+ const bool isNodeValues,
+ const bool verbose = false
+ ) const;
+
+ //- Write tensorField for a single surface to file.
+ // One value per face or vertex (isNodeValues = true)
+ virtual void write
+ (
+ const fileName& outputDir,
+ const fileName& surfaceName,
+ const pointField& points,
+ const faceList& faces,
+ const word& fieldName,
+ const Field& values,
+ const bool isNodeValues,
+ const bool verbose = false
+ ) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+ #include "nastranSurfaceWriterTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/sampling/sampledSurface/writers/nastran/nastranSurfaceWriterTemplates.C b/src/sampling/sampledSurface/writers/nastran/nastranSurfaceWriterTemplates.C
new file mode 100644
index 0000000000..a393a5968b
--- /dev/null
+++ b/src/sampling/sampledSurface/writers/nastran/nastranSurfaceWriterTemplates.C
@@ -0,0 +1,201 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+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 "OFstream.H"
+#include "IOmanip.H"
+
+// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
+
+template
+void Foam::nastranSurfaceWriter::writeFaceValue
+(
+ const word& nasFieldName,
+ const Type& value,
+ const label EID,
+ Ostream& os
+) const
+{
+ // Fixed short/long formats:
+ // 1 Nastran distributed load type, e.g. PLOAD4
+ // 2 SID : load set ID
+ // 3 EID : element ID
+ // 4 onwards: load values
+
+ label SID = 0;
+
+ label w = 16;
+ switch (writeFormat_)
+ {
+ case wfShort:
+ {
+ w = 8;
+ }
+ case wfLong:
+ {
+ os << setw(8) << nasFieldName
+ << setw(8) << SID
+ << setw(8) << EID;
+
+ for (direction dirI = 0; dirI < pTraits::nComponents; dirI++)
+ {
+ os << setw(w) << component(value, dirI);
+ }
+
+ break;
+ }
+ case wfFree:
+ {
+ os << nasFieldName << ','
+ << SID << ','
+ << EID;
+
+ for (direction dirI = 0; dirI < pTraits::nComponents; dirI++)
+ {
+ os << ',' << component(value, dirI);
+ }
+
+ break;
+ }
+ default:
+ {
+ }
+ }
+
+ os << nl;
+}
+
+
+template
+void Foam::nastranSurfaceWriter::writeTemplate
+(
+ const fileName& outputDir,
+ const fileName& surfaceName,
+ const pointField& points,
+ const faceList& faces,
+ const word& fieldName,
+ const Field& values,
+ const bool isNodeValues,
+ const bool verbose
+) const
+{
+ if (!fieldMap_.found(fieldName))
+ {
+ WarningIn
+ (
+ "void Foam::nastranSurfaceWriter::writeTemplate"
+ "("
+ "const fileName&, "
+ "const fileName&, "
+ "const pointField&, "
+ "const faceList&, "
+ "const word&, "
+ "const Field&, "
+ "const bool, "
+ "const bool"
+ ") const"
+ )
+ << "No mapping found between field " << fieldName
+ << " and corresponding Nastran field. Available types are:"
+ << fieldMap_
+ << exit(FatalError);
+
+ return;
+ }
+
+ const word& nasFieldName(fieldMap_[fieldName]);
+
+ if (!isDir(outputDir/fieldName))
+ {
+ mkDir(outputDir/fieldName);
+ }
+
+ // const scalar timeValue = Foam::name(this->mesh().time().timeValue());
+ const scalar timeValue = 0.0;
+
+ OFstream os(outputDir/fieldName/surfaceName + ".dat");
+ formatOS(os);
+
+ if (verbose)
+ {
+ Info<< "Writing nastran file to " << os.name() << endl;
+ }
+
+ os << "TITLE=OpenFOAM " << surfaceName.c_str() << " " << fieldName
+ << " data" << nl
+ << "$" << nl
+ << "TIME " << timeValue << nl
+ << "$" << nl
+ << "BEGIN BULK" << nl;
+
+ List > decomposedFaces(faces.size());
+
+ writeGeometry(points, faces, decomposedFaces, os);
+
+
+ os << "$" << nl
+ << "$ Field data" << nl
+ << "$" << nl;
+
+ if (isNodeValues)
+ {
+ label n = 0;
+
+ forAll(decomposedFaces, i)
+ {
+ const DynamicList& dFaces = decomposedFaces[i];
+ forAll(dFaces, faceI)
+ {
+ Type v = pTraits::zero;
+ const face& f = dFaces[faceI];
+
+ forAll(f, fptI)
+ {
+ v += values[f[fptI]];
+ }
+
+ writeFaceValue(nasFieldName, v, ++n, os);
+ }
+ }
+ }
+ else
+ {
+ label n = 0;
+
+ forAll(decomposedFaces, i)
+ {
+ const DynamicList& dFaces = decomposedFaces[i];
+
+ forAll(dFaces, faceI)
+ {
+ writeFaceValue(nasFieldName, values[faceI], ++n, os);
+ }
+ }
+ }
+
+ os << "ENDDATA" << endl;
+}
+
+
+// ************************************************************************* //