From b476dd92e6e14f40a6e5ff507b1dece09b8c36f0 Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Thu, 27 Feb 2020 13:16:28 +0100 Subject: [PATCH] ENH: improvements for nastran surface writer (#1571) - avoid face copying. Maintain separate offsets/list for non tri/quad face decomposition, which eliminates copying for tri/quad types that represent the bulk of geometries - report inappropriate use of PLOAD2 for higher-ranks only once per field instead of per face. For this case, write its magnitude instead of 0. - perform field output scaling prior to calling the write face function. This will make it easier to handle different per-field scaling in the future (#1612) BUG: nastran quad written as "CTRIA3" instead of "CQUAD4" --- src/fileFormats/nastran/NASCore.C | 36 ++++- src/fileFormats/nastran/NASCore.H | 26 +++- .../surfaceFormats/nas/NASsurfaceFormat.C | 2 +- .../writers/nastran/nastranSurfaceWriter.C | 60 +++++---- .../writers/nastran/nastranSurfaceWriter.H | 8 +- .../nastran/nastranSurfaceWriterImpl.C | 127 +++++++++++++----- 6 files changed, 193 insertions(+), 66 deletions(-) diff --git a/src/fileFormats/nastran/NASCore.C b/src/fileFormats/nastran/NASCore.C index 184eb65565..ab4de5915d 100644 --- a/src/fileFormats/nastran/NASCore.C +++ b/src/fileFormats/nastran/NASCore.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2017-2019 OpenCFD Ltd. + Copyright (C) 2017-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -197,4 +197,38 @@ Foam::Ostream& Foam::fileFormats::NASCore::writeKeyword } +Foam::label Foam::fileFormats::NASCore::faceDecomposition +( + const UList& points, + const UList& faces, + labelList& decompOffsets, + DynamicList& decompFaces +) +{ + // On-demand face decomposition (triangulation) + + decompOffsets.resize(faces.size()+1); + decompFaces.clear(); + + auto offsetIter = decompOffsets.begin(); + *offsetIter = 0; // The first offset is always zero + + for (const face& f : faces) + { + const label n = f.size(); + + if (n != 3 && n != 4) + { + // Decompose non-tri/quad into tris + f.triangles(points, decompFaces); + } + + // The end offset, which is the next begin offset + *(++offsetIter) = decompFaces.size(); + } + + return decompFaces.size(); +} + + // ************************************************************************* // diff --git a/src/fileFormats/nastran/NASCore.H b/src/fileFormats/nastran/NASCore.H index 24a5afcede..d059a754b5 100644 --- a/src/fileFormats/nastran/NASCore.H +++ b/src/fileFormats/nastran/NASCore.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2017-2019 OpenCFD Ltd. + Copyright (C) 2017-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -40,15 +40,15 @@ SourceFiles #include "scalar.H" #include "string.H" #include "Enum.H" +#include "face.H" +#include "point.H" +#include "DynamicList.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { -// Forward Declarations -class Ostream; - namespace fileFormats { @@ -84,7 +84,7 @@ public: // Constructors - //- Construct null + //- Default construct NASCore() = default; @@ -120,6 +120,22 @@ public: const word& keyword, const fieldFormat format ); + + //- Calculate face decomposition for non tri/quad faces + // + // \param points the surface points + // \param faces the surface faces + // \param decompOffsets begin/end offsets (size+1) into decompFaces + // \param decompFaces List of non-tri/quad decomposed into triangles + // + // \return number of decomposed faces + static label faceDecomposition + ( + const UList& points, + const UList& faces, + labelList& decompOffsets, + DynamicList& decompFaces + ); }; diff --git a/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C b/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C index da3e45694a..5e0f2b1666 100644 --- a/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C +++ b/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C @@ -55,7 +55,7 @@ inline Foam::label Foam::fileFormats::NASsurfaceFormat::writeShell } else if (n == 4) { - os << "CTRIA3" << ',' + os << "CQUAD4" << ',' << ++elementId << ',' << (groupId + 1) << ',' << (f[0] + 1) << ',' diff --git a/src/surfMesh/writers/nastran/nastranSurfaceWriter.C b/src/surfMesh/writers/nastran/nastranSurfaceWriter.C index 69d4ae84d4..9592e5bba9 100644 --- a/src/surfMesh/writers/nastran/nastranSurfaceWriter.C +++ b/src/surfMesh/writers/nastran/nastranSurfaceWriter.C @@ -204,7 +204,8 @@ void Foam::surfaceWriters::nastranWriter::writeGeometry ( Ostream& os, const meshedSurf& surf, - List& decomposedFaces + labelList& decompOffsets, + DynamicList& decompFaces ) const { const pointField& points = surf.points(); @@ -213,9 +214,9 @@ void Foam::surfaceWriters::nastranWriter::writeGeometry // Write points - os << "$" << nl + os << '$' << nl << "$ Points" << nl - << "$" << nl; + << '$' << nl; forAll(points, pointi) { @@ -223,18 +224,19 @@ void Foam::surfaceWriters::nastranWriter::writeGeometry } // Write faces, with on-the-fly decomposition (triangulation) - decomposedFaces.clear(); - decomposedFaces.resize(faces.size()); + decompOffsets.resize(faces.size()+1); + decompFaces.clear(); - os << "$" << nl + decompOffsets[0] = 0; // The first offset is always zero + + os << '$' << nl << "$ Faces" << nl - << "$" << nl; + << '$' << nl; - label elemId = 0; // The element-id + label elemId = 0; // The element-id forAll(faces, facei) { const face& f = faces[facei]; - faceList& decomp = decomposedFaces[facei]; // 1-offset for PID const label propId = 1 + (facei < zones.size() ? zones[facei] : 0); @@ -242,28 +244,36 @@ void Foam::surfaceWriters::nastranWriter::writeGeometry if (f.size() == 3) { writeFace(os, "CTRIA3", f, ++elemId, propId); - decomp.resize(1); - decomp[0] = f; } else if (f.size() == 4) { writeFace(os, "CQUAD4", f, ++elemId, propId); - decomp.resize(1); - decomp[0] = f; } else { - // Decompose poly face into tris - decomp.resize(f.nTriangles()); + // Decompose into tris + f.triangles(points, decompFaces); - label nTri = 0; - f.triangles(points, nTri, decomp); - - for (const face& f2 : decomp) + for + ( + label decompi = decompOffsets[facei]; + decompi < decompFaces.size(); + ++decompi + ) { - writeFace(os, "CTRIA3", f2, ++elemId, propId); + writeFace + ( + os, + "CTRIA3", + decompFaces[decompi], + ++elemId, + propId + ); } } + + // The end offset, which is the next begin offset + decompOffsets[facei+1] = decompFaces.size(); } } @@ -323,7 +333,7 @@ Foam::surfaceWriters::nastranWriter::nastranWriter() surfaceWriter(), writeFormat_(fieldFormat::SHORT), fieldMap_(), - scale_(1.0), + scale_(1), separator_() {} @@ -432,11 +442,13 @@ Foam::fileName Foam::surfaceWriters::nastranWriter::write() os << "TITLE=OpenFOAM " << outputPath_.name() << " mesh" << nl - << "$" << nl + << '$' << nl << "BEGIN BULK" << nl; - List decomposedFaces; - writeGeometry(os, surf, decomposedFaces); + labelList decompOffsets; + DynamicList decompFaces; + + writeGeometry(os, surf, decompOffsets, decompFaces); writeFooter(os, surf) << "ENDDATA" << nl; diff --git a/src/surfMesh/writers/nastran/nastranSurfaceWriter.H b/src/surfMesh/writers/nastran/nastranSurfaceWriter.H index b27831174f..e2ddba4ac7 100644 --- a/src/surfMesh/writers/nastran/nastranSurfaceWriter.H +++ b/src/surfMesh/writers/nastran/nastranSurfaceWriter.H @@ -155,12 +155,16 @@ private: const label propId //!< 1-based Property Id ) const; - //- Main driver to write the surface mesh geometry + //- Write the surface mesh geometry, tracking face decomposition + // + // \param decompOffsets begin/end offsets (size+1) into decompFaces + // \param decompFaces Non tri/quad decomposed into triangles void writeGeometry ( Ostream& os, const meshedSurf& surf, - List& decomposedFaces + labelList& decompOffsets, + DynamicList& decompFaces ) const; //- Write the formatted keyword to the output stream diff --git a/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C b/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C index 3b29d8a2c2..737240262c 100644 --- a/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C +++ b/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C @@ -89,8 +89,6 @@ Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeFaceValue const label setId = 1; - Type scaledValue = scale_*value; - // Write keyword writeKeyword(os, fileFormats::NASCore::loadFormatNames[format]) << separator_; @@ -106,19 +104,14 @@ Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeFaceValue { if (pTraits::nComponents == 1) { - writeValue(os, scaledValue) << separator_; + writeValue(os, value); } else { - WarningInFunction - << fileFormats::NASCore::loadFormatNames[format] - << " requires scalar values" - << " - it cannot be used for higher rank values" - << endl; - - writeValue(os, scalar(0)) << separator_; + writeValue(os, mag(value)); } + os << separator_; writeValue(os, elemId); break; } @@ -130,7 +123,7 @@ Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeFaceValue for (direction d = 0; d < pTraits::nComponents; ++d) { os << separator_; - writeValue(os, component(scaledValue, d)); + writeValue(os, component(value, d)); } break; } @@ -164,7 +157,7 @@ Foam::fileName Foam::surfaceWriters::nastranWriter::writeTemplate return fileName::null; } - const loadFormat& format(fieldMap_[fieldName]); + const loadFormat format(fieldMap_[fieldName]); // Field: rootdir/