ENH: make Nastran PLOAD2,PLOAD4 field mappings optional

- PLOAD2 is a reasonable default and PLOAD4 output
  (currently misused for vectors/tensors) is the exception.

- simplify the specification by using optional PLOAD4, PLOAD2 wordRes
  lists to act as allow/deny selectors. In the regular case won't need
  to specify anything or perhaps only the PLOAD4 list.

ENH: atomic creation of Nastran files

FIX: inconsistent Nastran surface output format

- use FREE format by default. Previously had an odd mix of SHORT
  format when created without options and LONG format (as default)
  when created with format options.
This commit is contained in:
Mark Olesen 2024-06-26 08:44:20 +02:00
parent d8d3e34d5c
commit dce009cef1
4 changed files with 84 additions and 82 deletions

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2022 OpenCFD Ltd.
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -250,12 +250,12 @@ Foam::fileName Foam::coordSetWriters::nastranWriter::writeTemplate
Info<< "Writing nastran geometry to " << outputFile << endl;
}
if (!isDir(outputFile.path()))
if (!Foam::isDir(outputFile.path()))
{
mkDir(outputFile.path());
Foam::mkDir(outputFile.path());
}
OFstream os(outputFile);
OFstream os(IOstreamOption::ATOMIC, outputFile);
fileFormats::NASCore::setPrecision(os, writeFormat_);
os << "TITLE=OpenFOAM " << outputFile.stem()
@ -293,12 +293,12 @@ Foam::fileName Foam::coordSetWriters::nastranWriter::writeTemplate
Info<< "Writing nastran geometry to " << outputFile << endl;
}
if (!isDir(outputFile.path()))
if (!Foam::isDir(outputFile.path()))
{
mkDir(outputFile.path());
Foam::mkDir(outputFile.path());
}
OFstream os(outputFile);
OFstream os(IOstreamOption::ATOMIC, outputFile);
fileFormats::NASCore::setPrecision(os, writeFormat_);
os << "TITLE=OpenFOAM " << outputFile.stem()

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012-2016 OpenFOAM Foundation
Copyright (C) 2015-2022 OpenCFD Ltd.
Copyright (C) 2015-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -307,16 +307,10 @@ void Foam::surfaceWriters::nastranWriter::writeGeometry
Foam::surfaceWriters::nastranWriter::nastranWriter()
:
surfaceWriter(),
writeFormat_(fieldFormat::SHORT),
fieldMap_(),
writeFormat_(fieldFormat::FREE),
commonGeometry_(false),
separator_()
{
// if (writeFormat_ == fieldFormat::FREE)
// {
// separator_ = ",";
// }
}
separator_(",") // FREE format
{}
Foam::surfaceWriters::nastranWriter::nastranWriter
@ -331,29 +325,40 @@ Foam::surfaceWriters::nastranWriter::nastranWriter
(
"format",
options,
fieldFormat::LONG
fieldFormat::FREE
)
),
fieldMap_(),
commonGeometry_(options.getOrDefault("commonGeometry", false)),
separator_()
commonGeometry_(options.getOrDefault("commonGeometry", false))
{
if (writeFormat_ == fieldFormat::FREE)
{
separator_ = ",";
}
// Explicit PLOAD2, PLOAD4 field specification
options.readIfPresent("PLOAD2", pload2_);
options.readIfPresent("PLOAD4", pload4_);
// Compatibility:
// Optional pairs of (field name => load format)
// Could make conditional on (pload2_.empty() && pload4_.empty())
List<Pair<word>> fieldPairs;
options.readEntry("fields", fieldPairs);
options.readIfPresent("fields", fieldPairs);
for (const Pair<word>& item : fieldPairs)
{
// (field name => load format)
fieldMap_.insert
(
item.first(),
fileFormats::NASCore::loadFormatNames[item.second()]
);
const loadFormat format =
fileFormats::NASCore::loadFormatNames[item.second()];
if (format == loadFormat::PLOAD2)
{
pload2_.push_back(item.first());
}
else if (format == loadFormat::PLOAD4)
{
pload4_.push_back(item.first());
}
}
}
@ -414,12 +419,12 @@ Foam::fileName Foam::surfaceWriters::nastranWriter::write()
if (UPstream::master() || !parallel_)
{
if (!isDir(outputFile.path()))
if (!Foam::isDir(outputFile.path()))
{
mkDir(outputFile.path());
Foam::mkDir(outputFile.path());
}
OFstream os(outputFile);
OFstream os(IOstreamOption::ATOMIC, outputFile);
fileFormats::NASCore::setPrecision(os, writeFormat_);
os << "TITLE=OpenFOAM " << outputPath_.name() << " geometry" << nl

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012-2016 OpenFOAM Foundation
Copyright (C) 2015-2022 OpenCFD Ltd.
Copyright (C) 2015-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -33,13 +33,15 @@ Description
The formatOptions for nastran:
\table
Property | Description | Reqd | Default
fields | Field pairs for PLOAD2/PLOAD4 | yes |
format | Nastran format (short/long/free) | no | long
format | Nastran format (short/long/free) | no | free
scale | Output geometry scaling | no | 1
transform | Output coordinate transform | no |
fieldLevel | Subtract field level before scaling | no | empty dict
fieldScale | Output field scaling | no | empty dict
commonGeometry | use separate geometry files | no | false
PLOAD2 | Field selection (words/regex) for PLOAD2 | no |
PLOAD4 | Field selection (words/regex) for PLOAD4 | no |
fields | Compat: Field pairs for PLOAD2/PLOAD4 | no |
\endtable
For example,
@ -48,13 +50,6 @@ Description
{
nastran
{
// OpenFOAM field name to NASTRAN load types
fields
(
(pMean PLOAD2)
(p PLOAD4)
);
format free; // format type
scale 1000; // [m] -> [mm]
@ -62,10 +57,27 @@ Description
{
"p.*" 0.01; // [Pa] -> [mbar]
}
// Specific NASTRAN load types
PLOAD2 ( pMean );
PLOAD4 ( "p.*" );
// old style specification
fields
(
(pMean PLOAD2)
(p PLOAD4)
);
}
}
\endverbatim
Unless otherwise specified, all fields will be treated as PLOAD2
output. Can optionally specify PLOAD4 output using a combination
of \c PLOAD4 (accept) and \c PLOAD2 (deny) entries. The older \c fields
specification is also accepted and will be transcribed to
corresponding PLOAD4, PLOAD2 entries.
\section Output file locations
The \c rootdir normally corresponds to something like
@ -93,7 +105,6 @@ Description
Note
Output variable scaling does not apply to integer types such as Ids.
Field pairs default to PLOAD2 for scalars and PLOAD4 for vectors etc.
SourceFiles
nastranSurfaceWriter.C
@ -106,7 +117,7 @@ SourceFiles
#include "surfaceWriter.H"
#include "NASCore.H"
#include "HashTable.H"
#include "wordRes.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -139,15 +150,18 @@ private:
//- Field format (width and separator)
fieldFormat writeFormat_;
//- Mapping from field name to data format enumeration
HashTable<loadFormat> fieldMap_;
//- Use common geometry file
bool commonGeometry_;
//- Separator (used for free format)
word separator_;
//- Explicit selection for PLOAD2 output (deselects for PLOAD4)
wordRes pload2_;
//- Explicit selection for PLOAD4 output
wordRes pload4_;
// Private Member Functions
@ -221,10 +235,10 @@ public:
// Constructors
//- Default construct. Default SHORT format
//- Default construct. Default FREE format
nastranWriter();
//- Construct with some output options. Default LONG format
//- Construct with some output options. Default FREE format
explicit nastranWriter(const dictionary& options);
//- Construct from components

View File

@ -103,13 +103,13 @@ Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeFaceValue
{
case loadFormat::PLOAD2 :
{
if (pTraits<Type>::nComponents == 1)
if (pTraits<Type>::nComponents > 1)
{
writeValue(os, value);
writeValue(os, Foam::mag(value));
}
else
{
writeValue(os, mag(value));
writeValue(os, value);
}
os << separator_;
@ -121,6 +121,9 @@ Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeFaceValue
{
writeValue(os, elemId);
// NOTE: these should actually be vertex values,
// but misused here to provide vector quantities!
for (direction d = 0; d < pTraits<Type>::nComponents; ++d)
{
os << separator_;
@ -156,43 +159,23 @@ Foam::fileName Foam::surfaceWriters::nastranWriter::writeTemplate
checkOpen();
const loadFormat format
(
fieldMap_.lookup
(
fieldName,
// Default format
(
pTraits<Type>::nComponents == 1
? loadFormat::PLOAD2
: loadFormat::PLOAD4
)
)
);
// Default is PLOAD2
loadFormat format = loadFormat::PLOAD2;
if
(
!std::is_integral<Type>::value // Handle 'Ids' etc silently
&& !fieldMap_.empty()
&& !fieldMap_.found(fieldName)
&& !pload4_.empty()
)
{
WarningInFunction
<< "No mapping found between field " << fieldName
<< " and corresponding Nastran field. Available types:"
<< fieldMap_ << nl;
}
const wordRes::filter matcher(pload4_, pload2_);
// Emit any common warnings
if (format == loadFormat::PLOAD2 && pTraits<Type>::nComponents != 1)
{
WarningInFunction
<< fileFormats::NASCore::loadFormatNames[format]
<< " cannot be used for higher rank values"
<< " - reverting to mag()" << endl;
if (matcher(fieldName))
{
format = loadFormat::PLOAD4;
}
}
// Common geometry
// Field: rootdir/<TIME>/<field>_surfaceName.bdf
@ -239,9 +222,9 @@ Foam::fileName Foam::surfaceWriters::nastranWriter::writeTemplate
{
const auto& values = tfield();
if (!isDir(outputFile.path()))
if (!Foam::isDir(outputFile.path()))
{
mkDir(outputFile.path());
Foam::mkDir(outputFile.path());
}
const scalar timeValue(0);
@ -251,7 +234,7 @@ Foam::fileName Foam::surfaceWriters::nastranWriter::writeTemplate
DynamicList<face> decompFaces;
OFstream os(outputFile);
OFstream os(IOstreamOption::ATOMIC, outputFile);
fileFormats::NASCore::setPrecision(os, writeFormat_);
os << "TITLE=OpenFOAM " << outputFile.name()