/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2024 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 "NASCore.H"
#include "IOmanip.H"
#include "Ostream.H"
#include "parsing.H"
#include "defineDebugSwitch.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace fileFormats
{
defineDebugSwitchWithName(NASCore, "nastran.debug", 0);
registerDebugSwitchWithName
(
NASCore, Nastran, "nastran.debug"
);
}
}
const Foam::Enum
<
Foam::fileFormats::NASCore::fieldFormat
>
Foam::fileFormats::NASCore::fieldFormatNames
({
{ fieldFormat::SHORT, "short" },
{ fieldFormat::LONG, "long" },
{ fieldFormat::FREE, "free" },
});
const Foam::Enum
<
Foam::fileFormats::NASCore::loadFormat
>
Foam::fileFormats::NASCore::loadFormatNames
({
{ loadFormat::PLOAD2, "PLOAD2" },
{ loadFormat::PLOAD4, "PLOAD4" },
});
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
template
static inline void putValue(Ostream& os, const Type& value, const int width)
{
if (width) os << setw(width);
os << value;
}
} // End namespace Foam
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::scalar Foam::fileFormats::NASCore::readNasScalar(const std::string& str)
{
const auto signPos = str.find_last_of("+-");
if
(
signPos == std::string::npos
|| signPos == 0
|| str[signPos-1] == 'E' || str[signPos-1] == 'e'
|| isspace(str[signPos-1])
)
{
// A normal number format
return readScalar(str);
}
// Nastran compact number format.
// Eg, "1234-2" instead of "1234E-2"
scalar value = 0;
int exponent = 0; // Any integer
if
(
readScalar(str.substr(0, signPos), value) // Mantissa
&& readInt(str.substr(signPos), exponent) // Exponent (with sign)
)
{
// Note: this does not catch underflow/overflow
// (especially when scalar is a float)
value *= ::pow(10, exponent);
}
else
{
FatalIOErrorInFunction("unknown")
<< parsing::errorNames[parsing::errorType::GENERAL] << str
<< exit(FatalIOError);
value = 0;
}
return value;
}
std::string Foam::fileFormats::NASCore::nextNasField
(
const std::string& str,
std::string::size_type& pos,
const std::string::size_type width,
const bool free_format
)
{
const auto beg = pos;
const auto end = str.find(',', pos);
if (end == std::string::npos)
{
if (free_format)
{
// Nothing left
pos = str.size();
return str.substr(beg);
}
// Fixed format - continue after field width
pos = beg + width;
return str.substr(beg, width);
}
else
{
// Free format - continue after comma
pos = end + 1;
return str.substr(beg, (end - beg));
}
}
void Foam::fileFormats::NASCore::setPrecision
(
Ostream& os,
const fieldFormat format
)
{
os.setf(std::ios_base::scientific);
// Capitalise the E marker
os.setf(std::ios_base::uppercase);
const label offset = 7;
label prec = 16 - offset;
switch (format)
{
case fieldFormat::SHORT :
{
prec = 8 - offset;
break;
}
case fieldFormat::LONG :
case fieldFormat::FREE :
{
prec = 16 - offset;
break;
}
}
os.precision(prec);
}
Foam::Ostream& Foam::fileFormats::NASCore::writeKeyword
(
Ostream& os,
const word& keyword,
const fieldFormat format
)
{
os.setf(std::ios_base::left);
switch (format)
{
case fieldFormat::SHORT :
{
os << setw(8) << keyword;
break;
}
case fieldFormat::LONG :
{
os << setw(8) << word(keyword + '*');
break;
}
case fieldFormat::FREE :
{
os << keyword;
break;
}
}
os.unsetf(std::ios_base::left);
return os;
}
void Foam::fileFormats::NASCore::writeCoord
(
Ostream& os,
const point& p,
const label pointId, // zero-based
const fieldFormat format
)
{
// Field width (SHORT, LONG formats)
const int width =
(
format == fieldFormat::SHORT ? 8
: format == fieldFormat::LONG ? 16
: 0
);
// Separator char (FREE format)
const char sep = (format == fieldFormat::FREE ? ',' : '\0');
// Fixed short/long formats:
// 1 GRID
// 2 ID : point ID - requires starting index of 1
// 3 CP : coordinate system ID (blank)
// 4 X1 : point x coordinate
// 5 X2 : point y coordinate
// 6 X3 : point z coordinate
// 7 CD : coordinate system for displacements (blank)
// 8 PS : single point constraints (blank)
// 9 SEID : super-element ID
writeKeyword(os, "GRID", format);
if (sep) os << sep;
os.setf(std::ios_base::right);
// Point ID (from 0-based to 1-based)
putValue(os, (pointId+1), width);
if (sep) os << sep;
// Coordinate system ID (blank)
putValue(os, "", width);
if (sep) os << sep;
putValue(os, p.x(), width);
if (sep) os << sep;
putValue(os, p.y(), width);
if (sep) os << sep;
if (format == fieldFormat::LONG)
{
// Continuation
os.unsetf(std::ios_base::right);
os << nl;
writeKeyword(os, "", format);
os.setf(std::ios_base::right);
}
putValue(os, p.z(), width);
os << nl;
os.unsetf(std::ios_base::right);
}
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();
}
// ************************************************************************* //