Compare commits

...

18 Commits

Author SHA1 Message Date
7207e9e3a9 TUT: add a multi-region finite-area example tutorial 2025-10-12 17:00:17 +02:00
6d2deda470 ENH: revise some regionFaModel parameter naming (#3419)
- the old naming grew organically and was previously restricted
  by avoiding name collisions with volume fields, which resulted
  in some minor consistencies

Common solid shell naming:

  | Keyword  | Default     | Description  | Key(old) | Old Naming     |
  | -------- | ----------- | ------------ | -------- | -------------- |
  | h        | hs (suffix) | thickness    | h        | "h_" + region  |
  | T        | Ts (suffix) | temperature  | -        | "Ts_" + region |

Vibration shells:

  | Keyword  | Default     | Description  | Key(old) | Old Naming     |
  | -------- | ----------- | ------------ | -------- | -------------- |
  |  as      | as (suffix) | acceleration | -        | "as_" + region |
  |  ps      | ps (suffix) | pres on shell| -        | "ps_" + region |
  |  ws      | ws (suffix) | displacement | -        | "ws_" + region |
  |  qs      | qs (suffix  | source field | -        | "qs_" + region |

Other:

  | Keyword  | Default     | Description  | Key(old) |
  | -------- | ----------- | ------------ | -------- |
  | Tprimary | T   | temperature (volume) | T        |

Joule heating: (possibly breaking naming changes)

  | Field    | Name                     | Name(old)                |
  | -------- | ------------------------ | ------------------------ |
  |  V       | \<scope\>:V (suffix)     | \<scope\>:V + region     |
  |  sigma   | \<scope\>:sigma (suffix) | \<scope\>:sigma + region |
2025-10-12 15:54:05 +02:00
c172b588c0 ENH: multi-region finiteArea support [parallel] (#3419)
- redistributePar (partly working)
2025-10-12 15:54:05 +02:00
c075af4f7b ENH: redistributePar cleanup
- remove old dead code (without file-handlers)
- update coding style
2025-10-12 15:54:05 +02:00
a1e5dcee43 ENH: redistributePar cleanup
- update and extend loadOrCreateMesh coding
- support bitSet return values
- accept checks with name/instance/local in IOobject parameter order
2025-10-12 15:54:05 +02:00
f2922f1ae9 ENH: multi-region finiteArea support [parallel] (#3419)
- decomposePar, reconstructPar, reconstructParMesh
2025-10-12 15:54:05 +02:00
1ae48880d2 ENH: multi-region finiteArea support [post-processing] (#3419)
- foamToEnsight, foamToVTK
2025-10-12 15:54:05 +02:00
9fc52d42eb ENH: multi-region finiteArea support [pre-processing] (#3419)
- checkFaMesh, makeFaMesh, setFields
2025-10-12 15:54:05 +02:00
c669f7b736 ENH: provide general static singleton for the faMeshesRegistry objects 2025-10-12 15:54:05 +02:00
27878797e2 ENH: add support for name suffixing in faOption and regionFaModel (#3419)
- in earlier versions, when area fields and volume fields were stored
  together, an automatic suffix of '_' + regionName was appended to
  many of the finite-area fields. This was needed to prevent name
  clashes between 'T' (area) and 'T' (volume) field names.

  This is no longer necessary, but some existing setups may rely on
  the old naming convention. To make this more flexible while also
  minimizing the number of changes, introduced a "suffixing"
  keyword for faOption and regionFaModel.

  Can specify suffixing as "default" to recover the (_ + region)
  naming scheme (can also currently also use true/false/none here).
  Or specify a suffix (eg, _shell) unrelated to any region name.

ENH: improve the code style and alignment in jouleHeatingSource

- make {fa,fv} versions more consistent, for better maintenance
2025-10-12 15:53:29 +02:00
e9fcd75ec4 ENH: add default "constant" name for fileOperations::findTimes()
- makes fileHandler calling resemble Time more closely

ENH: provide natural_sort less/greater functions

- more succinct than (compare < 0) or (compare > 0).
  The corresponding wrappers for UList renamed as list_less, etc
  but they were only used in unit tests

ENH: handle (-allRegions | -all-regions, ..) directly when retrieving args

- makes handling independent of aliasing order

STYLE: include <string_view> when including <string>

- the standard does not guarantee which headers (if any) actually
  include string_view
2025-10-12 15:53:26 +02:00
ac34d9fd29 ENH: allow delayed construction of regionFaModel in volume bcs (#3419)
Ideally wish to delay construction of the finite-area mesh until
  updateCoeffs(), when it is actually needed.

  This helps avoid difficult to trace errors and avoids inadvertent
  parallel communication during construction from a dictionary.

  However, lazy evaluation fails at the later stage while attempting
  to load the corresponding initial fields, since the timeIndex has
  already advanced.

  Use the newly introduced regionModels::allowFaModels() switch
  to locally enable or disable lazy evaluation as needed.

  This allows selective disabling (eg, in post-processing utilities)
  where loading the volume field should not activate the associated
  regionFaModel and loading a finite-area mesh too (which may not
  exist or be defined at that point).
2025-10-11 19:51:51 +02:00
14bece937b ENH: added clean up function remove0DirFields (RunFunctions)
- less typing than before and avoids relying on bash-specific behaviour
  (fixes #3448)

ENH: add -region support for cleanFaMesh and cleanPolyMesh

CONFIG: add bash completion help for -area-region

ENH: general improvements for regionProperties

- robustness and failsafe for foamListRegions, regionProperties
- additional global model switches for regionModels
2025-10-10 18:18:31 +02:00
2396828a60 ENH: increase some string_view coverage
- remove some stdFoam::span<char> handling, which was just a stop-gap
  measure
2025-10-10 09:05:23 +02:00
9223d238bd STYLE: surface/volume writing function objects
- further hide implementation (cxx ending)

STYLE: better distinction between code/templates for fileFormats/conversion

- for ensight and vtk, a large part of the code is header only.
  Make this easier to identify
2025-10-10 08:54:03 +02:00
4b92bb6533 ENH: update globalIndex::mpiGather to use MPI intrinsic/user types
- add provisional support for selecting MPI_Gatherv
  when merging fields in the surface writers.
  Uses the 'gatherv' keyword [experimental]

BUG: gatherv/scatterv wrappers used the incorrect data type

- incorrectly checked against UPstream_basic_dataType trait instead of
  UPstream_dataType, which resulted in a count mismatch for
  user-defined types (eg, vector, tensor,...).

  This was not visibly active bug, since previous internal uses of
  gatherv were restricted to primitive types.

COMP: make UPstream dataType traits size(...) constexpr

- allows static asserts and/or compile-time selection
  of code based on size(1)
2025-10-10 08:51:20 +02:00
55c81bce1b ENH: GAMGAgglomeration: increase repeatability. Fixes #3450 2025-10-09 11:55:06 +01:00
1cb0b7b6c9 Merge branch 'extend-field-distributors' into 'develop'
cleanup of decompose/reconstruct/redistribute, adding area-name support

See merge request Development/openfoam!761
2025-10-09 10:29:56 +00:00
249 changed files with 5824 additions and 2453 deletions

View File

@ -200,7 +200,7 @@ void printTypeName()
template<class Type, bool UseTypeName = true>
void printPstreamTraits(const std::string_view name = std::string_view())
void printPstreamTraits(std::string_view name = std::string_view())
{
Info<< "========" << nl;
Info<< "type: ";
@ -299,6 +299,9 @@ void printPstreamTraits(const std::string_view name = std::string_view())
// Use element or component type (or byte-wise) for data type
using base = typename UPstream_dataType<Type>::base;
// The sizing factor is constexpr
constexpr std::streamsize count = UPstream_dataType<Type>::size(1);
Info<< " : ";
if constexpr (UseTypeName)
{
@ -311,8 +314,7 @@ void printPstreamTraits(const std::string_view name = std::string_view())
Info<< " cmpt-type=";
printDataTypeId(UPstream_dataType<Type>::datatype_id);
Info<< " count=" << UPstream_dataType<Type>::size(1);
Info<< nl;
Info<< " count=" << count << nl;
}
}
@ -362,6 +364,24 @@ void print_data_opType(BinaryOp bop, std::string_view name)
}
template<class Type>
int check_simple(std::string_view name = std::string_view())
{
// The sizing factor is constexpr
constexpr std::streamsize count = UPstream_dataType<Type>::size(1);
static_assert
(
(count == 1),
"Code does not (yet) work with aggregate types"
);
Info<< "check_simple: " << name << ": " << count << nl;
return count;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
@ -389,6 +409,8 @@ int main()
printPstreamTraits<const float>();
printPstreamTraits<floatVector>();
check_simple<floatVector>("vector<float>");
printPstreamTraits<scalar>();
printPstreamTraits<double>();
printPstreamTraits<doubleVector>();

View File

@ -49,8 +49,7 @@ int main(int argc, char *argv[])
Info<< "mesh 0: " << mesh.sortedNames() << nl;
faMeshesRegistry& reg =
const_cast<faMeshesRegistry&>(faMeshesRegistry::New(mesh));
auto& reg = const_cast<faMeshesRegistry&>(faMeshesRegistry::New(mesh));
// faMeshesRegistry faReg = faMeshesRegistry(mesh);

View File

@ -1,3 +1,3 @@
foamToEnsight-check.C
foamToEnsight-check.cxx
EXE = $(FOAM_USER_APPBIN)/foamToEnsight-check

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022-2023 OpenCFD Ltd.
Copyright (C) 2022-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -203,6 +203,7 @@ int main(int argc, char *argv[])
argList::addVerboseOption();
#include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
argList::addBoolOption
(
@ -251,6 +252,14 @@ int main(int argc, char *argv[])
// Handle -allRegions, -regions, -region
#include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
// ------------------------------------------------------------------------
#include "createNamedMeshes.H"
@ -259,8 +268,8 @@ int main(int argc, char *argv[])
/// #include "createMeshAccounting.H"
PtrList<ensightMesh> ensightMeshes(regionNames.size());
PtrList<faMesh> meshesFa(regionNames.size());
PtrList<ensightFaMesh> ensightMeshesFa(regionNames.size());
List<PtrList<faMesh>> meshesFa(regionNames.size());
List<PtrList<ensightFaMesh>> ensightMeshesFa(regionNames.size());
forAll(regionNames, regioni)
{
@ -273,21 +282,32 @@ int main(int argc, char *argv[])
);
ensightMeshes[regioni].verbose(optVerbose);
if (doFiniteArea)
if (!doFiniteArea)
{
autoPtr<faMesh> faMeshPtr(faMesh::TryNew(mesh));
continue;
}
meshesFa[regioni].resize_null(areaRegionNames.size());
ensightMeshesFa[regioni].resize_null(areaRegionNames.size());
autoPtr<faMesh> faMeshPtr(faMesh::TryNew(mesh));
forAll(areaRegionNames, areai)
{
const word& areaName = areaRegionNames[areai];
autoPtr<faMesh> faMeshPtr(faMesh::TryNew(areaName, mesh));
if (faMeshPtr)
{
meshesFa.set(regioni, std::move(faMeshPtr));
meshesFa[regioni].set(areai, std::move(faMeshPtr));
ensightMeshesFa.set
ensightMeshesFa[regioni].set
(
regioni,
new ensightFaMesh(meshesFa[regioni])
areai,
new ensightFaMesh(meshesFa[regioni][areai])
);
ensightMeshesFa[regioni].verbose(optVerbose);
ensightMeshesFa[regioni][areai].verbose(optVerbose);
}
}
}
@ -295,7 +315,7 @@ int main(int argc, char *argv[])
// ------------------------------------------------------------------------
if (Pstream::master())
if (UPstream::master())
{
Info<< "Checking " << timeDirs.size() << " time steps" << nl;
}
@ -317,17 +337,20 @@ int main(int argc, char *argv[])
auto& ensMesh = ensightMeshes[regioni];
// Finite-area (can be missing)
auto* ensFaMeshPtr = ensightMeshesFa.get(regioni);
auto& ensFaMeshes = ensightMeshesFa[regioni];
if (moving)
{
ensMesh.expire();
ensMesh.correct();
if (ensFaMeshPtr)
forAll(areaRegionNames, areai)
{
ensFaMeshPtr->expire();
ensFaMeshPtr->correct();
if (auto* ensFaMeshPtr = ensFaMeshes.get(areai))
{
ensFaMeshPtr->expire();
ensFaMeshPtr->correct();
}
}
}
@ -340,9 +363,15 @@ int main(int argc, char *argv[])
printInfo(ensMesh, optVerbose);
if (ensFaMeshPtr)
// finite-area
forAll(areaRegionNames, areai)
{
printInfo(*ensFaMeshPtr, optVerbose);
auto* ensFaMeshPtr = ensFaMeshes.get(areai);
if (ensFaMeshPtr)
{
printInfo(*ensFaMeshPtr, optVerbose);
}
}
}
}

View File

@ -296,7 +296,7 @@ int main(int argc, char *argv[])
(
strings,
order,
stringOps::natural_sort::less<string>(strings)
stringOps::natural_sort::list_less(strings)
);
Info<< "natural sortedOrder: " << flatOutput(order) << endl;
}
@ -321,7 +321,7 @@ int main(int argc, char *argv[])
/// sortable = hashed.toc();
/// sortable.sort
/// (
/// stringOps::natural_sort::less<string>(sortable)
/// stringOps::natural_sort::list_less(sortable)
/// );
/// Info<< nl << "natural:" << sortable << endl;
@ -329,7 +329,7 @@ int main(int argc, char *argv[])
/// sortable = hashed.toc();
/// sortable.sort
/// (
/// stringOps::natural_sort::greater<string>(sortable)
/// stringOps::natural_sort::list_greater(sortable)
/// );
/// Info<< nl << "natural:" << sortable << endl;
}

View File

@ -59,11 +59,6 @@ int main(int argc, char *argv[])
<< " type: " << typeid(cstr).name() << " len:" << len << nl;
Info<< " view: " << std::string_view(cstr) << nl;
Info<< " span: "
<< stdFoam::span<const char>(cstr, len) << nl;
Info<< " span: "
<< stdFoam::span<char>(const_cast<char*>(cstr), len) << nl;
}
}

View File

@ -1,4 +1,4 @@
mydebugSurfaceWriter.C
Test-surface-sampling.C
mydebugSurfaceWriter.cxx
Test-surface-sampling.cxx
EXE = $(FOAM_USER_APPBIN)/Test-surface-sampling

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022-2023 OpenCFD Ltd.
Copyright (C) 2022-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -83,12 +83,10 @@ template<> struct narrowType<SymmTensor<double>>
typedef SymmTensor<float> type;
};
// FIXME: Not sure why this one seems to be broken...
//
// template<> struct narrowType<Tensor<double>>
// {
// typedef Tensor<float> type;
// };
template<> struct narrowType<Tensor<double>>
{
typedef Tensor<float> type;
};
} // End namespace Foam
@ -104,12 +102,18 @@ Foam::surfaceWriters::mydebugWriter::mergeField
{
addProfiling(merge, "debugWriter::merge-field");
// This is largely identical to surfaceWriter::mergeField()
// Identical to surfaceWriter::mergeField()
// but with narrowing for communication
if (narrowTransfer_ && parallel_ && UPstream::parRun())
if constexpr (std::is_same_v<Tensor<double>, Type>)
{
// Cannot narrow tensor. Does not compile since MatrixSpace
// does not (yet) allow assigments from different Cmpt types.
}
else if (narrowTransfer_ && parallel_ && UPstream::parRun())
{
// The narrowed type
typedef typename narrowType<Type>::type narrowedType;
using narrowedType = typename narrowType<Type>::type;
// Ensure geometry is also merged
merge();
@ -130,14 +134,29 @@ Foam::surfaceWriters::mydebugWriter::mergeField
ConstPrecisionAdaptor<narrowedType, Type> input(fld);
PrecisionAdaptor<narrowedType, Type> output(allFld);
globIndex.gather
(
input.cref(), // fld,
output.ref(), // allFld,
UPstream::msgType(),
commType_,
UPstream::worldComm
);
if (gatherv_)
{
globIndex.mpiGather
(
input.cref(), // fld
output.ref(), // allFld
UPstream::worldComm,
// For fallback:
commType_,
UPstream::msgType()
);
}
else
{
globIndex.gather
(
input.cref(), // fld
output.ref(), // allFld
UPstream::msgType(),
commType_,
UPstream::worldComm
);
}
// Commit adapted content changes
input.commit();
@ -193,8 +212,19 @@ Foam::surfaceWriters::mydebugWriter::mydebugWriter
{
Info<< "Using debug surface writer ("
<< (this->isPointData() ? "point" : "face") << " data):"
<< " commsType=" << UPstream::commsTypeNames[commType_]
<< " merge=" << Switch::name(enableMerge_)
<< " commsType=";
if (UPstream::parRun())
{
if (gatherv_) Info<< "gatherv+";
Info<< UPstream::commsTypeNames[commType_];
}
else
{
Info<< "serial";
}
Info<< " merge=" << Switch::name(enableMerge_)
<< " write=" << Switch::name(enableWrite_)
<< " narrow=" << Switch::name(narrowTransfer_)
<< endl;

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2017 Wikki Ltd
Copyright (C) 2021-2023 OpenCFD Ltd.
Copyright (C) 2021-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -28,7 +28,7 @@ Application
makeFaMesh
Description
Check a finiteArea mesh
Check a finite-area mesh
Original Authors
Zeljko Tukovic, FAMENA
@ -39,6 +39,7 @@ Original Authors
#include "Time.H"
#include "argList.H"
#include "faMesh.H"
#include "faMeshTools.H"
#include "polyMesh.H"
#include "areaFaMesh.H"
#include "edgeFaMesh.H"
@ -47,7 +48,7 @@ Original Authors
#include "processorFaPatch.H"
#include "foamVtkIndPatchWriter.H"
#include "foamVtkLineWriter.H"
#include "faMeshTools.H"
#include "regionProperties.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -59,7 +60,7 @@ int main(int argc, char *argv[])
{
argList::addNote
(
"Check a finiteArea mesh"
"Check a finite-area mesh"
);
argList::addBoolOption
@ -77,9 +78,15 @@ int main(int argc, char *argv[])
);
#include "addRegionOption.H"
#include "addFaRegionOption.H"
#include "addAllFaRegionOptions.H"
#include "setRootCase.H"
#include "createTime.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
// ------------------------------------------------------------------------
#include "createNamedPolyMesh.H"
int geometryOrder(1);
@ -91,16 +98,41 @@ int main(int argc, char *argv[])
faMesh::geometryOrder(geometryOrder);
}
#include "createNamedFaMesh.H"
Info<< "Time = " << runTime.timeName() << nl << endl;
// Mesh information (verbose)
faMeshTools::printMeshChecks(aMesh);
if (args.found("write-vtk"))
for (const word& areaName : areaRegionNames)
{
#include "faMeshWriteVTK.H"
Info<< "Create faMesh";
if (!polyMesh::regionName(areaName).empty())
{
Info<< " [" << areaName << "]";
}
Info<< " for time = " << runTime.timeName() << nl;
autoPtr<faMesh> faMeshPtr(faMesh::TryNew(areaName, mesh));
if (!faMeshPtr)
{
Info<< " ...failed to create area-mesh";
if (!polyMesh::regionName(areaName).empty())
{
Info<< " [" << areaName << "]";
}
Info<< endl;
continue;
}
else
{
Info<< endl;
}
const auto& aMesh = faMeshPtr();
// Mesh information (verbose)
faMeshTools::printMeshChecks(aMesh);
if (args.found("write-vtk"))
{
#include "faMeshWriteVTK.H"
}
}
Info<< "\nEnd\n" << endl;

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2023 OpenCFD Ltd.
Copyright (C) 2021-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -15,6 +15,16 @@ Description
\*---------------------------------------------------------------------------*/
// The base name for output files
word vtkBaseFileName(aMesh.regionName());
if (polyMesh::regionName(vtkBaseFileName).empty())
{
vtkBaseFileName = "finiteArea";
}
Info<< nl;
Info<< "Write faMesh in vtk format:" << nl;
{
// finiteArea - faces
vtk::uindirectPatchWriter writer
@ -23,7 +33,7 @@ Description
// vtk::formatType::INLINE_ASCII,
fileName
(
aMesh.time().globalPath() / "finiteArea"
aMesh.time().globalPath() / vtkBaseFileName
)
);
@ -32,7 +42,7 @@ Description
globalIndex procAddr(aMesh.nFaces());
labelList cellIDs;
if (Pstream::master())
if (UPstream::master())
{
cellIDs.resize(procAddr.totalSize());
for (const labelRange& range : procAddr.ranges())
@ -53,8 +63,7 @@ Description
writer.beginPointData(1);
writer.write("normal", aMesh.pointAreaNormals());
Info<< nl
<< "Wrote faMesh in vtk format: " << writer.output().name() << nl;
Info<< " " << writer.output().name() << nl;
}
{
@ -66,7 +75,7 @@ Description
// vtk::formatType::INLINE_ASCII,
fileName
(
aMesh.time().globalPath() / "finiteArea-edges"
aMesh.time().globalPath() / (vtkBaseFileName + "-edges")
)
);
@ -88,8 +97,7 @@ Description
writer.beginPointData(1);
writer.write("normal", aMesh.pointAreaNormals());
Info<< nl
<< "Wrote faMesh in vtk format: " << writer.output().name() << nl;
Info<< " " << writer.output().name() << nl;
}
{
@ -108,7 +116,7 @@ Description
// vtk::formatType::INLINE_ASCII,
fileName
(
aMesh.time().globalPath() / "finiteArea-edgesCentres"
aMesh.time().globalPath() / (vtkBaseFileName + "-edgesCentres")
)
);
@ -134,8 +142,7 @@ Description
writer.write("normal", fld);
}
Info<< nl
<< "Wrote faMesh in vtk format: " << writer.output().name() << nl;
Info<< " " << writer.output().name() << nl;
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2023 OpenCFD Ltd.
Copyright (C) 2023-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -15,7 +15,7 @@ Description
Input
mesh (polyMesh)
meshDefDict (system/faMeshDefintion)
meshDefDict (system/finite-area/faMeshDefinition)
\*---------------------------------------------------------------------------*/
@ -25,13 +25,16 @@ Input
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
wordRes polyPatchNames;
meshDefDict.readIfPresent("polyMeshPatches", polyPatchNames);
labelList patchIDs;
const labelList patchIDs
if
(
pbm.indices(polyPatchNames, true) // useGroups
);
wordRes select;
meshDefDict.readIfPresent("polyMeshPatches", select)
)
{
patchIDs = pbm.indices(select, true); // useGroups
}
label nFaceLabels = 0;
for (const label patchi : patchIDs)

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2024 OpenCFD Ltd.
Copyright (C) 2021-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -13,6 +13,18 @@ License
Description
Search for the appropriate faMeshDefinition dictionary...
Expects to find a faMeshDefinition file in a location specified
by the command-line option, or one of the standard locations.
For default area region (region0):
(1) system/finite-area/faMeshDefinition
(2) system/faMeshDefinition [legacy location - v2312 and earlier]
For a named area region:
(1) system/finite-area/<area-name>/faMeshDefinition
(2) system/finite-area/faMeshDefinition.<area-name>
[symmetric with faOptions]
Required Classes
- Foam::polyMesh
- Foam::IOdictionary
@ -24,81 +36,185 @@ Required Variables
- runTime [Time]
Provided Variables
- meshDefDict [IOdictionary]
- meshDictPtr [autoPtr<IOdictionary>]
- faMeshDefinitionPtr [autoPtr<IOdictionary>]
If the dictionary cannot be found, exits with an error message or
reports a warning (dry-run mode)
\*---------------------------------------------------------------------------*/
const word dictName("faMeshDefinition");
autoPtr<IOdictionary> meshDictPtr;
autoPtr<IOdictionary> faMeshDefinitionPtr;
{
fileName dictPath;
const word& regionDir = Foam::polyMesh::regionName(regionName);
const word& areaRegionDir = Foam::polyMesh::regionName(areaRegionName);
// Exit unless dry-run?
const bool exitOnFailure = (!args.dryRun());
if (args.readIfPresent("dict", dictPath))
const word& regionDir = polyMesh::regionName(regionName);
const word& areaRegionDir = polyMesh::regionName(areaRegionName);
// Canonical location
fileName dictPath
(
runTime.system()/regionDir
/ faMesh::prefix()/areaRegionDir/dictName
);
// Dictionary specified on the command-line ...
const bool specified = args.readIfPresent("dict", dictPath);
if (specified)
{
// Dictionary specified on the command-line ...
if (isDir(dictPath))
{
dictPath /= dictName;
}
}
else if
(
// Dictionary under system/faMeshDefinition ?
// (v2312 and earlier)
areaRegionDir.empty()
&& exists
(
runTime.path()/runTime.caseSystem()
/ regionDir/faMesh::meshSubDir/dictName
)
)
{
// Dictionary present directly in system/ (v2312 and earlier)
dictPath = runTime.system()/regionDir/dictName;
}
else
{
// Use system/finite-area/ directory, with region qualifications
dictPath =
(
runTime.system()/regionDir
/ faMesh::prefix()/areaRegionDir/dictName
);
}
IOobject meshDictIO
(
dictPath,
runTime,
IOobject::MUST_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER,
IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER,
true // is globalObject
);
if (!meshDictIO.typeHeaderOk<IOdictionary>(true))
refPtr<IOobject> meshDictIOPtr;
bool foundIOobject = meshDictIO.typeHeaderOk<IOdictionary>(true);
// For reporting any alternative locations
dictPath.clear();
if (!foundIOobject && !specified)
{
FatalErrorInFunction
<< meshDictIO.objectPath() << nl
<< exit(FatalError);
if (!areaRegionDir.empty())
{
// Alternative location
// - system/finite-area/faMeshDefinition.<area-name>
dictPath =
(
runTime.system()/regionDir
/ faMesh::prefix()/IOobject::groupName(dictName, areaRegionDir)
);
}
else
{
// legacy location (v2312 and earlier)
// - system/faMeshDefinition
dictPath = runTime.system()/regionDir/dictName;
}
if (!dictPath.empty())
{
auto ioptr = autoPtr<IOobject>::New
(
dictPath,
runTime,
IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER,
true // is globalObject
);
foundIOobject =
(
ioptr && ioptr->typeHeaderOk<IOdictionary>(true)
);
if (foundIOobject)
{
// Use if found
meshDictIOPtr = std::move(ioptr);
}
// Generally retain dictPath for error messages,
// but don't mention the really old legacy location
if (areaRegionDir.empty())
{
dictPath.clear();
}
}
}
Info<< "Creating faMesh from definition: "
<< meshDictIO.objectRelPath() << endl;
// Alternative location or regular location?
if (!meshDictIOPtr)
{
meshDictIOPtr.cref(meshDictIO);
}
const auto& io = meshDictIOPtr();
meshDictPtr = autoPtr<IOdictionary>::New(meshDictIO);
// Handle final success or failure
if (foundIOobject)
{
Info<< "----------------" << nl
<< "Using area-mesh definition";
if (!areaRegionDir.empty())
{
Info<< " [" << areaRegionName << "]";
}
Info<< nl
<< " " << io.objectRelPath() << nl << endl;
faMeshDefinitionPtr = autoPtr<IOdictionary>::New(io);
}
else
{
// Failure
if (exitOnFailure)
{
auto& err =
FatalErrorInFunction
<< "Did not find area-mesh definition";
if (!areaRegionDir.empty())
{
err<< " [" << areaRegionName << "]";
}
err << nl
<< " " << io.objectRelPath() << nl;
if (!dictPath.empty())
{
err << " " << dictPath << nl;
}
FatalError<< exit(FatalError);
}
else
{
// dry-run: warning
auto& err =
Warning << nl
<< "----------------" << nl
<< "Did not find area-mesh definition";
if (!areaRegionDir.empty())
{
err << " [" << areaRegionName << "]";
}
err << nl
<< " " << io.objectRelPath() << nl;
if (!dictPath.empty())
{
err << " " << dictPath << nl;
}
}
}
}
IOdictionary& meshDefDict = *meshDictPtr;
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2017 Wikki Ltd
Copyright (C) 2021-2023 OpenCFD Ltd.
Copyright (C) 2021-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -40,7 +40,6 @@ Original Authors
#include "Time.H"
#include "argList.H"
#include "OSspecific.H"
#include "faMesh.H"
#include "faMeshTools.H"
#include "IOdictionary.H"
@ -53,6 +52,7 @@ Original Authors
#include "PtrListOps.H"
#include "foamVtkLineWriter.H"
#include "foamVtkIndPatchWriter.H"
#include "regionProperties.H"
#include "syncTools.H"
#include "OBJstream.H"
@ -104,12 +104,14 @@ int main(int argc, char *argv[])
);
#include "addRegionOption.H"
#include "addFaRegionOption.H"
#include "addAllFaRegionOptions.H"
#include "setRootCase.H"
#include "createTime.H"
#include "createNamedPolyMesh.H"
#include "getFaRegionOption.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
const bool doDecompose = !args.found("no-decompose");
const bool doDecompFields = !args.found("no-fields");
@ -123,56 +125,83 @@ int main(int argc, char *argv[])
Info<< "Skip decompose of finiteArea fields" << nl;
}
// Reading faMeshDefinition dictionary
#include "findMeshDefinitionDict.H"
// ------------------------------------------------------------------------
// Inject/overwrite name for optional 'empty' patch
word patchName;
if (args.readIfPresent("empty-patch", patchName))
for (const word& areaRegionName : areaRegionNames)
{
meshDefDict.add("emptyPatch", patchName, true);
}
// Reading faMeshDefinition dictionary
#include "findMeshDefinitionDict.H"
// Preliminary checks
#include "checkPatchTopology.H"
if (!faMeshDefinitionPtr)
{
if (args.dryRun())
{
break;
}
else
{
FatalErrorInFunction
<< "Did not find area-mesh definition"<< nl
<< exit(FatalError);
}
}
Info << "Create areaMesh";
if (!Foam::polyMesh::regionName(areaRegionName).empty())
{
Foam::Info << ' ' << areaRegionName;
}
Info << " for polyMesh at time = " << runTime.timeName() << nl;
auto& meshDefDict = (*faMeshDefinitionPtr);
// Create
faMesh aMesh(areaRegionName, mesh, meshDefDict);
// Mesh information (less verbose)
faMeshTools::printMeshChecks(aMesh, 0);
// Inject/overwrite name for optional 'empty' patch
if (word name; args.readIfPresent("empty-patch", name))
{
meshDefDict.add("emptyPatch", name, true);
}
if (args.found("write-edges-obj"))
{
#include "faMeshWriteEdgesOBJ.H"
}
// Preliminary checks
#include "checkPatchTopology.H"
if (args.found("write-vtk"))
{
#include "faMeshWriteVTK.H"
}
Info<< "Create area-mesh";
if (!polyMesh::regionName(areaRegionName).empty())
{
Info<< " [" << areaRegionName << "]";
}
Info<< " with polyMesh at time = " << runTime.timeName() << nl;
if (args.dryRun())
{
Info<< "\ndry-run: not writing mesh or decomposing fields\n" << nl;
}
else
{
// More precision (for points data)
IOstream::minPrecision(10);
// Create
faMesh aMesh(areaRegionName, mesh, meshDefDict);
Info<< nl << "Write finite area mesh." << nl;
aMesh.write();
// Mesh information (less verbose)
faMeshTools::printMeshChecks(aMesh, 0);
Info<< endl;
#include "decomposeFaFields.H"
if (args.found("write-edges-obj"))
{
#include "faMeshWriteEdgesOBJ.H"
}
if (args.found("write-vtk"))
{
#include "faMeshWriteVTK.H"
}
if (args.dryRun())
{
Info<< "\ndry-run: not writing mesh or decomposing fields\n" << nl;
}
else
{
// More precision (for points data)
IOstream::minPrecision(10);
Info<< nl << "Write finite area mesh";
if (const word& name = aMesh.regionName(); !name.empty())
{
Info<< " [" << name << "]";
}
Info<< nl;
aMesh.write();
Info<< endl;
#include "decomposeFaFields.H"
}
}
Info<< "\nEnd\n" << endl;

View File

@ -30,7 +30,8 @@ Group
grpPostProcessingUtilities
Description
List regions from constant/regionProperties.
List volume regions from constant/regionProperties
or area regions from constant/finite-area/regionProperties
Usage
\b foamListRegions [OPTION]
@ -72,6 +73,12 @@ int main(int argc, char *argv[])
"List constant/finite-area/regionProperties (if available)"
);
argList::addBoolOption
(
"optional",
"A missing regionProperties is not treated as an error"
);
argList::addDryRunOption
(
"Make reading optional and add verbosity"
@ -92,14 +99,20 @@ int main(int argc, char *argv[])
++optVerbose;
}
// File is optional, not an error
const bool isOptional = args.found("optional");
// Use finite-area regions
const bool doFiniteArea = args.found("finite-area");
// The number of optional region filters to apply
const label nFilters = (args.size()-1);
IOobjectOption::readOption readOpt(IOobjectOption::MUST_READ);
if (dryRun || doFiniteArea)
if (dryRun || isOptional || doFiniteArea)
{
// Always treat finite-area regionProperties as optional
// The finite-area regionProperties are also considered optional
readOpt = IOobjectOption::READ_IF_PRESENT;
}
@ -116,58 +129,70 @@ int main(int argc, char *argv[])
if (doFiniteArea)
{
regionProps = regionProperties(runTime, faMeshPrefix, readOpt);
if (regionProps.empty())
{
InfoErr<< "No finite-area region types" << nl;
}
else if (optVerbose)
{
InfoErr
<< "Have " << regionProps.size()
<< " finite-area region types, "
<< regionProps.count() << " regions" << nl << nl;
}
}
else
{
regionProps = regionProperties(runTime, readOpt);
if (regionProps.empty())
{
// Probably only occurs with -dry-run option
InfoErr<< "No region types" << nl;
}
else if (optVerbose)
{
InfoErr
<< "Have " << regionProps.size() << " region types, "
<< regionProps.count() << " regions" << nl << nl;
}
}
// We now handle checking args and general sanity etc.
wordList regionTypes;
if (args.size() > 1)
// Some reporting...
if (regionProps.empty())
{
regionTypes.resize(args.size()-1);
if (doFiniteArea)
{
InfoErr<< "No finite-area region types" << nl;
}
else if (isOptional)
{
InfoErr<< "No region types" << nl;
}
}
else if (optVerbose)
{
InfoErr << "Have " << regionProps.size();
// No duplicates
if (doFiniteArea)
{
InfoErr<< " finite-area";
}
InfoErr
<< " region types, "
<< regionProps.count() << " regions" << nl << nl;
}
// We now handle checking args and general sanity etc.
DynamicList<word> regionTypes;
if (isOptional && regionProps.empty())
{
// Nothing to do...
}
else if (nFilters > 0)
{
// Apply region filters
regionTypes.reserve_exact
(
Foam::min(nFilters, regionProps.size())
);
// No duplicates, and no duplicate warnings
wordHashSet uniq;
label nTypes = 0;
for (label argi = 1; argi < args.size(); ++argi)
{
regionTypes[nTypes] = args[argi];
const word& regType = regionTypes[nTypes];
word regType(args[argi]);
if (uniq.insert(regType))
{
if (regionProps.contains(regType))
{
++nTypes;
if (!regionTypes.contains(regType))
{
regionTypes.push_back(std::move(regType));
}
}
else
{
@ -175,22 +200,22 @@ int main(int argc, char *argv[])
}
}
}
regionTypes.resize(nTypes);
}
else
{
// Take all regions
regionTypes = regionProps.sortedToc();
}
for (const word& regionType : regionTypes)
{
const wordList& regionNames = regionProps[regionType];
for (const word& regionName : regionNames)
if (const auto iter = regionProps.cfind(regionType); iter.good())
{
Info<< regionName << nl;
for (const word& regionName : iter.val())
{
Info<< regionName << nl;
}
}
}

View File

@ -334,6 +334,7 @@ int main(int argc, char *argv[])
);
#include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
argList::addDryRunOption
(
@ -418,8 +419,14 @@ int main(int argc, char *argv[])
// Allow explicit -constant, have zero from time range
timeSelector::addOptions(true, false); // constant(true), zero(false)
// Prevent volume BCs from triggering finite-area
regionModels::allowFaModels(false);
#include "setRootCase.H"
// ------------------------------------------------------------------------
// Configuration
const bool writeCellDist = args.found("cellDist");
// Most of these are ignored for dry-run (not triggered anywhere)
@ -436,7 +443,6 @@ int main(int argc, char *argv[])
bool decomposeFieldsOnly = args.found("fields");
bool forceOverwrite = args.found("force");
// Set time from database
#include "createTime.H"
@ -485,9 +491,17 @@ int main(int argc, char *argv[])
decompDictFile = runTime.globalPath()/decompDictFile;
}
// Get region names
// Handle -allRegions, -regions, -region
#include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
const bool optRegions =
(regionNames.size() != 1 || regionNames[0] != polyMesh::defaultRegion);
@ -807,56 +821,76 @@ int main(int argc, char *argv[])
// Field objects at this time
IOobjectList objects;
IOobjectList faObjects;
// faMesh fields - can have multiple finite-area per volume
HashTable<IOobjectList> faObjects;
if (doDecompFields)
{
// List of volume mesh objects for this instance
objects = IOobjectList(mesh, runTime.timeName());
// List of area mesh objects (assuming single region)
faObjects = IOobjectList
(
mesh.time(),
runTime.timeName(),
faMesh::dbDir(mesh, word::null),
IOobjectOption::NO_REGISTER
);
// Ignore generated fields: (cellDist)
objects.remove("cellDist");
// Lists of finite-area fields
faObjects.reserve(areaRegionNames.size());
for (const word& areaName : areaRegionNames)
{
// The finite-area objects for this area region
IOobjectList objs
(
faMesh::Registry(mesh),
runTime.timeName(),
polyMesh::regionName(areaName),
IOobjectOption::NO_REGISTER
);
if (!objs.empty())
{
faObjects.emplace_set(areaName, std::move(objs));
}
}
}
// Finite area handling
autoPtr<faMeshDecomposition> faMeshDecompPtr;
// - all area regions use the same volume decomposition
HashPtrTable<faMeshDecomposition> faMeshDecompHashes;
if (doFiniteArea)
{
const word boundaryInst =
mesh.time().findInstance(mesh.meshDir(), "boundary");
IOobject io
(
"faBoundary",
boundaryInst,
faMesh::meshDir(mesh, word::null),
mesh.time(),
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
);
if (io.typeHeaderOk<faBoundaryMesh>(true))
for (const word& areaName : areaRegionNames)
{
// Always based on the volume decomposition!
faMeshDecompPtr.reset
IOobject io
(
new faMeshDecomposition
(
mesh,
mesh.nProcs(),
mesh.model()
)
"faBoundary",
boundaryInst,
faMesh::meshDir(mesh, areaName),
mesh.time(),
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
);
if (io.typeHeaderOk<faBoundaryMesh>(true))
{
// Always based on the volume decomposition!
faMeshDecompHashes.set
(
areaName,
autoPtr<faMeshDecomposition>::New
(
areaName,
mesh,
mesh.nProcs(),
mesh.model()
)
);
}
}
}
@ -1060,7 +1094,7 @@ int main(int argc, char *argv[])
processorDb.setTime(runTime);
// read the mesh
// Read the mesh
if (!procMeshList.set(proci))
{
procMeshList.set
@ -1267,12 +1301,15 @@ int main(int argc, char *argv[])
}
// Finite area mesh and field decomposition
if (faMeshDecompPtr)
// Finite-area mesh and field decomposition
for (auto& iter : faMeshDecompHashes.sorted())
{
Info<< "\nFinite area mesh decomposition" << endl;
const word& areaName = iter.key();
faMeshDecomposition& aMesh = faMeshDecompPtr();
faMeshDecomposition& aMesh = *(iter.val());
Info<< "\nFinite area mesh decomposition: "
<< areaName << endl;
aMesh.decomposeMesh();
aMesh.writeDecomposition();
@ -1283,9 +1320,13 @@ int main(int argc, char *argv[])
faFieldDecomposer::fieldsCache areaFieldCache;
if (doDecompFields)
if
(
const auto objs = faObjects.cfind(areaName);
doDecompFields && objs.good()
)
{
areaFieldCache.readAllFields(aMesh, faObjects);
areaFieldCache.readAllFields(aMesh, objs.val());
}
const label nAreaFields = areaFieldCache.size();
@ -1316,7 +1357,7 @@ int main(int argc, char *argv[])
processorDb.setTime(runTime);
// Read the mesh
// Read the volume mesh
fvMesh procFvMesh
(
IOobject
@ -1327,7 +1368,7 @@ int main(int argc, char *argv[])
)
);
faMesh procMesh(procFvMesh);
faMesh procMesh(areaName, procFvMesh);
// // Does not work. HJ, 15/Aug/2017
// const labelIOList& faceProcAddressing =
@ -1386,7 +1427,11 @@ int main(int argc, char *argv[])
boundaryProcAddressing
);
areaFieldCache.decomposeAllFields(fieldDecomposer);
areaFieldCache.decomposeAllFields
(
fieldDecomposer,
args.verbose() // report
);
}
}
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015-2023 OpenCFD Ltd.
Copyright (C) 2015-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -91,6 +91,7 @@ int main(int argc, char *argv[])
argList::noParallel();
#include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
argList::addVerboseOption();
argList::addOption
@ -135,9 +136,14 @@ int main(int argc, char *argv[])
"Only reconstruct new times (i.e. that do not exist already)"
);
// Prevent volume BCs from triggering finite-area
regionModels::allowFaModels(false);
#include "setRootCase.H"
#include "createTime.H"
// ------------------------------------------------------------------------
// Configuration
const bool doFields = !args.found("no-fields");
wordRes selectedFields;
@ -196,9 +202,17 @@ int main(int argc, char *argv[])
const bool newTimes = args.found("newTimes");
// Get region names
// Handle -allRegions, -regions, -region
#include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
// Determine the processor count
label nProcs{0};
@ -386,19 +400,30 @@ int main(int argc, char *argv[])
IOobjectOption::NO_REGISTER
);
IOobjectList faObjects;
// The finite-area fields (multiple finite-area per volume)
HashTable<IOobjectList> faObjects;
if (doFiniteArea && doFields)
{
// List of area mesh objects (assuming single region)
// - scan on processor0
faObjects = IOobjectList
(
procMeshes.meshes()[0],
databases[0].timeName(),
faMesh::dbDir(word::null), // local relative to mesh
IOobjectOption::NO_REGISTER
);
// Lists of finite-area fields - scan on processor0
faObjects.reserve(areaRegionNames.size());
for (const word& areaName : areaRegionNames)
{
// The finite-area objects for this area region
IOobjectList objs
(
procMeshes.meshes()[0],
databases[0].timeName(),
faMesh::dbDir(areaName), // local relative to mesh
IOobjectOption::NO_REGISTER
);
if (!objs.empty())
{
faObjects.emplace_set(areaName, std::move(objs));
}
}
}
if (doFields)
@ -548,42 +573,60 @@ int main(int argc, char *argv[])
}
// If there are any FA fields, reconstruct them
if (!doFiniteArea)
// Reconstruct any finite-area fields
if (doFiniteArea)
{
bool hadFaFields = false;
for (const word& areaName : areaRegionNames)
{
const auto objs = faObjects.cfind(areaName);
if (!objs.good())
{
continue;
}
const auto& faObjs = objs.val();
if
(
!faObjs.count(fieldTypes::is_area)
&& !faObjs.count<edgeScalarField>()
)
{
continue;
}
hadFaFields = true;
Info<< "Reconstructing finite-area fields ["
<< polyMesh::regionName(areaName)
<< "]" << nl << endl;
const faMesh aMesh(areaName, mesh);
processorFaMeshes procFaMeshes
(
procMeshes.meshes(),
areaName
);
faFieldReconstructor reconstructor
(
aMesh,
procFaMeshes.meshes(),
procFaMeshes.edgeProcAddressing(),
procFaMeshes.faceProcAddressing(),
procFaMeshes.boundaryProcAddressing()
);
reconstructor.reconstructAllFields(faObjs);
}
if (!hadFaFields)
{
Info << "No finite-area fields" << nl << endl;
}
}
else if
(
faObjects.count<areaScalarField>()
|| faObjects.count<areaVectorField>()
|| faObjects.count<areaSphericalTensorField>()
|| faObjects.count<areaSymmTensorField>()
|| faObjects.count<areaTensorField>()
|| faObjects.count<edgeScalarField>()
)
{
Info << "Reconstructing FA fields" << nl << endl;
faMesh aMesh(mesh);
processorFaMeshes procFaMeshes(procMeshes.meshes());
faFieldReconstructor reconstructor
(
aMesh,
procFaMeshes.meshes(),
procFaMeshes.edgeProcAddressing(),
procFaMeshes.faceProcAddressing(),
procFaMeshes.boundaryProcAddressing()
);
reconstructor.reconstructAllFields(faObjects);
}
else
{
Info << "No FA fields" << nl << endl;
}
if (doReconstructSets)
{

View File

@ -119,17 +119,10 @@ autoPtr<faceCoupleInfo> determineCoupledFaces
const polyBoundaryMesh& masterPatches = masterMesh.boundaryMesh();
DynamicList<label> masterFaces
(
masterMesh.nFaces()
- masterMesh.nInternalFaces()
);
DynamicList<label> masterFaces(masterMesh.nBoundaryFaces());
forAll(masterPatches, patchi)
for (const polyPatch& pp : masterPatches)
{
const polyPatch& pp = masterPatches[patchi];
if (isA<processorPolyPatch>(pp))
{
for
@ -139,11 +132,8 @@ autoPtr<faceCoupleInfo> determineCoupledFaces
proci++
)
{
const string toProcString("to" + name(proci));
if (
pp.name().rfind(toProcString)
== (pp.name().size()-toProcString.size())
)
const string toProcString("to" + Foam::name(proci));
if (pp.name().ends_with(toProcString))
{
label meshFacei = pp.start();
forAll(pp, i)
@ -156,7 +146,6 @@ autoPtr<faceCoupleInfo> determineCoupledFaces
}
}
masterFaces.shrink();
// Pick up all patches on meshToAdd ending in "procBoundaryDDDtoYYY"
@ -164,16 +153,10 @@ autoPtr<faceCoupleInfo> determineCoupledFaces
const polyBoundaryMesh& addPatches = meshToAdd.boundaryMesh();
DynamicList<label> addFaces
(
meshToAdd.nFaces()
- meshToAdd.nInternalFaces()
);
DynamicList<label> addFaces(meshToAdd.nBoundaryFaces());
forAll(addPatches, patchi)
for (const polyPatch& pp : addPatches)
{
const polyPatch& pp = addPatches[patchi];
if (isA<processorPolyPatch>(pp))
{
bool isConnected = false;
@ -215,7 +198,6 @@ autoPtr<faceCoupleInfo> determineCoupledFaces
}
}
}
addFaces.shrink();
return autoPtr<faceCoupleInfo>::New
(
@ -502,15 +484,14 @@ void writeMaps
Info<< " pointProcAddressing" << endl;
ioAddr.rename("pointProcAddressing");
IOList<label>::writeContents(ioAddr, pointProcAddressing);
labelIOList::writeContents(ioAddr, pointProcAddressing);
// From processor face to reconstructed mesh face
Info<< " faceProcAddressing" << endl;
ioAddr.rename("faceProcAddressing");
labelIOList faceProcAddr(ioAddr, faceProcAddressing);
// - add turning index to faceProcAddressing.
// See reconstructPar for meaning of turning index.
labelList faceProcAddr(faceProcAddressing);
// Now add turning index to faceProcAddressing.
// See reconstructPar for meaning of turning index.
forAll(faceProcAddr, procFacei)
{
const label masterFacei = faceProcAddr[procFacei];
@ -545,19 +526,21 @@ void writeMaps
}
}
faceProcAddr.write();
Info<< " faceProcAddressing" << endl;
ioAddr.rename("faceProcAddressing");
labelIOList::writeContents(ioAddr, faceProcAddr);
faceProcAddr.clear();
// From processor cell to reconstructed mesh cell
Info<< " cellProcAddressing" << endl;
ioAddr.rename("cellProcAddressing");
IOList<label>::writeContents(ioAddr, cellProcAddressing);
labelIOList::writeContents(ioAddr, cellProcAddressing);
// From processor patch to reconstructed mesh patch
Info<< " boundaryProcAddressing" << endl;
ioAddr.rename("boundaryProcAddressing");
IOList<label>::writeContents(ioAddr, boundProcAddressing);
labelIOList::writeContents(ioAddr, boundProcAddressing);
Info<< endl;
}
@ -645,7 +628,8 @@ void sortFaEdgeMapping
{
// From faMeshReconstructor.C - edge shuffling on patches
Map<label> remapGlobal(2*onePatch.nEdges());
Map<label> remapGlobal;
remapGlobal.reserve(onePatch.nEdges());
for (label edgei = 0; edgei < onePatch.nInternalEdges(); ++edgei)
{
remapGlobal.insert(edgei, remapGlobal.size());
@ -779,12 +763,23 @@ int main(int argc, char *argv[])
);
#include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
// Prevent volume fields [with regionFaModels] from incidental
// triggering finite-area
regionModels::allowFaModels(false);
// Prevent volume BCs from triggering finite-area
regionModels::allowFaModels(false);
#include "setRootCase.H"
#include "createTime.H"
printWarning();
// ------------------------------------------------------------------------
// Configuration
const bool fullMatch = args.found("fullMatch");
const bool procMatch = args.found("procMatch");
const bool writeCellDist = args.found("cellDist");
@ -835,9 +830,17 @@ int main(int argc, char *argv[])
}
}
// Get region names
// Handle -allRegions, -regions, -region
#include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
// Determine the processor count
label nProcs{0};
@ -929,7 +932,8 @@ int main(int argc, char *argv[])
polyMesh::meshDir(regionName),
databases[0],
IOobject::NO_READ,
IOobject::NO_WRITE
IOobject::NO_WRITE,
IOobject::NO_REGISTER
);
// Problem: faceCompactIOList recognises both 'faceList' and
@ -1399,8 +1403,12 @@ int main(int argc, char *argv[])
// Read finite-area
PtrList<faMesh> procFaMeshes(databases.size());
// For each named area region that exists create a HashTable
// entry that will contain the PtrList for all processors
PtrList<polyMesh> procMeshes(databases.size());
HashTable<PtrList<faMesh>> procAreaRegionMeshes;
procAreaRegionMeshes.reserve(areaRegionNames.size());
forAll(databases, proci)
{
@ -1408,20 +1416,16 @@ int main(int argc, char *argv[])
<< "Read processor mesh: "
<< (databases[proci].caseName()/regionDir) << endl;
procMeshes.set
const polyMesh& procMesh = procMeshes.emplace
(
proci,
new polyMesh
IOobject
(
IOobject
(
regionName,
databases[proci].timeName(),
databases[proci]
)
regionName,
databases[proci].timeName(),
databases[proci]
)
);
const polyMesh& procMesh = procMeshes[proci];
writeMaps
(
@ -1444,38 +1448,67 @@ int main(int argc, char *argv[])
"boundary"
);
IOobject io
(
"faBoundary",
boundaryInst,
faMesh::meshDir(procMesh, word::null),
procMesh.time(),
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
);
if (io.typeHeaderOk<faBoundaryMesh>(true))
for (const word& areaName : areaRegionNames)
{
// Always based on the volume decomposition!
procFaMeshes.set(proci, new faMesh(procMesh));
IOobject io
(
"faBoundary",
boundaryInst,
faMesh::meshDir(procMesh, areaName),
procMesh.time(),
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
);
if (io.typeHeaderOk<faBoundaryMesh>(true))
{
// Always based on the volume decomposition!
auto& procFaMeshes = procAreaRegionMeshes(areaName);
procFaMeshes.resize(databases.size());
procFaMeshes.set
(
proci,
new faMesh(areaName, procMesh)
);
}
}
}
}
// Finite-area mapping
doFiniteArea = false;
forAll(procFaMeshes, proci)
// A finite-area mapping exists if procFaMeshes was filled
// Re-read reconstructed polyMesh. Note: could probably be avoided
// by merging into loops above.
refPtr<polyMesh> masterPolyMeshPtr;
if (!procAreaRegionMeshes.empty())
{
if (procFaMeshes.set(proci))
{
doFiniteArea = true;
}
masterPolyMeshPtr.reset
(
new polyMesh
(
IOobject
(
regionName,
runTime.timeName(),
runTime
),
true
)
);
}
if (doFiniteArea)
// Process any finite-area meshes
for (const auto& iter : procAreaRegionMeshes.csorted())
{
const auto& areaName = iter.key();
const auto& procFaMeshes = iter.val();
const polyMesh& masterMesh = masterPolyMeshPtr();
// Addressing from processor to reconstructed case
labelListList faFaceProcAddressing(nProcs);
labelListList faEdgeProcAddressing(nProcs);
@ -1493,32 +1526,10 @@ int main(int argc, char *argv[])
faBoundProcAddressing[proci] = identity(bm.size());
// Mark processor patches
for
(
label patchi = bm.nNonProcessor();
patchi < bm.size();
++patchi
)
{
faBoundProcAddressing[proci][patchi] = -1;
}
faBoundProcAddressing[proci].slice(bm.nNonProcessor()) = -1;
}
// Re-read reconstructed polyMesh. Note: could probably be avoided
// by merging into loops above.
const polyMesh masterMesh
(
IOobject
(
regionName,
runTime.timeName(),
runTime
),
true
);
// faceProcAddressing
// ~~~~~~~~~~~~~~~~~~
@ -1553,13 +1564,13 @@ int main(int argc, char *argv[])
// Construct without patches
faMesh masterFaMesh
(
areaName,
masterMesh,
std::move(masterFaceLabels),
io
);
const uindirectPrimitivePatch& masterPatch =
masterFaMesh.patch();
const auto& masterPatch = masterFaMesh.patch();
// pointProcAddressing
@ -1571,7 +1582,7 @@ int main(int argc, char *argv[])
const auto& procPatch = procFaMeshes[proci].patch();
const auto& mp = procPatch.meshPoints();
labelList& pointAddr = faPointProcAddressing[proci];
auto& pointAddr = faPointProcAddressing[proci];
pointAddr.resize_nocopy(mp.size());
forAll(mp, i)
@ -1620,8 +1631,7 @@ int main(int argc, char *argv[])
label nPatches = 0;
forAll(completePatches, patchi)
{
const labelList& patchEdgeLabels =
singlePatchEdgeLabels[patchi];
const auto& patchEdgeLabels = singlePatchEdgeLabels[patchi];
const faPatch& fap = procMesh0.boundary()[patchi];
@ -1652,11 +1662,11 @@ int main(int argc, char *argv[])
// Serial mesh - no parallel communication
const bool oldParRun = Pstream::parRun(false);
const bool oldParRun = UPstream::parRun(false);
masterFaMesh.addFaPatches(completePatches);
Pstream::parRun(oldParRun); // Restore parallel state
UPstream::parRun(oldParRun); // Restore parallel state
// Write mesh & individual addressing

View File

@ -33,99 +33,266 @@ License
#include "decomposedBlockData.H"
#include "IFstream.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
bool Foam::checkFileExistence(const fileName& fName)
// Trimmed-down version of lookupAndCacheProcessorsPath
// with Foam::exists() check. No caching.
// Check for two conditions:
// - file has to exist
// - if collated the entry has to exist inside the file
// Note: bypass fileOperation::filePath(IOobject&) since has problems
// with going to a different number of processors
// (in collated format). Use file-based searching instead
namespace Foam
{
// Trimmed-down version of lookupAndCacheProcessorsPath
// with Foam::exists() check. No caching.
// Check for two conditions:
// - file has to exist
// - if collated the entry has to exist inside the file
// Note: bypass fileOperation::filePath(IOobject&) since has problems
// with going to a different number of processors
// (in collated format). Use file-based searching instead
const auto& handler = Foam::fileHandler();
typedef fileOperation::procRangeType procRangeType;
fileName path, pDir, local;
procRangeType group;
label numProcs;
const label proci =
fileOperation::splitProcessorPath
(fName, path, pDir, local, group, numProcs);
// If indeed collated format:
// Collect block-number in individual filenames
// (might differ on different processors)
static bool checkFileExistenceCollated
(
const Foam::fileOperation& handler,
const Foam::fileName& fName
)
{
// using namespace Foam;
bool found = false;
if (proci != -1)
{
// Read all directories to see any beginning with processor
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const label handlerComm = handler.comm();
const fileNameList dirEntries
(
handler.readDir(path, fileName::Type::DIRECTORY)
);
const label globalProci = UPstream::myProcNo(UPstream::worldComm);
const label handlerProci = UPstream::myProcNo(handlerComm);
const label nHandlerProcs = UPstream::nProcs(handlerComm);
// Extract info from processorN or processorsNN
// - highest processor number
// - directory+offset containing data for proci
// label nProcs = 0;
for (const fileName& dirN : dirEntries)
// Determine my local block number
label myBlockNumber = -1;
{
// Analyse directory name
label rNum(-1);
const label readProci =
fileOperation::detectProcessorPath(dirN, group, &rNum);
fileOperation::procRangeType group;
label proci = fileOperation::detectProcessorPath(fName, group);
if (proci == readProci)
if (proci == -1 && group.empty())
{
// Found "processorN"
if (Foam::exists(path/dirN/local))
{
found = true;
break;
}
// 'processorsXXX' format so contains all ranks
// according to worldComm
myBlockNumber = globalProci;
}
else if (rNum != -1)
else
{
// "processorsNN" or "processorsNN_start-end"
if (group.empty())
{
// "processorsNN"
if (proci < rNum && Foam::exists(path/dirN/local))
{
found = true;
break;
}
}
else if (group.contains(proci))
{
// "processorsNN_start-end"
// - save the local proc offset
if (Foam::exists(path/dirN/local))
{
found = true;
break;
}
}
// 'processorsXXX_n-m' format so check for relative rank
myBlockNumber = handlerProci;
}
}
}
if (!found)
{
found = Foam::exists(fName);
// Since we are streaming anyhow, could also pack as tuple:
// Tuple2<fileName, label>
// Collect file names on master of local communicator
const fileNameList fNames
(
Pstream::listGatherValues
(
fName,
handlerComm,
UPstream::msgType()
)
);
// Collect block numbers on master of local communicator
const labelList myBlockNumbers
(
Pstream::listGatherValues
(
myBlockNumber,
handlerComm,
UPstream::msgType()
)
);
// Determine for all whether the filename exists in the collated file.
boolList allFound;
if (UPstream::master(handlerComm))
{
allFound.resize(nHandlerProcs, false);
// Store nBlocks and index of file that was used for nBlocks
label nBlocks = -1;
label blockRanki = -1;
forAll(fNames, ranki)
{
if
(
blockRanki == -1
|| (fNames[ranki] != fNames[blockRanki])
)
{
blockRanki = ranki;
IFstream is(fNames[ranki]);
nBlocks = decomposedBlockData::getNumBlocks(is);
}
allFound[ranki] = (myBlockNumbers[ranki] < nBlocks);
}
}
// Scatter using the handler communicator
found = Pstream::listScatterValues
(
allFound,
handlerComm,
UPstream::msgType()
);
}
return found;
}
} // End namespace
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
Foam::bitSet Foam::haveProcessorFile
(
const word& name, // eg "faces"
const fileName& instance, // eg "constant"
const fileName& local, // eg, polyMesh
const Time& runTime,
const bool verbose
)
{
const auto& handler = Foam::fileHandler();
const fileName fName
(
handler.filePath(runTime.path()/instance/local/name)
);
bool found = handler.isFile(fName);
// Assume non-collated (as fallback value).
// If everyone claims to have the file, use master to verify if
// collated is involved.
bool isCollated = false;
if (returnReduceAnd(found, UPstream::worldComm))
{
// Test for collated format.
// Note: can test only world-master. Since even host-collated will have
// same file format type for all processors
if (UPstream::master(UPstream::worldComm))
{
const bool oldParRun = UPstream::parRun(false);
if (IFstream is(fName); is.good())
{
IOobject io(name, instance, local, runTime);
io.readHeader(is);
isCollated = decomposedBlockData::isCollatedType(io);
}
UPstream::parRun(oldParRun);
}
Pstream::broadcast(isCollated, UPstream::worldComm);
}
// For collated, check that the corresponding blocks exist
if (isCollated)
{
found = checkFileExistenceCollated(handler, fName);
}
// Globally consistent information about who has the file
bitSet haveFileOnProc = bitSet::allGather(found, UPstream::worldComm);
if (verbose)
{
Info<< "Per processor availability of \""
<< name << "\" file in " << instance/local << nl
<< " " << flatOutput(haveFileOnProc) << nl << endl;
}
return haveFileOnProc;
}
Foam::boolList Foam::haveMeshFile
(
const word& name, // eg "faces"
const fileName& instance, // eg "constant"
const fileName& local, // eg, polyMesh
const Time& runTime,
const bool verbose
)
{
const auto& handler = Foam::fileHandler();
const fileName fName
(
handler.filePath(runTime.path()/instance/local/name)
);
bool found = handler.isFile(fName);
// Assume non-collated (as fallback value).
// If everyone claims to have the file, use master to verify if
// collated is involved.
bool isCollated = false;
if (returnReduceAnd(found, UPstream::worldComm))
{
// Test for collated format.
// Note: can test only world-master. Since even host-collated will have
// same file format type for all processors
if (UPstream::master(UPstream::worldComm))
{
const bool oldParRun = UPstream::parRun(false);
if (IFstream is(fName); is.good())
{
IOobject io(name, instance, local, runTime);
io.readHeader(is);
isCollated = decomposedBlockData::isCollatedType(io);
}
UPstream::parRun(oldParRun);
}
Pstream::broadcast(isCollated, UPstream::worldComm);
}
// For collated, check that the corresponding blocks exist
if (isCollated)
{
found = checkFileExistenceCollated(handler, fName);
}
// Globally consistent information about who has a mesh
boolList haveFileOnProc
(
UPstream::allGatherValues<bool>(found, UPstream::worldComm)
);
if (verbose)
{
Info<< "Per processor availability of \""
<< name << "\" file in " << instance/local << nl
<< " " << flatOutput(haveFileOnProc) << nl << endl;
}
return haveFileOnProc;
}
Foam::boolList Foam::haveMeshFile
(
@ -135,143 +302,49 @@ Foam::boolList Foam::haveMeshFile
const bool verbose
)
{
#if 0
// Simple directory scanning - too fragile
bool found = checkFileExistence(runTime.path()/meshPath/meshFile);
#else
// Trimmed-down version of lookupAndCacheProcessorsPath
// with Foam::exists() check. No caching.
// Check for two conditions:
// - file has to exist
// - if collated the entry has to exist inside the file
// Note: bypass fileOperation::filePath(IOobject&) since has problems
// with going to a different number of processors
// (in collated format). Use file-based searching instead
const auto& handler = Foam::fileHandler();
typedef fileOperation::procRangeType procRangeType;
const fileName fName
(
handler.filePath(runTime.path()/meshPath/meshFile)
);
bool found = handler.isFile(fName);
if (returnReduceAnd(found)) // worldComm
// Assume non-collated (as fallback value).
// If everyone claims to have the file, use master to verify if
// collated is involved.
bool isCollated = false;
if (returnReduceAnd(found, UPstream::worldComm))
{
// Bit tricky: avoid having all slaves open file since this involves
// reading it on master and broadcasting it. This fails if file > 2G.
// So instead only read on master
bool isCollated = false;
// Test for collated format.
// Note: can test only world-master. Since even host-collated will have
// same file format type for all processors
if (UPstream::master(UPstream::worldComm))
{
const bool oldParRun = UPstream::parRun(false);
IFstream is(fName);
if (is.good())
if (IFstream is(fName); is.good())
{
IOobject io(meshFile, meshPath, runTime);
io.readHeader(is);
isCollated = decomposedBlockData::isCollatedType(io);
}
UPstream::parRun(oldParRun);
}
Pstream::broadcast(isCollated); //UPstream::worldComm
// Collect block-number in individual filenames (might differ
// on different processors)
if (isCollated)
{
const label nProcs = UPstream::nProcs(fileHandler().comm());
const label myProcNo = UPstream::myProcNo(fileHandler().comm());
// Collect file names on master of local communicator
const fileNameList fNames
(
Pstream::listGatherValues
(
fName,
fileHandler().comm(),
UPstream::msgType()
)
);
// Collect local block number
label myBlockNumber = -1;
{
procRangeType group;
label proci = fileOperation::detectProcessorPath(fName, group);
if (proci == -1 && group.empty())
{
// 'processorsXXX' format so contains all ranks
// according to worldComm
myBlockNumber = UPstream::myProcNo(UPstream::worldComm);
}
else
{
// 'processorsXXX_n-m' format so check for the
// relative rank
myBlockNumber = myProcNo;
}
}
const labelList myBlockNumbers
(
Pstream::listGatherValues
(
myBlockNumber,
fileHandler().comm(),
UPstream::msgType()
)
);
// Determine for all whether the filename exists in the collated
// file.
boolList allFound(nProcs, false);
if (UPstream::master(fileHandler().comm()))
{
// Store nBlocks and index of file that was used for nBlocks
label nBlocks = -1;
label blockRanki = -1;
forAll(fNames, ranki)
{
if
(
blockRanki == -1
|| (fNames[ranki] != fNames[blockRanki])
)
{
blockRanki = ranki;
IFstream is(fNames[ranki]);
nBlocks = decomposedBlockData::getNumBlocks(is);
}
allFound[ranki] = (myBlockNumbers[ranki] < nBlocks);
}
}
found = Pstream::listScatterValues
(
allFound,
fileHandler().comm(),
UPstream::msgType()
);
}
Pstream::broadcast(isCollated, UPstream::worldComm);
}
#endif
// For collated, check that the corresponding blocks exist
if (isCollated)
{
found = checkFileExistenceCollated(handler, fName);
}
// Globally consistent information about who has a mesh
boolList haveFileOnProc

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012 OpenFOAM Foundation
Copyright (C) 2022-2023 OpenCFD Ltd.
Copyright (C) 2022-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -48,15 +48,32 @@ namespace Foam
// Forward Declarations
class faMesh;
//- Check for availability of given file
bool checkFileExistence(const fileName& fName);
//- Check for availability of specified file (on all ranks)
bitSet haveProcessorFile
(
const word& name, // eg, "faces"
const fileName& instance, // eg, "constant"
const fileName& local, // eg, "polyMesh"
const Time& runTime,
const bool verbose = true
);
//- Check for availability of specified mesh file (default: "faces")
//- Check for availability of specified file (on all ranks)
boolList haveMeshFile
(
const word& name, // eg, "faces"
const fileName& instance, // eg, "constant"
const fileName& local, // eg, "polyMesh"
const Time& runTime,
const bool verbose = true
);
//- Check for availability of specified mesh file
boolList haveMeshFile
(
const Time& runTime,
const fileName& meshPath,
const word& meshFile = "faces",
const word& meshFile,
const bool verbose = true
);
@ -75,7 +92,7 @@ void masterMeshInstance
fileName& pointsInstance
);
}
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -21,44 +21,59 @@ Requires
// Initially all possible objects that are available at the final time
List<wordHashSet> availableRegionObjectNames(meshes.size());
List<wordHashSet> availableFaRegionObjectNames(meshes.size());
List<HashTable<wordHashSet>> availableFaRegionObjectNames(meshes.size());
forAll(meshes, regioni)
{
const auto& mesh = meshes[regioni];
IOobjectList objects;
IOobjectList faObjects;
HashTable<IOobjectList> faObjects;
if (doConvertFields && !timeDirs.empty())
{
// const word& checkTimeDir = timeDirs.back().name();
// List of volume mesh objects for this instance
objects = IOobjectList(mesh, timeDirs.back().name());
// List of area mesh objects (assuming single region)
faObjects = IOobjectList
(
mesh.time(),
timeDirs.back().name(),
faMesh::dbDir(mesh, word::null),
IOobjectOption::NO_REGISTER
);
if (fieldSelector)
{
objects.filterObjects(fieldSelector);
faObjects.filterObjects(fieldSelector);
}
// Remove "*_0" restart fields
objects.prune_0();
faObjects.prune_0();
if (!doPointValues)
{
// Prune point fields if disabled
objects.filterClasses(Foam::fieldTypes::is_point, true);
}
// The finite-area regions and their fields for this volume region
// and instance
faObjects.reserve(areaRegionNames.size());
for (const word& areaName : areaRegionNames)
{
IOobjectList objs
(
faMesh::Registry(mesh),
timeDirs.back().name(),
polyMesh::regionName(areaName),
IOobjectOption::NO_REGISTER
);
if (fieldSelector)
{
objs.filterObjects(fieldSelector);
}
// Remove "*_0" restart fields
objs.prune_0();
faObjects(areaName) = std::move(objs);
}
}
// Volume fields
@ -78,20 +93,29 @@ forAll(meshes, regioni)
}
// Area fields
if (!faObjects.empty())
for (const word& areaName : areaRegionNames)
{
wordList objectNames(faObjects.sortedNames());
wordList objectNames;
// Check availability for all times... (assuming single region)
checkData
if (const auto iter = faObjects.cfind(areaName); iter.good())
{
objectNames = iter.val().sortedNames();
// Check availability for all times...
checkData
(
faMesh::Registry(mesh),
timeDirs,
objectNames,
polyMesh::regionName(areaName)
);
}
availableFaRegionObjectNames[regioni].emplace_set
(
mesh.time(),
timeDirs,
objectNames,
faMesh::dbDir(mesh, word::null)
areaName,
std::move(objectNames)
);
availableFaRegionObjectNames[regioni] = objectNames;
}
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
Copyright (C) 2021-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -15,12 +15,14 @@ Description
\*---------------------------------------------------------------------------*/
// Cases and meshes per volume region
PtrList<ensightCase> ensightCases(regionNames.size());
PtrList<ensightMesh> ensightMeshes(regionNames.size());
PtrList<faMesh> meshesFa(regionNames.size());
PtrList<ensightCase> ensightCasesFa(regionNames.size());
PtrList<ensightFaMesh> ensightMeshesFa(regionNames.size());
// Per volume region can have multiple finite-area regions
List<PtrDynList<faMesh>> meshesFa(regionNames.size());
List<PtrDynList<ensightCase>> ensightCasesFa(regionNames.size());
List<PtrDynList<ensightFaMesh>> ensightMeshesFa(regionNames.size());
{
forAll(regionNames, regioni)
@ -45,6 +47,7 @@ PtrList<ensightFaMesh> ensightMeshesFa(regionNames.size());
}
}
// Volume mesh
ensightMeshes.set
(
regioni,
@ -59,33 +62,60 @@ PtrList<ensightFaMesh> ensightMeshesFa(regionNames.size());
new ensightCase(ensCasePath, ensCaseName, caseOpts)
);
if (doFiniteArea)
if (!doFiniteArea)
{
autoPtr<faMesh> faMeshPtr(faMesh::TryNew(mesh));
continue;
}
// Note: not every volume region is guaranteed to have
// any or all area region(s)
meshesFa[regioni].reserve_exact(areaRegionNames.size());
for (const word& areaName : areaRegionNames)
{
auto faMeshPtr = faMesh::TryNew(areaName, mesh);
if (faMeshPtr)
{
ensightCasesFa.set
(
regioni,
new ensightCase
(
ensCasePath/"finite-area",
"finite-area",
caseOpts
)
);
meshesFa.set(regioni, std::move(faMeshPtr));
ensightMeshesFa.set
(
regioni,
new ensightFaMesh(meshesFa[regioni])
);
ensightMeshesFa[regioni].verbose(optVerbose);
meshesFa[regioni].push_back(std::move(faMeshPtr));
}
}
// Setup the ensight components
const label nAreas = meshesFa[regioni].size();
ensightCasesFa[regioni].reserve_exact(nAreas);
ensightMeshesFa[regioni].reserve_exact(nAreas);
for (const faMesh& areaMesh : meshesFa[regioni])
{
// Use regionName() - automatically filters for defaultRegion
const word& areaName = areaMesh.regionName();
if (areaName.empty())
{
// single-region
ensightCasesFa[regioni].emplace_back
(
ensCasePath/"finite-area",
"finite-area",
caseOpts
);
}
else
{
// multi-region
ensightCasesFa[regioni].emplace_back
(
ensCasePath/"finite-area"/areaName,
areaName,
caseOpts
);
}
auto& ensFaMesh = ensightMeshesFa[regioni].emplace_back(areaMesh);
ensFaMesh.verbose(optVerbose);
}
}
}

View File

@ -124,6 +124,7 @@ Usage
#include "OFstream.H"
#include "Pstream.H"
#include "HashOps.H"
#include "PtrDynList.H"
#include "regionProperties.H"
#include "fvc.H"
@ -172,6 +173,7 @@ int main(int argc, char *argv[])
argList::addVerboseOption();
#include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
argList::addBoolOption
(
@ -323,6 +325,9 @@ int main(int argc, char *argv[])
);
argList::addOptionCompat("cellZones", {"cellZone", 1912});
// Prevent volume BCs from triggering finite-area
regionModels::allowFaModels(false);
#include "setRootCase.H"
// ------------------------------------------------------------------------
@ -436,6 +441,14 @@ int main(int argc, char *argv[])
// Handle -allRegions, -regions, -region
#include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
// ------------------------------------------------------------------------
// Directory management
@ -515,29 +528,32 @@ int main(int argc, char *argv[])
polyMesh::readUpdateState meshState = mesh.readUpdate();
const bool moving = (meshState != polyMesh::UNCHANGED);
// Ensight
// Ensight (fvMesh)
auto& ensCase = ensightCases[regioni];
auto& ensMesh = ensightMeshes[regioni];
// Finite-area (can be missing)
auto* ensFaCasePtr = ensightCasesFa.get(regioni);
auto* ensFaMeshPtr = ensightMeshesFa.get(regioni);
ensCase.setTime(timeDirs[timei], timeIndex);
if (ensFaCasePtr)
// Finite-area (optional)
// Accounting exists for each volume region but may be empty
auto& ensFaCases = ensightCasesFa[regioni];
auto& ensFaMeshes = ensightMeshesFa[regioni];
for (auto& ensFaCase : ensFaCases)
{
ensFaCasePtr->setTime(timeDirs[timei], timeIndex);
ensFaCase.setTime(timeDirs[timei], timeIndex);
}
// Movement
if (moving)
{
ensMesh.expire();
ensMesh.correct();
if (ensFaMeshPtr)
for (auto& ensFaMesh : ensFaMeshes)
{
ensFaMeshPtr->expire();
ensFaMeshPtr->correct();
ensFaMesh.expire();
ensFaMesh.correct();
}
}
@ -552,15 +568,19 @@ int main(int argc, char *argv[])
}
// finite-area
if (ensFaCasePtr && ensFaMeshPtr)
forAll(ensFaMeshes, areai)
{
autoPtr<ensightGeoFile> os =
ensFaCasePtr->newGeometry(hasMovingMesh);
const auto& ensFaCase = ensFaCases[areai];
const auto& ensFaMesh = ensFaMeshes[areai];
ensFaMeshPtr->write(os.ref());
autoPtr<ensightGeoFile> os =
ensFaCase.newGeometry(hasMovingMesh);
ensFaMesh.write(os.ref());
}
}
// Objects at this time
IOobjectList objects(mesh, runTime.timeName());
@ -572,23 +592,37 @@ int main(int argc, char *argv[])
// Volume, internal, point fields
#include "convertVolumeFields.H"
// The finite-area objects at this time
IOobjectList faObjects;
if (ensFaMeshPtr)
// finite-area
forAll(ensFaMeshes, areai)
{
faObjects =
IOobjectList(ensFaMeshPtr->mesh(), runTime.timeName());
auto* ensFaCasePtr = ensFaCases.get(areai);
auto* ensFaMeshPtr = ensFaMeshes.get(areai);
faObjects.filterObjects
(
availableFaRegionObjectNames[regioni]
);
// The finite-area region objects at this time
IOobjectList faObjects;
if (ensFaMeshPtr)
{
const word& areaName = ensFaMeshPtr->mesh().name();
faObjects = IOobjectList
(
faMesh::Registry(mesh),
runTime.timeName(),
polyMesh::regionName(areaName),
IOobjectOption::NO_REGISTER
);
faObjects.filterObjects
(
availableFaRegionObjectNames[regioni](areaName)
);
}
// The finiteArea fields
#include "convertAreaFields.H"
}
// The finiteArea fields
#include "convertAreaFields.H"
// Lagrangian fields
#include "convertLagrangian.H"
}
@ -601,14 +635,13 @@ int main(int argc, char *argv[])
// Write cases
forAll(ensightCases, regioni)
{
// finite-volume
ensightCases[regioni].write();
}
forAll(ensightCasesFa, regioni)
{
if (ensightCasesFa.set(regioni))
// Finite-area (if any)
for (const auto& ensFaCase : ensightCasesFa[regioni])
{
ensightCasesFa[regioni].write();
ensFaCase.write();
}
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2023 OpenCFD Ltd.
Copyright (C) 2018-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,7 +26,6 @@ License
\*---------------------------------------------------------------------------*/
#include "readFields.H"
#include "volFields.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
@ -42,26 +41,30 @@ Foam::label Foam::checkData
wordHashSet goodFields;
IOobject io
(
"any-name", // placeholder
"constant", // placeholder
local,
obr,
IOobjectOption::NO_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
);
for (const word& fieldName : objectNames)
{
// // If prune_0() not previously used...
// if (objectNames.ends_with("_0")) continue;
// In case prune_0() not previously used...
if (fieldName.ends_with("_0")) continue;
bool good = false;
for (const instant& inst : timeDirs)
{
good =
IOobject
(
fieldName,
inst.name(),
local,
obr,
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
).typeHeaderOk<volScalarField>(false, false);
io.resetHeader(fieldName);
io.instance() = inst.name();
good = io.typeHeaderOk<regIOobject>(false, false);
if (!good)
{

View File

@ -22,24 +22,66 @@ Description
//
// No subsetting!
if (doFiniteArea)
if (doFiniteArea && !areaRegionNames.empty())
{
using reportFields = foamToVtkReportFields;
autoPtr<faMesh> faMeshPtr;
// The (region) polyMesh being used. No subsetting possible
const auto& basePolyMesh = meshProxy.baseMesh();
const label nAreaFields = faObjects.count(Foam::fieldTypes::is_area);
if (nAreaFields || withMeshIds)
for (const word& areaName : areaRegionNames)
{
faMeshPtr = faMesh::TryNew(meshProxy.baseMesh());
}
const bool isDefaultRegion(polyMesh::regionName(areaName).empty());
if (faMeshPtr && (nAreaFields || withMeshIds))
{
const faMesh& areaMesh = faMeshPtr();
// CAUTION
// If we want to have constant access to the HashTable:
//
// (SEGFAULT)
// const auto& faObjs = faObjects.lookup(areaName, IOobjectList());
//
// Use an empty fallback to avoid binding to a temporary:
//
// const IOobjectList emptyObjectList;
// const auto& faObjs = faObjects.lookup(areaName, emptyObjectList);
reportFields::area(Info, faObjects);
// Since we do not need the area fields afterwards,
// just move them out from the HashTable
IOobjectList faObjs;
if (auto iter = faObjects.find(areaName); iter.good())
{
faObjs = std::move(iter.val());
}
const label nAreaFields = faObjs.count(Foam::fieldTypes::is_area);
autoPtr<faMesh> faMeshPtr;
if (nAreaFields || withMeshIds)
{
faMeshPtr = faMesh::TryNew(areaName, basePolyMesh);
}
if (!faMeshPtr)
{
if (!isDefaultRegion)
{
// Report any area region specified but missing
// - silently ignore region0
Info<< "No area-mesh [" << polyMesh::regionName(areaName)
<< "] on volume-region ["
<< basePolyMesh.regionName() << "]" << endl;
}
continue;
}
const auto& areaMesh = faMeshPtr();
Info<< "Using area-mesh [" << polyMesh::regionName(areaName)
<< "] on volume-region ["
<< basePolyMesh.regionName() << "]" << endl;
reportFields::area(Info, faObjs);
const auto& pp = faMeshPtr->patch();
@ -49,7 +91,12 @@ if (doFiniteArea)
writeOpts,
(
outputDir/regionDir/"finite-area"
/ "finiteArea" + timeDesc
/ (
isDefaultRegion
? fileName("finiteArea")
: fileName(areaName/areaName)
)
+ timeDesc
),
UPstream::parRun()
);
@ -96,7 +143,7 @@ if (doFiniteArea)
(
writer,
areaMesh,
faObjects,
faObjs,
true // syncPar
);

View File

@ -135,13 +135,13 @@ Note
#include "emptyPolyPatch.H"
#include "volPointInterpolation.H"
#include "faceZoneMesh.H"
#include "faMesh.H"
#include "areaFields.H"
#include "fvMeshSubsetProxy.H"
#include "faceSet.H"
#include "pointSet.H"
#include "HashOps.H"
#include "regionProperties.H"
#include "stringListOps.H" // For stringListOps::findMatching()
#include "Cloud.H"
#include "readFields.H"
@ -434,6 +434,7 @@ int main(int argc, char *argv[])
argList::addOptionCompat("one-boundary", {"allPatches", 1806});
#include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
argList::addOption
(
@ -479,8 +480,14 @@ int main(int argc, char *argv[])
"Directory name for VTK output (default: 'VTK')"
);
// Prevent volume BCs from triggering finite-area
regionModels::allowFaModels(false);
#include "setRootCase.H"
// ------------------------------------------------------------------------
// Configuration
/// const int optVerbose = args.verbose();
const bool decomposePoly = args.found("poly-decomp");
const bool doBoundary = !args.found("no-boundary");
@ -624,6 +631,16 @@ int main(int argc, char *argv[])
// Handle -allRegions, -regions, -region
#include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
// ------------------------------------------------------------------------
// Names for sets and zones
word cellSelectionName;
word faceSetName;
@ -771,8 +788,11 @@ int main(int argc, char *argv[])
}
}
// fvMesh fields
IOobjectList objects;
IOobjectList faObjects;
// faMesh fields (multiple finite-area regions per volume region)
HashTable<IOobjectList> faObjects;
if (doConvertFields)
{
@ -780,33 +800,51 @@ int main(int argc, char *argv[])
objects =
IOobjectList(meshProxy.baseMesh(), runTime.timeName());
// List of area mesh objects (assuming single region)
faObjects =
IOobjectList
(
runTime,
runTime.timeName(),
faMesh::dbDir(meshProxy.baseMesh(), word::null),
IOobjectOption::NO_REGISTER
);
if (fieldSelector)
{
objects.filterObjects(fieldSelector);
faObjects.filterObjects(fieldSelector);
}
// Remove "*_0" restart fields
objects.prune_0();
faObjects.prune_0();
if (!doPointValues)
{
// Prune point fields if disabled
objects.filterClasses(Foam::fieldTypes::is_point, true);
}
// Lists of finite-area fields
faObjects.reserve(areaRegionNames.size());
for (const word& areaName : areaRegionNames)
{
// The finite-area objects for given area region.
// Add as method to faMeshesRegistry?
IOobjectList objs
(
faMesh::Registry(meshProxy.baseMesh()),
runTime.timeName(),
polyMesh::regionName(areaName),
IOobjectOption::NO_REGISTER
);
if (fieldSelector)
{
objs.filterObjects(fieldSelector);
}
// Remove "*_0" restart fields
objs.prune_0();
if (!objs.empty())
{
faObjects.emplace_set(areaName, std::move(objs));
}
}
}
if (processorFieldsOnly)
{
// Processor-patches only and continue

View File

@ -1,10 +1,10 @@
EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/finiteArea/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude
-I$(LIB_SRC)/finiteArea/lnInclude
EXE_LIBS = \
-lmeshTools \
-lfiniteVolume \
-lfiniteArea \
-lmeshTools \
-lgenericPatchFields

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2022-2024 OpenCFD Ltd.
Copyright (C) 2022-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -47,6 +47,7 @@ Description
#include "areaFields.H"
#include "coupledFvPatch.H"
#include "coupledFaPatch.H"
#include "regionProperties.H"
using namespace Foam;
@ -86,17 +87,18 @@ bool consumeUnusedType(const fieldDescription& fieldDesc, Istream& is)
//? typedef GeometricField<Type, faePatchField, areaMesh> fieldType3;
//? typedef GeometricField<Type, fvsPatchField, volMesh> fieldType4;
if
const bool isExpectedType
(
fieldDesc.type() == fieldType1::typeName
|| fieldDesc.type() == fieldType2::typeName
)
);
if (isExpectedType)
{
(void) pTraits<Type>(is);
return true;
}
return false;
return isExpectedType;
}
@ -122,13 +124,18 @@ bool setCellFieldType
(
const fieldDescription& fieldDesc,
const fvMesh& mesh,
const labelList& selectedCells,
const labelUList& selectedCells,
Istream& is
)
{
typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
if (fieldDesc.type() != fieldType::typeName)
const bool isExpectedType
(
fieldDesc.type() == fieldType::typeName
);
if (!isExpectedType)
{
return false;
}
@ -143,7 +150,9 @@ bool setCellFieldType
fieldDesc.name(),
mesh.thisDb().time().timeName(),
mesh.thisDb(),
IOobject::MUST_READ
IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
);
bool found = fieldHeader.typeHeaderOk<fieldType>(true);
@ -151,13 +160,8 @@ bool setCellFieldType
if (!found)
{
// Fallback to "constant" directory
fieldHeader = IOobject
(
fieldDesc.name(),
mesh.thisDb().time().constant(),
mesh.thisDb(),
IOobject::MUST_READ
);
fieldHeader.resetHeader();
fieldHeader.instance() = mesh.thisDb().time().constant();
found = fieldHeader.typeHeaderOk<fieldType>(true);
}
@ -171,7 +175,7 @@ bool setCellFieldType
fieldType field(fieldHeader, mesh, false);
if (isNull(selectedCells) || selectedCells.size() == field.size())
if (isNull(selectedCells) || (selectedCells.size() == field.size()))
{
field.primitiveFieldRef() = fieldValue;
}
@ -204,7 +208,7 @@ bool setCellFieldType
<< "Field " << fieldDesc.name() << " not found" << endl;
}
return true;
return isExpectedType;
}
@ -216,13 +220,18 @@ bool setAreaFieldType
(
const fieldDescription& fieldDesc,
const faMesh& mesh,
const labelList& selectedFaces,
const labelUList& selectedFaces,
Istream& is
)
{
typedef GeometricField<Type, faPatchField, areaMesh> fieldType;
if (fieldDesc.type() != fieldType::typeName)
const bool isExpectedType
(
fieldDesc.type() == fieldType::typeName
);
if (!isExpectedType)
{
return false;
}
@ -237,7 +246,9 @@ bool setAreaFieldType
fieldDesc.name(),
mesh.thisDb().time().timeName(),
mesh.thisDb(),
IOobject::MUST_READ
IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
);
bool found = fieldHeader.typeHeaderOk<fieldType>(true);
@ -245,13 +256,8 @@ bool setAreaFieldType
if (!found)
{
// Fallback to "constant" directory
fieldHeader = IOobject
(
fieldDesc.name(),
mesh.thisDb().time().constant(),
mesh.thisDb(),
IOobject::MUST_READ
);
fieldHeader.resetHeader();
fieldHeader.instance() = mesh.thisDb().time().constant(),
found = fieldHeader.typeHeaderOk<fieldType>(true);
}
@ -292,7 +298,7 @@ bool setAreaFieldType
<< "Field " << fieldDesc.name() << " not found" << endl;
}
return true;
return isExpectedType;
}
@ -304,13 +310,18 @@ bool setFaceFieldType
(
const fieldDescription& fieldDesc,
const fvMesh& mesh,
const labelList& selectedFaces,
const labelUList& selectedFaces,
Istream& is
)
{
typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
if (fieldDesc.type() != fieldType::typeName)
const bool isExpectedType
(
fieldDesc.type() == fieldType::typeName
);
if (!isExpectedType)
{
return false;
}
@ -325,7 +336,9 @@ bool setFaceFieldType
fieldDesc.name(),
mesh.thisDb().time().timeName(),
mesh.thisDb(),
IOobject::MUST_READ
IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
);
bool found = fieldHeader.typeHeaderOk<fieldType>(true);
@ -333,13 +346,8 @@ bool setFaceFieldType
if (!found)
{
// Fallback to "constant" directory
fieldHeader = IOobject
(
fieldDesc.name(),
mesh.thisDb().time().constant(),
mesh.thisDb(),
IOobject::MUST_READ
);
fieldHeader.resetHeader();
fieldHeader.instance() = mesh.thisDb().time().constant();
found = fieldHeader.typeHeaderOk<fieldType>(true);
}
@ -355,15 +363,14 @@ bool setFaceFieldType
// Create flat list of selected faces and their value.
Field<Type> allBoundaryValues(mesh.nBoundaryFaces());
forAll(field.boundaryField(), patchi)
for (const auto& pfld : field.boundaryField())
{
SubField<Type>
(
allBoundaryValues,
field.boundaryField()[patchi].size(),
field.boundaryField()[patchi].patch().start()
- mesh.nInternalFaces()
) = field.boundaryField()[patchi];
pfld.size(),
pfld.patch().offset()
) = pfld;
}
// Override
@ -424,8 +431,7 @@ bool setFaceFieldType
(
allBoundaryValues,
fieldBf[patchi].size(),
fieldBf[patchi].patch().start()
- mesh.nInternalFaces()
fieldBf[patchi].patch().offset()
);
}
}
@ -445,7 +451,7 @@ bool setFaceFieldType
<< "Field " << fieldDesc.name() << " not found" << endl;
}
return true;
return isExpectedType;
}
@ -460,7 +466,7 @@ struct setCellField
(
const fieldDescription& fieldDesc,
const fvMesh& m,
const labelList& selectedCells,
const labelUList& selectedCells,
Istream& is
)
{
@ -477,11 +483,11 @@ struct setCellField
class iNew
{
const fvMesh& mesh_;
const labelList& selected_;
const labelUList& selected_;
public:
iNew(const fvMesh& mesh, const labelList& selectedCells)
iNew(const fvMesh& mesh, const labelUList& selectedCells) noexcept
:
mesh_(mesh),
selected_(selectedCells)
@ -528,7 +534,7 @@ struct setFaceField
(
const fieldDescription& fieldDesc,
const fvMesh& m,
const labelList& selectedFaces,
const labelUList& selectedFaces,
Istream& is
)
{
@ -545,11 +551,11 @@ struct setFaceField
class iNew
{
const fvMesh& mesh_;
const labelList& selected_;
const labelUList& selected_;
public:
iNew(const fvMesh& mesh, const labelList& selectedFaces)
iNew(const fvMesh& mesh, const labelUList& selectedFaces) noexcept
:
mesh_(mesh),
selected_(selectedFaces)
@ -596,7 +602,7 @@ struct setAreaField
(
const fieldDescription& fieldDesc,
const faMesh& m,
const labelList& selectedFaces,
const labelUList& selectedFaces,
Istream& is
)
{
@ -613,11 +619,11 @@ struct setAreaField
class iNew
{
const faMesh& mesh_;
const labelList& selected_;
const labelUList& selected_;
public:
iNew(const faMesh& mesh, const labelList& selectedFaces)
iNew(const faMesh& mesh, const labelUList& selectedFaces) noexcept
:
mesh_(mesh),
selected_(selectedFaces)
@ -675,6 +681,7 @@ int main(int argc, char *argv[])
);
#include "addRegionOption.H"
#include "addAllFaRegionOptions.H"
// -------------------------
@ -686,15 +693,59 @@ int main(int argc, char *argv[])
#include "createNamedMesh.H"
autoPtr<faMesh> faMeshPtr;
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!args.found("no-finite-area"))
if (args.found("no-finite-area"))
{
faMeshPtr = faMesh::TryNew(mesh);
areaRegionNames.clear(); // For consistency
}
if (faMeshPtr)
// ------------------------------------------------------------------------
PtrList<faMesh> faMeshes;
// Setup all area meshes on this region
if (!areaRegionNames.empty()) // ie, !args.found("no-finite-area")
{
Info<< "Detected finite-area mesh" << nl;
faMeshes.resize(areaRegionNames.size());
label nGoodRegions(0);
for (const word& areaName : areaRegionNames)
{
autoPtr<faMesh> faMeshPtr = faMesh::TryNew(areaName, mesh);
if (faMeshPtr)
{
faMeshes.set(nGoodRegions++, std::move(faMeshPtr));
}
}
faMeshes.resize(nGoodRegions);
}
if (faMeshes.size() == 1)
{
Info<< "Using finite-area mesh";
if
(
const word& name = polyMesh::regionName(faMeshes[0].name());
!name.empty()
)
{
Info<< " [" << name << "]";
}
Info<< nl;
}
else if (faMeshes.size() > 1)
{
Info<< "Detected finite-area meshes:";
for (const faMesh& areaMesh : faMeshes)
{
Info<< " [" << areaMesh.name() << "]";
}
Info<< nl;
}
const word dictName("setFieldsDict");
@ -712,37 +763,45 @@ int main(int argc, char *argv[])
// Default field values
if
(
const auto* eptr
= setFieldsDict.findEntry("defaultFieldValues", keyType::LITERAL)
)
{
const entry* eptr =
setFieldsDict.findEntry("defaultFieldValues", keyType::LITERAL);
ITstream& is = eptr->stream();
if (eptr)
Info<< "Setting volume field default values" << endl;
PtrList<setCellField> defaultFieldValues
(
is,
setCellField::iNew(mesh, labelList::null())
);
for (const faMesh& areaMesh : faMeshes)
{
ITstream& is = eptr->stream();
Info<< "Setting area field default values";
Info<< "Setting volume field default values" << endl;
PtrList<setCellField> defaultFieldValues
if
(
is,
setCellField::iNew(mesh, labelList::null())
);
if (faMeshPtr)
const word& name = polyMesh::regionName(areaMesh.name());
!name.empty()
)
{
const faMesh& areaMesh = faMeshPtr();
is.rewind();
Info<< "Setting area field default values" << endl;
PtrList<setAreaField> defaultFieldValues
(
is,
setAreaField::iNew(areaMesh, labelList::null())
);
Info<< " [" << name << "]";
}
Info<< endl;
is.rewind();
PtrList<setAreaField> defaultAreaFieldValues
(
is,
setAreaField::iNew(areaMesh, labelList::null())
);
}
Info<< endl;
}
@ -768,11 +827,15 @@ int main(int argc, char *argv[])
labelList selectedCells(subset.sortedToc());
Info<< " Selected "
<< returnReduce(selectedCells.size(), sumOp<label>())
<< '/'
<< returnReduce(mesh.nCells(), sumOp<label>())
<< " cells" << nl;
{
FixedList<label, 2> stats;
stats[0] = selectedCells.size();
stats[1] = mesh.nCells();
reduce(stats, sumOp<label>());
Info<< " Selected " << stats[0] << '/' << stats[1]
<< " cells" << nl;
}
ITstream& is = region.dict().lookup("fieldValues");
@ -806,10 +869,8 @@ int main(int argc, char *argv[])
setFaceField::iNew(mesh, selectedFaces)
);
if (faMeshPtr)
for (const faMesh& areaMesh : faMeshes)
{
const faMesh& areaMesh = faMeshPtr();
const labelUList& faceLabels = areaMesh.faceLabels();
// Transcribe from mesh faces to finite-area addressing
@ -828,11 +889,15 @@ int main(int argc, char *argv[])
}
areaFaces.resize(nUsed);
Info<< " Selected "
<< returnReduce(areaFaces.size(), sumOp<label>())
<< '/'
<< returnReduce(faceLabels.size(), sumOp<label>())
<< " area faces" << nl;
{
FixedList<label, 2> stats;
stats[0] = areaFaces.size();
stats[1] = faceLabels.size();
reduce(stats, sumOp<label>());
Info<< " Selected " << stats[0] << '/' << stats[1]
<< " area faces for " << areaMesh.name() << endl;
}
is.rewind();

138
bin/foamCleanFaMesh Executable file
View File

@ -0,0 +1,138 @@
#!/bin/sh
#------------------------------------------------------------------------------
# ========= |
# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
# \\ / O peration |
# \\ / A nd | www.openfoam.com
# \\/ M anipulation |
#-------------------------------------------------------------------------------
# Copyright (C) 2011 OpenFOAM Foundation
# Copyright (C) 2025 OpenCFD Ltd.
#------------------------------------------------------------------------------
# License
# This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
#
# Script
# foamCleanFaMesh
#
# Description
# Remove the contents of the constant/finite-area/faMesh directory
# as per the Foam::faMesh::removeFiles() method.
#
#------------------------------------------------------------------------------
usage() {
exec 1>&2
while [ "$#" -ge 1 ]; do echo "$1"; shift; done
cat <<USAGE
Usage: ${0##*/} [OPTION]
options:
-case <dir> case directory, default is the cwd
-area-region <name> area-mesh region
-dry-run | -n report actions but do not remove
-help print the usage
Remove the contents of the constant/finite-area/faMesh directory as per the
Foam::faMesh::removeFiles() method.
USAGE
exit 1
}
#------------------------------------------------------------------------------
# Parse options
unset caseDir areaRegion optDryRun
while [ "$#" -gt 0 ]
do
case "$1" in
-h | -help*)
usage
;;
-dry-run | -n)
optDryRun="(dry-run) "
;;
-case=*)
caseDir="${1#*=}"
;;
-case)
[ "$#" -ge 2 ] || usage "'$1' option requires an argument"
cd "$2" 2>/dev/null || usage "directory does not exist: '$2'"
caseDir=$2
shift
;;
-area-region)
[ "$#" -ge 2 ] || usage "'$1' option requires an argument"
areaRegion=$2
shift
;;
(*)
usage "unknown option/argument: '$*'"
;;
esac
shift
done
#------------------------------------------------------------------------------
# Remove files (mesh etc)
# also remove .gz versions of the same files
removeFiles()
{
local directory="$1"
for i in \
faceLabels \
faBoundary \
;
do
if [ -n "$optDryRun" ]
then
echo "${optDryRun} rm -rf $directory/{$i,$i.gz}"
else
rm -rf -- "$directory/$i" "$directory/$i.gz"
fi
done
}
#------------------------------------------------------------------------------
meshDir="constant/finite-area/${areaRegion}${areaRegion:+/}faMesh"
if [ -d "$meshDir" ]
then
# [OK] has constant/finite-areaRegion/<region>/faMesh
:
elif [ -n "$caseDir" ]
then
# Specified -case, so no extra magic...
echo "Error: no <$meshDir> in $caseDir" 1>&2
exit 1
else
# Try some other combinations
other="${meshDir#constant/}"
if [ -d "$other" ]
then
# Probably already within constant/
meshDir="$other}"
elif [ "${PWD##*/}" = faMesh ] && [ -z "$areaRegion" ]
then
# Apparently already within faMesh/
meshDir=.
fi
fi
echo "Cleaning ${caseDir:-.}/$meshDir" 1>&2
removeFiles "$meshDir"
#------------------------------------------------------------------------------

View File

@ -7,7 +7,7 @@
# \\/ M anipulation |
#-------------------------------------------------------------------------------
# Copyright (C) 2011-2016 OpenFOAM Foundation
# Copyright (C) 2022 OpenCFD Ltd.
# Copyright (C) 2022,2025 OpenCFD Ltd.
#------------------------------------------------------------------------------
# License
# This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -27,9 +27,10 @@ usage() {
Usage: ${0##*/} [OPTION]
options:
-case <dir> specify alternative case directory, default is the cwd
-region <name> specify alternative mesh region
-help print the usage
-case <dir> case directory, default is the cwd
-region <name> mesh region
-dry-run | -n report actions but do not remove
-help print the usage
Remove the contents of the constant/polyMesh directory as per the
Foam::polyMesh::removeFiles() method.
@ -38,58 +39,101 @@ USAGE
exit 1
}
unset caseDir regionName
#------------------------------------------------------------------------------
# Parse options
unset caseDir regionName optDryRun
# Parse a single option
while [ "$#" -gt 0 ]
do
case "$1" in
-h | -help*)
usage
;;
-dry-run | -n)
optDryRun="(dry-run) "
;;
-case=*)
caseDir="${1#*=}"
;;
-case)
caseDir="$2"
[ "$#" -ge 2 ] || usage "'$1' option requires an argument"
cd "$2" 2>/dev/null || usage "directory does not exist: '$2'"
caseDir=$2
shift 2
shift
;;
-region)
[ "$#" -ge 2 ] || usage "'$1' option requires an argument"
regionName=$2
shift 2
regionName="$2"
shift
;;
*)
(*)
usage "unknown option/argument: '$*'"
;;
esac
shift
done
meshDir=polyMesh
if [ -n "$regionName" ]
then
meshDir="$regionName/$meshDir"
fi
#------------------------------------------------------------------------------
# If -case was specified: insist upon 'constant/polyMesh'
if [ -n "$caseDir" ]
# Remove files (mesh itself, modifiers, snappyHexMesh ones) and subdirectories
# also remove .gz versions of the same files
removeFiles()
{
local directory="$1"
for i in \
points faces \
owner neighbour \
boundary \
cells \
cellZones faceZones pointZones \
meshModifiers \
parallelData \
sets \
cellLevel pointLevel \
level0Edge \
refinementHistory \
surfaceIndex \
;
do
if [ -n "$optDryRun" ]
then
echo "${optDryRun} rm -rf $directory/{$i,$i.gz}"
else
rm -rf -- "$directory/$i" "$directory/$i.gz"
fi
done
}
#------------------------------------------------------------------------------
meshDir="constant/${regionName}${regionName:+/}polyMesh"
if [ -d "$meshDir" ]
then
if [ -d constant/"$meshDir" ]
then
# Use constant/polyMesh
meshDir=constant/"$meshDir"
else
echo "Error: no 'constant/$meshDir' in $caseDir" 1>&2
exit 1
fi
# [OK] has constant/<region>/polyMesh
:
elif [ -n "$caseDir" ]
then
# Specified -case, so no extra magic...
echo "Error: no <$meshDir> in $caseDir" 1>&2
exit 1
else
if [ -d constant/"$meshDir" ]
# Try some other combinations
other="${meshDir#constant/}"
if [ -d "$other" ]
then
# Use constant/polyMesh
meshDir=constant/"$meshDir"
elif [ -d "$meshDir" ]
then
# Likely already in constant/ - do not adjust anything
:
# Probably already within constant/
meshDir="$other}"
elif [ "${PWD##*/}" = polyMesh ] && [ -z "$regionName" ]
then
# Apparently already within polyMesh/
@ -98,31 +142,8 @@ else
fi
# Remove files (mesh itself, modifiers, snappyHexMesh ones) and subdirectories
# also remove .gz versions of the same files
echo "Cleaning ${caseDir:-.}/$meshDir" 1>&2
for i in \
points \
faces \
owner \
neighbour \
cells \
boundary \
pointZones \
faceZones \
cellZones \
meshModifiers \
parallelData \
sets \
cellLevel \
pointLevel \
level0Edge \
refinementHistory \
surfaceIndex \
;
do
rm -rf "$meshDir/$i" "$meshDir/$i.gz"
done
removeFiles "$meshDir"
#------------------------------------------------------------------------------

View File

@ -108,54 +108,116 @@ cleanPostProcessing()
}
# ---------------
# Remove constant/finite-area/faMesh or constant/finite-area/{region}/faMesh
#
# Accepts following options:
# -region <name> The region name
# -- End of options
# ---------------
cleanFaMesh()
{
if [ -e constant/finite-area/faMesh ]
local region
# Parse options
while [ "$#" -gt 0 ]
do
case "$1" in
('') ;; # Ignore empty option
(--) shift; break ;; # Stop option parsing
(-region) region="$2"; shift ;;
(*) break ;;
esac
shift
done
# safety
if [ "$region" = "--" ]; then unset region; fi
local meshDir="constant/finite-area/${region}${region:+/}faMesh"
if [ -e "$meshDir" ]
then
rm -rf constant/finite-area/faMesh
[ -n "$region" ] && echo "Clearing $meshDir" 1>&2
rm -rf -- "$meshDir"
fi
if [ -e constant/faMesh ]
# Legacy location <constant/faMesh>
# - may still have remnant <constant/faMesh/faMeshDefinition>
meshDir="constant/faMesh"
if [ -e "$meshDir" ] && [ -z "$region" ]
then
if [ -e constant/faMesh/faMeshDefinition ]
if [ -e "$meshDir"/faMeshDefinition ]
then
# Old constant/faMesh location for faMeshDefinition still in use:
# - warn but don't remove anything
# VERY OLD LOCATION
echo
echo "Warning: not removing constant/faMesh/"
echo "WARNING: not removing $meshDir/"
echo " It contains a 'faMeshDefinition' file"
echo " Please relocate file(s) to system/ !!"
echo " Please relocate file(s) to system/finite-area/ !!"
echo
else
# Can remove constant/faMesh/ entirely (no faMeshDefinition)
rm -rf constant/faMesh
echo "Clearing $meshDir" 1>&2
rm -rf -- "$meshDir"
fi
fi
}
# ---------------
# Remove constant/polyMesh or constant/<region>/polyMesh
#
# Accepts following options:
# -region <name> The region name
# -- End of options
# ---------------
cleanPolyMesh()
{
if [ -e constant/polyMesh ]
local region
# Parse options
while [ "$#" -gt 0 ]
do
case "$1" in
('') ;; # Ignore empty option
(--) shift; break ;; # Stop option parsing
(-region) region="$2"; shift ;;
(*) break ;;
esac
shift
done
# safety
if [ "$region" = "--" ]; then unset region; fi
local meshDir="constant/${region}${region:+/}polyMesh"
if [ -e "$meshDir" ]
then
if [ -e constant/polyMesh/blockMeshDict ] \
|| [ -e constant/polyMesh/blockMeshDict.m4 ]
[ -n "$region" ] && echo "Clearing $meshDir" 1>&2
if [ -e "$meshDir"/blockMeshDict ] \
|| [ -e "$meshDir"/blockMeshDict.m4 ]
then
# Old constant/polyMesh location for blockMeshDict still in use:
# - warn but don't remove anything
# VERY OLD LOCATION
echo
echo "Warning: not removing constant/polyMesh/"
echo "WARNING: not removing $meshDir/"
echo " It contains a 'blockMeshDict' or 'blockMeshDict.m4' file"
echo " Please relocate file(s) to system/ !!"
echo
else
# Can remove constant/polyMesh/ entirely (no blockMeshDict)
rm -rf constant/polyMesh
rm -rf -- "$meshDir"
fi
fi
if [ -e system/blockMeshDict.m4 ]
meshDir="system${region:+/}${region}"
if [ -e "$meshDir"/blockMeshDict.m4 ]
then
rm -f system/blockMeshDict
rm -f -- "$meshDir"/blockMeshDict
fi
}
@ -212,7 +274,7 @@ cleanCase0()
removeCase()
{
echo "Removing case ${1:-unknown}"
[ "$#" -ge 1 ] && rm -rf "$1"
[ "$#" -ge 1 ] && rm -rf -- "$1"
}

View File

@ -517,9 +517,11 @@ cloneParallelCase()
}
# ---------------
# If 0.orig/ exists, copy (overwrite) into 0/ [ie, serial case]
# * -processor : copy into processor directories instead
# * -all : copy into serial and processor directories
# ---------------
restore0Dir()
{
if [ ! -d 0.orig ]
@ -553,4 +555,61 @@ restore0Dir()
}
# ---------------
# Helper routine to remove specified fields from the 0/ directory.
# Often used in combination with foamListRegions.
#
# Accepts following options:
# -region <name> The region name
# -- End of options
#
# any remaining parameters are taken to be fields names
# ---------------
remove0DirFields()
{
local region
# Parse options
while [ "$#" -gt 0 ]
do
case "$1" in
('') ;; # Ignore empty option
(--) shift; break ;; # Stop option parsing
(-region) region="$2"; shift ;;
(*) break ;;
esac
shift
done
# safety
if [ "$region" = "--" ]; then unset region; fi
if [ "$#" -eq 0 ]
then
echo "No fields specified for ${region:+region=$region }" 1>&2
return 0
fi
echo "Remove 0/ fields${region:+ [$region]} : $@" 1>&2
local subdir
for subdir in 0/"$region" processor*/0/"$region"
do
if [ -d "$subdir" ]
then
for field in $@ ## unquoted for IFS splitting [SIC]
do
# Cautious with removal
if [ -f "$subdir/$field" ]
then
rm -f -- "$subdir/$field"
fi
done
fi
done
return 0
}
#------------------------------------------------------------------------------

View File

@ -140,6 +140,11 @@ _of_complete_()
# Could use "foamListTimes -withZero", but still doesn't address ranges
COMPREPLY=($(compgen -d -X '![-0-9]*' -- ${cur}))
;;
-area-region)
# Or: $(find system/finite-area -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed -e 's%.*/%%')
choices=$(\ls -d system/finite-area/*/ 2>/dev/null | sed -e 's%/$%%; s%^.*/%%')
COMPREPLY=($(compgen -W "$choices" -- ${cur}))
;;
-region)
# Or: $(find system -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed -e 's%.*/%%')
choices=$(\ls -d system/*/ 2>/dev/null | sed -e 's%/$%%; s%^.*/%%')

View File

@ -341,22 +341,6 @@ inline Ostream& operator<<(Ostream& os, std::string_view s)
return os;
}
//- Write operator for character span. Output like string data
inline Ostream& operator<<(Ostream& os, stdFoam::span<char> s)
{
os.writeQuoted(s.data(), s.size(), true); // quoted
os.check("Foam::operator<<(Ostream&, stdFoam::span<char>)");
return os;
}
//- Write operator for const character span. Output like string data
inline Ostream& operator<<(Ostream& os, stdFoam::span<const char> s)
{
os.writeQuoted(s.data(), s.size(), true); // quoted
os.check("Foam::operator<<(Ostream&, stdFoam::span<const char>)");
return os;
}
/*---------------------------------------------------------------------------*\
Manipulators (without arguments)

View File

@ -343,11 +343,22 @@ void Foam::UPstream::mpiGatherv
}
// Nothing further to do
}
else if constexpr (UPstream_basic_dataType<Type>::value)
else if constexpr (UPstream_dataType<Type>::value)
{
// Restrict to basic (or aliased) MPI types to avoid recalculating
// the list of counts/offsets.
// The sizing factor (constexpr) must be 1 otherwise
// [recvCounts,recvOffsets] are likely incorrect
constexpr std::streamsize count = UPstream_dataType<Type>::size(1);
static_assert
(
(count == 1),
"Code does not (yet) work with aggregate types"
);
UPstream::mpi_gatherv
(
sendData,
@ -356,7 +367,7 @@ void Foam::UPstream::mpiGatherv
recvCounts,
recvOffsets,
UPstream_basic_dataType<Type>::datatype_id,
UPstream_dataType<Type>::datatype_id,
communicator
);
}
@ -364,7 +375,8 @@ void Foam::UPstream::mpiGatherv
{
static_assert
(
stdFoam::dependent_false_v<Type>, "Only basic MPI data types"
stdFoam::dependent_false_v<Type>,
"Only basic and user data types"
);
}
}
@ -392,11 +404,22 @@ void Foam::UPstream::mpiScatterv
}
// Nothing further to do
}
else if constexpr (UPstream_basic_dataType<Type>::value)
else if constexpr (UPstream_dataType<Type>::value)
{
// Restrict to basic (or aliased) MPI types to avoid recalculating
// the list of counts/offsets.
// The sizing factor (constexpr) must be 1 otherwise
// [sendCounts,sendOffsets] are likely incorrect
constexpr std::streamsize count = UPstream_dataType<Type>::size(1);
static_assert
(
(count == 1),
"Code does not (yet) work with aggregate types"
);
UPstream::mpi_scatterv
(
sendData,
@ -405,7 +428,7 @@ void Foam::UPstream::mpiScatterv
recvData,
recvCount,
UPstream_basic_dataType<Type>::datatype_id,
UPstream_dataType<Type>::datatype_id,
communicator
);
}
@ -413,7 +436,8 @@ void Foam::UPstream::mpiScatterv
{
static_assert
(
stdFoam::dependent_false_v<Type>, "Only basic MPI data types"
stdFoam::dependent_false_v<Type>,
"Only basic and user data types"
);
}
}

View File

@ -354,7 +354,7 @@ struct UPstream_basic_dataType
UPstream_alias_dataType<base>::datatype_id;
//- The size in terms of the number of underlying data elements
static std::streamsize size(std::streamsize n) noexcept
static constexpr std::streamsize size(std::streamsize n) noexcept
{
if constexpr (UPstream_alias_dataType<T>::value)
{
@ -373,7 +373,10 @@ struct UPstream_basic_dataType
template<> struct UPstream_basic_dataType<void> : UPstream_mpi_dataType<void>
{
using base = void;
static std::streamsize size(std::streamsize n) noexcept { return n; }
static constexpr std::streamsize size(std::streamsize n) noexcept
{
return n;
}
};
@ -410,7 +413,7 @@ struct UPstream_dataType
UPstream_any_dataType<base>::datatype_id;
//- The size in terms of the number of base data elements
static std::streamsize size(std::streamsize n) noexcept
static constexpr std::streamsize size(std::streamsize n) noexcept
{
if constexpr (UPstream_any_dataType<T>::value)
{

View File

@ -95,10 +95,12 @@ Foam::tokenList Foam::ITstream::parse_chars
IOstreamOption streamOpt
)
{
ISpanStream is(s, nbytes, streamOpt);
tokenList tokens;
parseStream(is, tokens);
if (s && nbytes > 0) // extra safety
{
ISpanStream is(s, nbytes, streamOpt);
parseStream(is, tokens);
}
return tokens;
}
@ -107,10 +109,19 @@ Foam::tokenList Foam::ITstream::parse_chars
void Foam::ITstream::reset(const char* input, size_t nbytes)
{
ISpanStream is(input, nbytes, static_cast<IOstreamOption>(*this));
tokenList tokens;
if (input && nbytes > 0) // extra safety
{
ISpanStream is(input, nbytes, static_cast<IOstreamOption>(*this));
parseStream(is, static_cast<tokenList&>(*this));
ITstream::seek(0); // rewind() bypassing virtual
parseStream(is, static_cast<tokenList&>(*this));
ITstream::seek(0); // rewind() bypassing virtual
}
else
{
ITstream::seek(0); // rewind() bypassing virtual
tokenList::clear();
}
}
@ -248,7 +259,10 @@ Foam::ITstream::ITstream
:
ITstream(streamOpt, name)
{
reset(input, strlen(input));
if (input)
{
reset(input, strlen(input));
}
}

View File

@ -77,7 +77,8 @@ class ITstream
// but leave any excess capacity (ie, like reserve).
void reserveCapacity(const label newCapacity);
//- Convert input sequence into a list of tokens,
//- Convert input sequence into a list of tokens.
// Includes nullptr guard
static tokenList parse_chars
(
const char* s,
@ -87,6 +88,7 @@ class ITstream
//- Convert input sequence into a list of tokens,
//- using the existing stream format. Rewinds the stream
// Includes nullptr guard
void reset(const char* input, size_t nbytes);
//- Failsafe read-access to token at specified location
@ -175,32 +177,6 @@ public:
reset(s.data(), s.size());
}
//- Construct token list by parsing the input character sequence
// Uses static parse function internally.
explicit ITstream
(
stdFoam::span<char> s,
IOstreamOption streamOpt = IOstreamOption()
)
:
ITstream(streamOpt)
{
reset(s.data(), s.size());
}
//- Construct token list by parsing the input character sequence
// Uses static parse function internally.
explicit ITstream
(
stdFoam::span<const char> s,
IOstreamOption streamOpt = IOstreamOption()
)
:
ITstream(streamOpt)
{
reset(s.data(), s.size());
}
// Additional constructors
@ -255,17 +231,6 @@ public:
return parse_chars(input.cdata(), input.size(), streamOpt);
}
//- Create token list by parsing the input string
//- until no good tokens remain.
static tokenList parse
(
const std::string& input,
IOstreamOption streamOpt = IOstreamOption()
)
{
return parse_chars(input.data(), input.size(), streamOpt);
}
//- Create token list by parsing the input character sequence
//- until no good tokens remain.
static tokenList parse
@ -274,7 +239,14 @@ public:
IOstreamOption streamOpt = IOstreamOption()
)
{
return parse_chars(input, strlen(input), streamOpt);
if (input)
{
return parse_chars(input, strlen(input), streamOpt);
}
else
{
return tokenList();
}
}
//- Create token list by parsing the input character sequence
@ -288,28 +260,6 @@ public:
return parse_chars(s.data(), s.size(), streamOpt);
}
//- Create token list by parsing the input character sequence
//- until no good tokens remain.
static tokenList parse
(
stdFoam::span<char> s,
IOstreamOption streamOpt = IOstreamOption()
)
{
return parse_chars(s.data(), s.size(), streamOpt);
}
//- Create token list by parsing the input character sequence
//- until no good tokens remain.
static tokenList parse
(
stdFoam::span<const char> s,
IOstreamOption streamOpt = IOstreamOption()
)
{
return parse_chars(s.data(), s.size(), streamOpt);
}
// Member Functions
@ -387,7 +337,7 @@ public:
label& tokenIndex() noexcept { return tokenIndex_; }
//- Set the token index (no checks). \return the previous value
label tokenIndex(const label num) noexcept
label tokenIndex(label num) noexcept
{
label old(tokenIndex_);
tokenIndex_ = num;

View File

@ -123,20 +123,6 @@ public:
stream_type(static_cast<buffer_type*>(this))
{}
//- Construct (shallow copy) from span character content
explicit ispanstream(stdFoam::span<char> s)
:
buffer_type(const_cast<char*>(s.data()), s.size()),
stream_type(static_cast<buffer_type*>(this))
{}
//- Construct (shallow copy) from span character content
explicit ispanstream(stdFoam::span<const char> s)
:
buffer_type(const_cast<char*>(s.data()), s.size()),
stream_type(static_cast<buffer_type*>(this))
{}
// Member Functions
@ -325,26 +311,6 @@ public:
ISpanStream(buffer.cdata(), buffer.size(), streamOpt)
{}
//- Construct (shallow copy) from span character content
explicit ISpanStream
(
stdFoam::span<const char> s,
IOstreamOption streamOpt = IOstreamOption()
)
:
ISpanStream(s.data(), s.size(), streamOpt)
{}
//- Construct (shallow copy) from span character content
explicit ISpanStream
(
stdFoam::span<char> s,
IOstreamOption streamOpt = IOstreamOption()
)
:
ISpanStream(s.data(), s.size(), streamOpt)
{}
// Member Functions
@ -402,20 +368,6 @@ public:
syncState();
}
//- Reset input area to use data from span character content
void reset(stdFoam::span<char> s)
{
stream_.reset(s.data(), s.size());
syncState();
}
//- Reset input area to use data from span character content
void reset(stdFoam::span<const char> s)
{
stream_.reset(s.data(), s.size());
syncState();
}
//- Rewind the stream, clearing any old errors
virtual void rewind() override
{

View File

@ -38,6 +38,7 @@ Description
#include "DynamicList.H"
#include <memory>
#include <string_view>
#include <string>
#include <type_traits>

View File

@ -113,6 +113,7 @@ SeeAlso
#include "label.H"
#include "scalar.H"
#include "regExpFwd.H"
#include "Switch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -55,6 +55,8 @@ SourceFiles
#include "label.H"
#include "word.H"
#include <string_view>
#include <string>
#include <iostream>

View File

@ -40,6 +40,7 @@ SourceFiles
#include "Dictionary.H"
#include "simpleRegIOobject.H"
#include <string_view>
#include <string>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -333,7 +333,7 @@ Foam::fileMonitor& Foam::fileOperation::monitor() const
void Foam::fileOperation::mergeTimes
(
const instantList& extraTimes,
const UList<instant>& extraTimes,
const word& constantName,
instantList& times
)

View File

@ -198,8 +198,10 @@ protected:
//- Merge two times
static void mergeTimes
(
const instantList& extraTimes,
const UList<instant>& extraTimes,
//! The "constant" name
const word& constantName,
//! [in,out] Updated with any extra times
instantList& times
);
@ -870,7 +872,13 @@ public:
) const;
//- Get sorted list of times
virtual instantList findTimes(const fileName&, const word&) const;
virtual instantList findTimes
(
//! The directory to search
const fileName& directory,
//! The "constant" name
const word& constantName = "constant"
) const;
//- Find time instance where IOobject is located.
//- The name of the IOobject can be empty, in which case only the

View File

@ -748,7 +748,13 @@ public:
// Other
//- Get sorted list of times
virtual instantList findTimes(const fileName&, const word&) const;
virtual instantList findTimes
(
//! The directory to search
const fileName& directory,
//! The "constant" name
const word& constantName = "constant"
) const;
//- Find time instance where IOobject is located.
//- The name of the IOobject can be empty, in which case only the

View File

@ -11,7 +11,10 @@ License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
Description
Add multi-region command-line options: -allRegions, -regions, -region
Add multi-region command-line options:
-allRegions | -all-regions
-regions
-region
Required Classes
- Foam::argList
@ -24,10 +27,10 @@ See Also
{
Foam::argList::addBoolOption
(
"all-regions",
"allRegions",
"Use all regions in regionProperties"
);
Foam::argList::addOptionCompat("all-regions", { "allRegions", -2506 });
Foam::argList::addOptionCompat("allRegions", { "all-regions", 0 });
Foam::argList::addOption
(

View File

@ -45,12 +45,19 @@ See Also
wordList regionNames;
{
// Local alias
auto& names = regionNames;
// Exit or fallback if nothing matches
constexpr bool exitOnNoMatches = true;
if (args.found("all-regions"))
// Local aliases
auto& names = regionNames;
const auto& fallback = Foam::polyMesh::defaultRegion;
if
(
// Handle both here (independent of which is an alias)
args.found("all-regions")
|| args.found("allRegions")
)
{
names =
(
@ -81,11 +88,11 @@ wordList regionNames;
{
select.uniq(); // Normally a no-op
if (select.size() == 1 && select.front().isLiteral())
if (select.size() == 1 && select[0].isLiteral())
{
// Identical to -region NAME
names.resize(1);
names.front() = select.front();
names[0] = select[0];
}
else if (select.size())
{
@ -116,12 +123,12 @@ wordList regionNames;
}
else
{
InfoErr<< "... ignoring and using default region"
InfoErr
<< "... ignoring and using default region"
<< nl << endl;
// Arbitrary fallback, but can handle this further on
names.resize(1);
names.front() = Foam::polyMesh::defaultRegion;
names[0] = fallback;
}
}
else
@ -160,7 +167,7 @@ wordList regionNames;
else
{
names.resize(1);
names.front() = Foam::polyMesh::defaultRegion;
names[0] = fallback;
InfoErr
<< "Warning: No regionProperties, "
@ -169,17 +176,30 @@ wordList regionNames;
}
}
}
else if (args.found("region"))
else
{
// Single region option or fallback
names.resize(1);
names.front() = args.get<word>("region");
auto& name = names[0];
if
(
!args.readIfPresent("region", name)
)
{
name = fallback;
}
}
// Fallback to defaultRegion
// Final sanity checks and/or fallback
if (names.empty())
{
names.resize(1);
names.front() = Foam::polyMesh::defaultRegion;
names[0] = fallback;
}
else if (names.size() == 1 && names[0].empty())
{
names[0] = fallback;
}
}

View File

@ -221,9 +221,14 @@ Foam::tmp<Foam::labelField> Foam::pairGAMGAgglomeration::agglomerate
auto tcoarseCellMap = tmp<labelField>::New(nFineCells, -1);
auto& coarseCellMap = tcoarseCellMap.ref();
// Small tolerance to account for faces potentially having slightly
// different truncation error in their weights from run to run
// (e.g. due to offloading). If all the largest faces per cell are
// within this tolerance use the first one. This guarantees repeatability.
const scalar tol = 1E-10;
nCoarseCells = 0;
label celli;
for (label cellfi=0; cellfi<nFineCells; cellfi++)
{
// Change cell ordering depending on direction for this level
@ -250,7 +255,7 @@ Foam::tmp<Foam::labelField> Foam::pairGAMGAgglomeration::agglomerate
(
coarseCellMap[upperAddr[facei]] < 0
&& coarseCellMap[lowerAddr[facei]] < 0
&& faceWeights[facei] > maxFaceWeight
&& faceWeights[facei] > maxFaceWeight*(1.0 + tol)
)
{
// Match found. Pick up all the necessary data
@ -282,7 +287,7 @@ Foam::tmp<Foam::labelField> Foam::pairGAMGAgglomeration::agglomerate
{
label facei = cellFaces[faceOs];
if (faceWeights[facei] > clusterMaxFaceCoeff)
if (faceWeights[facei] > clusterMaxFaceCoeff*(1.0 + tol))
{
clusterMatchFaceNo = facei;
clusterMaxFaceCoeff = faceWeights[facei];

View File

@ -27,6 +27,7 @@ License
\*---------------------------------------------------------------------------*/
#include "globalIndex.H"
#include <functional>
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
@ -696,159 +697,94 @@ void Foam::globalIndex::mpiGather
const UList<Type>& sendData,
OutputContainer& allData,
const label comm,
UPstream::commsTypes commsType,
const int tag
[[maybe_unused]] UPstream::commsTypes commsType,
[[maybe_unused]] const int tag
) const
{
if (!UPstream::parRun())
if (!UPstream::is_parallel(comm))
{
// Serial: direct copy
allData = sendData;
return;
}
// MPI_Gatherv requires contiguous data, but a byte-wise transfer can
// quickly exceed the 'int' limits used for MPI sizes/offsets.
// Thus gather label/scalar components when possible to increase the
// effective size limit.
//
// Note: cannot rely on pTraits (cmptType, nComponents) since this method
// needs to compile (and work) even with things like strings etc.
// Single char ad hoc "enum":
// - b(yte): gather bytes
// - f(loat): gather scalars components
// - i(nt): gather label components
// - 0: gather with Pstream read/write etc.
List<int> recvCounts;
List<int> recvOffsets;
char dataMode(0);
int nCmpts(0);
if constexpr (is_contiguous_v<Type>)
if (UPstream::master(comm))
{
if constexpr (is_contiguous_scalar<Type>::value)
{
dataMode = 'f';
nCmpts = static_cast<int>(sizeof(Type)/sizeof(scalar));
}
else if constexpr (is_contiguous_label<Type>::value)
{
dataMode = 'i';
nCmpts = static_cast<int>(sizeof(Type)/sizeof(label));
}
else
{
dataMode = 'b';
nCmpts = static_cast<int>(sizeof(Type));
}
allData.resize_nocopy(offsets_.back()); // == totalSize()
}
else
{
allData.clear(); // zero-size on non-master
}
if constexpr (UPstream_dataType<Type>::value)
{
// Restrict to basic (or aliased) MPI types
// - simplifies calculating counts/offsets
// and can call UPstream::mpiGatherv directly
// The sizing factor is constexpr
constexpr std::streamsize count = UPstream_dataType<Type>::size(1);
static_assert
(
(count == 1),
"Code does not (yet) work with aggregate types"
);
List<int> recvCounts;
List<int> recvOffsets;
// Offsets must fit into int
if (UPstream::master(comm))
{
const globalIndex& globalAddr = *this;
// Must be same as Pstream::nProcs(comm), at least on master!
// if (UPstream::nProcs(comm) != this->nProcs()) ...
if (globalAddr.totalSize() > (INT_MAX/nCmpts))
{
// Offsets do not fit into int - revert to manual.
dataMode = 0;
}
else
{
// Must be same as Pstream::nProcs(comm), at least on master!
const label nproc = globalAddr.nProcs();
recvCounts.resize(offsets_.size()-1);
recvOffsets.resize(offsets_.size());
allData.resize_nocopy(globalAddr.totalSize());
// Copy offsets
std::copy(offsets_.begin(), offsets_.end(), recvOffsets.begin());
recvCounts.resize(nproc);
recvOffsets.resize(nproc+1);
// Calculate sizes. Currently without std::minus <functional>
std::transform
(
offsets_.begin()+1, offsets_.end(),
offsets_.begin(), recvCounts.begin(),
std::minus<>{}
);
for (label proci = 0; proci < nproc; ++proci)
{
recvCounts[proci] = globalAddr.localSize(proci)*nCmpts;
recvOffsets[proci] = globalAddr.localStart(proci)*nCmpts;
}
recvOffsets[nproc] = globalAddr.totalSize()*nCmpts;
// Assign local data directly
recvCounts[0] = 0; // ie, ignore for MPI_Gatherv
SubList<Type>(allData, globalAddr.range(0)) =
SubList<Type>(sendData, globalAddr.range(0));
}
// FUTURE .. fix sizes and offsets by the element factor...
// if constexpr (UPstream_basic_dataType<Type>::size(1) > 1)
}
// Consistent information for everyone
UPstream::broadcast(&dataMode, 1, comm);
int sendSize = static_cast<int>(sendData.size());
// Note we let MPI_Gatherv copy back the local data as well...
UPstream::mpiGatherv
(
sendData.cdata(),
sendSize,
allData.data(),
recvCounts,
recvOffsets,
comm
);
}
// Dispatch
switch (dataMode)
else
{
case 'b': // Byte-wise
{
UPstream::mpiGatherv
(
sendData.cdata_bytes(),
sendData.size_bytes(),
allData.data_bytes(),
recvCounts,
recvOffsets,
comm
);
break;
}
case 'f': // Float (scalar) components
{
typedef scalar cmptType;
UPstream::mpiGatherv
(
reinterpret_cast<const cmptType*>(sendData.cdata()),
(sendData.size()*nCmpts),
reinterpret_cast<cmptType*>(allData.data()),
recvCounts,
recvOffsets,
comm
);
break;
}
case 'i': // Int (label) components
{
typedef label cmptType;
UPstream::mpiGatherv
(
reinterpret_cast<const cmptType*>(sendData.cdata()),
(sendData.size()*nCmpts),
reinterpret_cast<cmptType*>(allData.data()),
recvCounts,
recvOffsets,
comm
);
break;
}
default: // Regular (manual) gathering
{
globalIndex::gather
(
offsets_, // needed on master only
comm,
UPstream::allProcs(comm), // All communicator ranks
sendData,
allData,
tag,
commsType
);
break;
}
}
if (!UPstream::master(comm))
{
allData.clear(); // safety: zero-size on non-master
// Regular (manual) gathering
globalIndex::gather
(
offsets_, // needed on master only
comm,
UPstream::allProcs(comm), // All communicator ranks
sendData,
allData,
tag,
commsType
);
}
}

View File

@ -43,6 +43,9 @@ SourceFiles
#include "bool.H"
#include "stdFoam.H"
#include <string_view>
#include <string>
// Avoid any pre-processor conflicts with enum names
#undef FALSE
#undef TRUE

View File

@ -58,6 +58,9 @@ Description
#include <algorithm> // std::copy
#include <utility> // std::initializer_list
#include <vector>
#include <string_view>
#include <string>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -93,6 +96,11 @@ class CStringList
// \return location one-past end of dest (ie, the next destination)
static inline char* stringCopy(char* dest, const char* src);
//- Copy string characters into dest as NUL-terminated string.
//
// \return location one-past end of dest (ie, the next destination)
static inline char* stringCopy(char *dest, std::string_view src);
//- Copy string characters into dest as NUL-terminated string.
// Forces conversion of std::sub_match to string form
//
@ -133,9 +141,17 @@ public:
template<class StringType>
inline explicit CStringList(const UList<StringType>& input);
//- Copy construct from a list of string_views
// Copies the input characters.
inline explicit CStringList(const UList<std::string_view>& input);
//- Copy construct from a list of string_views
// Copies the input characters.
inline explicit CStringList(const std::vector<std::string_view>& input);
//- Copy construct from a list of sub-string references
// Copies the input characters.
explicit CStringList(const SubStrings& input);
inline explicit CStringList(const SubStrings& input);
//- Destructor. Invokes clear() to free memory.
@ -157,6 +173,9 @@ public:
//- Return the number of C-strings (ie, argc)
int size() const noexcept { return argc_; }
//- The flattened character content, with interspersed nul-chars
inline std::string_view view() const;
//- The flattened character content, with interspersed nul-chars
const char* cdata_bytes() const noexcept { return data_; }

View File

@ -28,16 +28,6 @@ License
#include "CStringList.H"
#include "Ostream.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::CStringList::CStringList(const SubStrings& input)
:
CStringList()
{
resetContent(input);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
// Largely identical to resetContent() except with 'c-string'

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2024 OpenCFD Ltd.
Copyright (C) 2016-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -35,6 +35,14 @@ inline char* Foam::CStringList::stringCopy(char* dest, const char* src)
}
inline char* Foam::CStringList::stringCopy(char *dest, std::string_view src)
{
dest = std::copy_n(src.data(), src.size(), dest);
*(dest++) = '\0';
return dest;
}
inline char* Foam::CStringList::stringCopy(char *dest, const std::string& src)
{
dest = std::copy_n(src.data(), src.size(), dest);
@ -90,6 +98,33 @@ inline Foam::CStringList::CStringList(const UList<StringType>& input)
}
inline Foam::CStringList::CStringList(const UList<std::string_view>& input)
:
CStringList()
{
resetContent(input);
}
inline Foam::CStringList::CStringList
(
const std::vector<std::string_view>& input
)
:
CStringList()
{
resetContent(input);
}
inline Foam::CStringList::CStringList(const SubStrings& input)
:
CStringList()
{
resetContent(input);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
inline Foam::CStringList::~CStringList()
@ -100,6 +135,12 @@ inline Foam::CStringList::~CStringList()
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline std::string_view Foam::CStringList::view() const
{
return std::string_view(data_, nbytes_);
}
inline void Foam::CStringList::clear()
{
argc_ = 0;

View File

@ -37,6 +37,7 @@ Description
#include <regex> // For std::ssub_match
#include <memory>
#include <string_view>
#include <string>
#include <vector>

View File

@ -69,6 +69,7 @@ SourceFiles
#define Foam_regExpCxx_H
#include <regex>
#include <string_view>
#include <string>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -54,6 +54,7 @@ SourceFiles
#include "Hasher.H"
#include <cstdlib>
#include <cstring>
#include <string_view>
#include <string>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017 OpenCFD Ltd.
Copyright (C) 2017-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -46,85 +46,106 @@ namespace Foam
namespace stringOps
{
//- 'Natural' compare for C-strings
// Uses algorithm and code from Jan-Marten Spit <jmspit@euronet.nl>
//
// In the 'natural' comparison, strings are compared alphabetically
// and numerically. Thus 'file010.txt' sorts after 'file2.txt'
//
// \param s1 left string
// \param s2 right string
//- 'Natural' compare for C-strings
// Uses algorithm and code from Jan-Marten Spit <jmspit@euronet.nl>
//
// In the 'natural' comparison, strings are compared alphabetically
// and numerically. Thus 'file010.txt' sorts after 'file2.txt'
//
// \param s1 left string
// \param s2 right string
// \return -1 when s1 < s2, 0 when s1 == s2, 1 when s1 > s2
int natstrcmp(const char* s1, const char* s2);
//- Encapsulation of natural order sorting for algorithms
struct natural_sort
{
//- Natural compare for std::string
// \return -1 when s1 < s2, 0 when s1 == s2, 1 when s1 > s2
int natstrcmp(const char* s1, const char* s2);
//- Encapsulation of natural order sorting for algorithms
struct natural_sort
static inline int compare
(
const std::string& s1,
const std::string& s2
)
{
//- Natural compare for std::string
// \return -1 when s1 < s2, 0 when s1 == s2, 1 when s1 > s2
static inline int compare
(
const std::string& s1,
const std::string& s2
)
{
return natstrcmp(s1.data(), s2.data());
}
return stringOps::natstrcmp(s1.data(), s2.data());
}
//- Default (forward) natural sorting
//- Natural compare two strings for a less-than relationship
static inline bool less
(
const std::string& s1,
const std::string& s2
)
{
return (natural_sort::compare(s1, s2) < 0);
}
//- Natural compare two strings for a greater-than relationship
static inline bool greater
(
const std::string& s1,
const std::string& s2
)
{
return (natural_sort::compare(s1, s2) > 0);
}
//- Default (forward) natural sorting
bool operator()(const std::string& s1, const std::string& s2) const
{
return (natural_sort::compare(s1, s2) < 0);
}
//- Reverse natural sorting
struct reverse
{
//- Reverse natural sorting
bool operator()(const std::string& s1, const std::string& s2) const
{
return natural_sort::compare(s1, s2) < 0;
return (natural_sort::compare(s1, s2) > 0);
}
//- Reverse natural sorting
struct reverse
{
//- Reverse natural sorting
bool operator()(const std::string& s1, const std::string& s2) const
{
return natural_sort::compare(s1, s2) > 0;
}
};
//- A list compare binary predicate for natural sort
template<class T>
struct less
{
const UList<T>& values;
less(const UList<T>& list)
:
values(list)
{}
bool operator()(const label a, const label b) const
{
return natural_sort::compare(values[a], values[b]) < 0;
}
};
//- A list compare binary predicate for reverse natural sort
template<class T>
struct greater
{
const UList<T>& values;
greater(const UList<T>& list)
:
values(list)
{}
bool operator()(const label a, const label b) const
{
return natural_sort::compare(values[a], values[b]) > 0;
}
};
};
//- A UList compare binary predicate for natural sort
template<class T>
struct list_less
{
const UList<T>& values;
list_less(const UList<T>& list) noexcept
:
values(list)
{}
bool operator()(label a, label b) const
{
return (natural_sort::compare(values[a], values[b]) < 0);
}
};
//- A Ulist compare binary predicate for reverse natural sort
template<class T>
struct list_greater
{
const UList<T>& values;
list_greater(const UList<T>& list) noexcept
:
values(list)
{}
bool operator()(label a, label b) const
{
return (natural_sort::compare(values[a], values[b]) > 0);
}
};
};
} // End namespace stringOps
} // End namespace Foam

View File

@ -28,33 +28,45 @@ License
#include "Pstream.H"
#include "PstreamGlobals.H"
#include "UPstreamWrapping.H"
#include "vector.H" // for debugging
#undef STRINGIFY
#undef STRING_QUOTE
#define STRINGIFY(content) #content
#define STRING_QUOTE(input) STRINGIFY(input)
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
static inline bool is_basic_dataType(Foam::UPstream::dataTypes id) noexcept
namespace
{
inline bool is_nonAggregate(Foam::UPstream::dataTypes id) noexcept
{
return
(
int(id) >= int(Foam::UPstream::dataTypes::Basic_begin)
&& int(id) < int(Foam::UPstream::dataTypes::Basic_end)
)
||
(
int(id) >= int(Foam::UPstream::dataTypes::User_begin)
&& int(id) < int(Foam::UPstream::dataTypes::User_end)
);
}
namespace
{
using namespace Foam;
// Local function to print some error information
inline void printErrorNonIntrinsic
(
const char* context,
UPstream::dataTypes dataTypeId
Foam::UPstream::dataTypes dataTypeId
)
{
using namespace Foam;
FatalError
<< "Bad input for " << context << ": likely a programming problem\n"
<< " Non-intrinsic data (" << int(dataTypeId) << ")\n"
<< " Non-intrinsic/non-user data (type:" << int(dataTypeId) << ")\n"
<< Foam::endl;
}
@ -214,19 +226,37 @@ void Foam::UPstream::mpi_gatherv
{
MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
if
(
FOAM_UNLIKELY
(
!is_basic_dataType(dataTypeId)
)
)
// Runtime assert that we are not using aggregated data types
if (FOAM_UNLIKELY(!is_nonAggregate(dataTypeId)))
{
FatalErrorInFunction;
printErrorNonIntrinsic("MPI_Gatherv()", dataTypeId);
FatalError << Foam::abort(FatalError);
}
const label np = UPstream::nProcs(communicator);
// For total-size calculation,
// don't rely on recvOffsets being (np+1)
const int totalSize =
(
(UPstream::master(communicator) && np > 1)
? (recvOffsets[np-1] + recvCounts[np-1])
: 0
);
if (FOAM_UNLIKELY(UPstream::debug))
{
Perr<< "[mpi_gatherv] :"
<< " type:" << int(dataTypeId)
<< " count:" << sendCount
<< " total:" << totalSize
<< " comm:" << communicator
<< " recvCounts:" << flatOutput(recvCounts)
<< " recvOffsets:" << flatOutput(recvOffsets)
<< Foam::endl;
}
{
PstreamDetail::gatherv
(
@ -235,6 +265,48 @@ void Foam::UPstream::mpi_gatherv
datatype, communicator
);
}
// Extended debugging. Limit to master:
#if 0
if (FOAM_UNLIKELY(UPstream::debug))
{
if (UPstream::master(communicator))
{
switch (dataTypeId)
{
#undef dataPrinter
#define dataPrinter(enumType, nativeType) \
case UPstream::dataTypes::enumType : \
{ \
UList<nativeType> combined \
( \
static_cast<nativeType*>(recvData), \
totalSize \
); \
\
Info<< "[mpi_gatherv] => " \
"List<" STRING_QUOTE(nativeType) "> "; \
combined.writeList(Info) << Foam::endl; \
\
break; \
}
// Some common types
dataPrinter(type_int32, int32_t);
dataPrinter(type_int64, int64_t);
dataPrinter(type_float, float);
dataPrinter(type_double, double);
dataPrinter(type_3float, floatVector);
dataPrinter(type_3double, doubleVector);
// Some other type
default: break;
#undef dataPrinter
}
}
}
#endif
}
@ -255,13 +327,8 @@ void Foam::UPstream::mpi_scatterv
{
MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId);
if
(
FOAM_UNLIKELY
(
!is_basic_dataType(dataTypeId)
)
)
// Runtime assert that we are not using aggregated data types
if (FOAM_UNLIKELY(!is_nonAggregate(dataTypeId)))
{
FatalErrorInFunction;
printErrorNonIntrinsic("MPI_Scatterv()", dataTypeId);

View File

@ -16,6 +16,6 @@ starcd/STARCDMeshWriter.C
polyDualMesh/polyDualMesh.C
vtk/output/foamVtkSurfaceFieldWriter.C
vtk/output/foamVtkSurfaceFieldWriter.cxx
LIB = $(FOAM_LIBBIN)/libconversion

View File

@ -98,7 +98,7 @@ bool writeAreaField
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "ensightOutputAreaFieldTemplates.C"
#include "ensightOutputAreaField.txx"
#endif
#endif

View File

@ -177,7 +177,7 @@ bool writePointField
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "ensightOutputVolFieldTemplates.C"
#include "ensightOutputVolField.txx"
#endif
#endif

View File

@ -39,7 +39,7 @@ Note
SourceFiles
foamVtkToolsI.H
foamVtkToolsTemplates.C
foamVtkTools.txx
\*---------------------------------------------------------------------------*/
@ -358,7 +358,7 @@ void Foam::vtk::Tools::remapTuple<Foam::symmTensor>(double data[])
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "foamVtkToolsTemplates.C"
#include "foamVtkTools.txx"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -39,7 +39,7 @@ Note
SourceFiles
foamVtkVtuAdaptorI.H
foamVtkVtuAdaptorTemplates.C
foamVtkVtuAdaptor.txx
\*---------------------------------------------------------------------------*/
@ -156,7 +156,7 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "foamVtkVtuAdaptorTemplates.C"
#include "foamVtkVtuAdaptor.txx"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -32,7 +32,7 @@ Description
Caution, currently only works properly for indirect patches.
SourceFiles
foamVtkGenericPatchGeoFieldsWriter.C
foamVtkGenericPatchGeoFieldsWriter.txx
\*---------------------------------------------------------------------------*/
@ -117,7 +117,7 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "foamVtkGenericPatchGeoFieldsWriter.C"
#include "foamVtkGenericPatchGeoFieldsWriter.txx"
#endif

View File

@ -44,7 +44,7 @@ See Also
Foam::vtk::internalMeshWriter
SourceFiles
foamVtkInternalWriterTemplates.C
foamVtkInternalWriter.txx
\*---------------------------------------------------------------------------*/
@ -183,7 +183,7 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "foamVtkInternalWriterTemplates.C"
#include "foamVtkInternalWriter.txx"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -43,7 +43,7 @@ See Also
Foam::vtk::patchMeshWriter
SourceFiles
foamVtkPatchWriterTemplates.C
foamVtkPatchWriter.txx
\*---------------------------------------------------------------------------*/
@ -202,7 +202,7 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "foamVtkPatchWriterTemplates.C"
#include "foamVtkPatchWriter.txx"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -47,7 +47,7 @@ Note
may be addressed using ghost points.
SourceFiles
surfaceFieldWriter.C
foamVtkSurfaceFieldWriter.cxx
\*---------------------------------------------------------------------------*/

View File

@ -9,7 +9,7 @@ faceSetOption/faceSetOption.C
derivedSources=sources/derived
$(derivedSources)/externalHeatFluxSource/externalHeatFluxSource.C
$(derivedSources)/jouleHeatingSource/jouleHeatingSource.C
$(derivedSources)/jouleHeatingSource/jouleHeatingSource.cxx
$(derivedSources)/contactHeatFluxSource/contactHeatFluxSource.C
$(derivedSources)/externalFileSource/externalFileSource.C

View File

@ -81,6 +81,33 @@ Foam::fa::option::option
active_(dict.getOrDefault("active", true)),
log(true)
{
// Suffix hint for variable names
if
(
coeffs_.readIfPresent("suffixing", suffixHint_)
|| dict.readIfPresent("suffixing", suffixHint_)
)
{
Switch sw = Switch::find(suffixHint_);
if (sw.good())
{
if (!sw) // No suffix
{
suffixHint_.clear();
}
}
else if (suffixHint_ == "default")
{
sw = true;
}
if (sw) // Default suffix
{
suffixHint_ = '_' + regionName_;
}
}
if (dict.readIfPresent("area", areaName_))
{
if (!sameRegionNames(areaName_, defaultAreaName))
@ -95,9 +122,14 @@ Foam::fa::option::option
}
}
Log << incrIndent << indent << "Source: " << name_
<< " [" << polyMesh::regionName(areaName_) << ']' << endl
<< decrIndent;
Log << incrIndent << indent << "Source: " << name_;
if (!polyMesh::regionName(areaName_).empty())
{
Log<< " [" << areaName_ << ']';
}
Info<< decrIndent << endl;
}
@ -117,13 +149,20 @@ Foam::autoPtr<Foam::fa::option> Foam::fa::option::New
coeffs.readIfPresent("area", areaName);
Info<< indent
<< "Selecting finite-area option, type " << modelType
<< " [" << polyMesh::regionName(areaName) << ']';
<< "Selecting finite-area option, type " << modelType;
if (!sameRegionNames(areaName, defaultAreaName))
if (sameRegionNames(areaName, defaultAreaName))
{
Info<< " != " << defaultAreaName << nl;
if (!polyMesh::regionName(areaName).empty())
{
Info<< " [" << areaName << ']';
}
}
else
{
Info<< " [" << areaName << "] != [" << defaultAreaName << ']';
}
Info<< endl;
mesh.time().libs().open

View File

@ -65,10 +65,13 @@ Usage
--> the selected faOption settings | dictionary | no | -
active | Flag to (de)activate faOption | bool | no | true
log | Flag to log faOption-related info | bool | no | true
suffixing | Suffix hint for option variables | word | no | -
\endtable
Note
- Source/sink options are to be added to the right-hand side of equations.
- Suffixing (true|false|none|default|...) currently selects between
no suffix and ('_'+region).
SourceFiles
faOption.C
@ -136,6 +139,9 @@ protected:
//- The model region name (finite-area)
word regionName_;
//- Suffix hint for variable names (default: "")
word suffixHint_;
// Protected Member Functions
@ -273,7 +279,7 @@ public:
//- The source name
const word& name() const noexcept { return name_; }
//- Return const access to the mesh database
//- Return const access to the volume mesh
const fvMesh& mesh() const noexcept { return mesh_; }
//- Return dictionary
@ -304,6 +310,18 @@ public:
inline bool active(bool on) noexcept;
// Helper Functions
//- The suffix hint when generating variable names
const word& suffixHint() const noexcept { return suffixHint_; }
//- Return the concatenation of \p base and the suffix hint
inline word suffixed(const char* base) const;
//- Return the concatenation of \p base and the suffix hint
inline word suffixed(const std::string& base) const;
// Checks
//- Is the source active?

View File

@ -61,4 +61,18 @@ inline const Foam::volSurfaceMapping& Foam::fa::option::vsm() const
}
inline Foam::word
Foam::fa::option::suffixed(const char* base) const
{
return word(base + suffixHint_);
}
inline Foam::word
Foam::fa::option::suffixed(const std::string& base) const
{
return word(base + suffixHint_);
}
// ************************************************************************* //

View File

@ -27,7 +27,6 @@ License
#include "faOptions.H"
#include "faMesh.H"
#include "faMeshesRegistry.H"
#include "Time.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -68,7 +67,7 @@ Foam::IOobject createIOobject
lookupName,
mesh.time().constant(),
// located under finite-area
faMeshesRegistry::New(mesh).thisDb(),
faMesh::Registry(mesh),
IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::REGISTER
@ -188,11 +187,7 @@ Foam::fa::options& Foam::fa::options::New
);
// Registered under finite-area?
auto* ptr =
faMeshesRegistry::New(mesh).thisDb().getObjectPtr<fa::options>
(
lookupName
);
auto* ptr = faMesh::Registry(mesh).getObjectPtr<fa::options>(lookupName);
if (!ptr && polyMesh::regionName(defaultAreaName).empty())
{

View File

@ -30,7 +30,6 @@ License
#include "addToRunTimeSelectionTable.H"
#include "volFields.H"
#include "famSup.H"
#include "zeroGradientFaPatchFields.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
@ -57,13 +56,10 @@ Foam::fa::contactHeatFluxSource::contactHeatFluxSource
:
fa::faceSetOption(sourceName, modelType, dict, mesh, defaultAreaName),
TName_(dict.getOrDefault<word>("T", "T")),
TprimaryName_(dict.get<word>("Tprimary")),
TprimaryName_(dict.getOrDefault<word>("Tprimary", "T")),
Tprimary_(mesh_.lookupObject<volScalarField>(TprimaryName_)),
thicknessLayers_(),
kappaLayers_(),
contactRes_(0),
curTimeIndex_(-1),
coupling_()
curTimeIndex_(-1)
{
fieldNames_.resize(1, TName_);
@ -131,30 +127,30 @@ void Foam::fa::contactHeatFluxSource::addSup
const label fieldi
)
{
if (isActive())
if (!isActive())
{
DebugInfo
<< name() << ": applying source to "
<< eqn.psi().name() << endl;
return;
}
if (curTimeIndex_ != mesh().time().timeIndex())
{
tmp<DimensionedField<scalar, areaMesh>> htcw(htc());
DebugInfo<< name() << ": applying source to " << eqn.psi().name() << endl;
// Wall temperature - mapped from primary field to finite-area
auto Twall = DimensionedField<scalar, areaMesh>::New
(
"Tw_" + option::name(),
regionMesh(),
dimensionedScalar(dimTemperature, Zero)
);
if (curTimeIndex_ != mesh().time().timeIndex())
{
tmp<DimensionedField<scalar, areaMesh>> htcw(htc());
vsm().mapInternalToSurface<scalar>(Tprimary_, Twall.ref().field());
// Wall temperature - mapped from primary field to finite-area
auto Twall = DimensionedField<scalar, areaMesh>::New
(
"Tw_" + option::name(),
regionMesh(),
dimensionedScalar(dimTemperature, Zero)
);
eqn += -fam::Sp(htcw(), eqn.psi()) + htcw()*Twall;
vsm().mapInternalToSurface<scalar>(Tprimary_, Twall.ref().field());
curTimeIndex_ = mesh().time().timeIndex();
}
eqn += -fam::Sp(htcw(), eqn.psi()) + htcw()*Twall;
curTimeIndex_ = mesh().time().timeIndex();
}
}
@ -190,8 +186,14 @@ bool Foam::fa::contactHeatFluxSource::read(const dictionary& dict)
const labelList& patches = regionMesh().whichPolyPatches();
coupling_.clear();
coupling_.resize(patches.empty() ? 0 : (patches.last()+1));
if (patches.empty())
{
coupling_.clear();
}
else
{
coupling_.resize_null(patches.back()+1);
}
for (const label patchi : patches)
{

View File

@ -40,6 +40,8 @@ Usage
{
// Mandatory entries (unmodifiable)
type contactHeatFluxSource;
// Optional entries (unmodifiable)
Tprimary <TprimaryFieldName>;
// Optional entries (runtime modifiable)
@ -60,12 +62,19 @@ Usage
\table
Property | Description | Type | Reqd | Dflt
type | Type name: contactHeatFluxSource | word | yes | -
Tprimary | Name of primary temperature field | word | yes | -
T | Name of operand temperature field | word | no | T
Tprimary | Name of primary temperature field | word | no | T
thicknessLayers | List of thicknesses of layers | scalarList | no | -
kappaLayers | List of conductivities of layers | scalarList | cndtnl | -
\endtable
Fields/variables used:
\table
Property | Description | Type | Deflt
T | Temperature | shell | T
Tprimary | Temperature | volume | T
\endtable
The inherited entries are elaborated in:
- \link faOption.H \endlink
- \link faceSetOption.H \endlink
@ -124,13 +133,13 @@ class contactHeatFluxSource
// Private Data
//- Name of temperature field
//- Name of shell temperature field (default: "T")
word TName_;
//- Name of primary temperature field
word TprimaryName_;
//- Name of volume temperature field (default: "T")
const word TprimaryName_;
//- Primary region temperature
//- Primary (volume) region temperature
const volScalarField& Tprimary_;
//- Thickness of layers

View File

@ -72,10 +72,6 @@ Foam::fa::externalHeatFluxSource::externalHeatFluxSource
fa::faceSetOption(sourceName, modelType, dict, m, defaultAreaName),
mode_(operationModeNames.get("mode", dict)),
TName_(dict.getOrDefault<word>("T", "T")),
Q_(nullptr),
q_(nullptr),
h_(nullptr),
Ta_(nullptr),
emissivity_(dict.getOrDefault<scalar>("emissivity", 0))
{
fieldNames_.resize(1, TName_);
@ -205,6 +201,11 @@ bool Foam::fa::externalHeatFluxSource::read(const dictionary& dict)
mode_ = operationModeNames.get("mode", dict);
Q_.reset(nullptr);
q_.reset(nullptr);
h_.reset(nullptr);
Ta_.reset(nullptr);
switch (mode_)
{
case fixedPower:

View File

@ -103,7 +103,7 @@ Usage
\verbatim
power | Use fixed power (supply Q)
flux | Use fixed heat flux (supply q)
coefficient | Use fixes heat transfer coefficient (supply h and T)
coefficient | Use fixes heat transfer coefficient (supply h and Ta)
\endverbatim
See also
@ -159,7 +159,7 @@ private:
//- Operation mode
operationMode mode_;
//- Name of temperature field
//- Name of shell temperature field (default: "T")
word TName_;
//- Heat power [W]
@ -174,7 +174,7 @@ private:
//- Ambient temperature [K]
autoPtr<Function1<scalar>> Ta_;
//- Optional surface emissivity for radiative transfer to ambient
//- Surface emissivity for radiative transfer to ambient (default: 0)
scalar emissivity_;

View File

@ -115,23 +115,30 @@ Usage
- \link faceSetOption.H \endlink
Note
- \c anisotropicElectricalConductivity=true enables
anisotropic (tensorial) electrical conductivity.
- \c anisotropicElectricalConductivity=false enables
isotropic (scalar) electrical conductivity.
- The electrical conductivity can be specified using either:
- If the \c sigma entry is present the electrical conductivity is specified
as a function of temperature using a \c Function1 type.
- If not present the \c sigma field will be read from file.
- If the \c anisotropicElectricalConductivity flag is set to \c true,
\c sigma should be specified as a tensor quantity.
If the \c sigma entry is present, the electrical conductivity is specified
as a function of temperature using a \c Function1 type, otherwise
the \c sigma field will be read from file.
When the \c anisotropicElectricalConductivity flag is set to \c true,
\c sigma should be specified as a \em tensor quantity instead of as
an isotropic \em scalar quantity.
BREAKING Naming changes from 2056 and earlier for the fields:
\table
Field | Scoped names | Scoped names (old)
V | \<scope\>:V (suffix) | \<scope\>:V_ + regionName
sigma | \<scope\>:sigma (suffix) | \<scope\>:sigma_ + regionName
\endtable
It is possible to replicate the older naming by specifying
the \c suffixing to ('_' + regionName).
See also
- Foam::Function1
- Foam::fv::jouleHeatingSource
SourceFiles
jouleHeatingSource.C
jouleHeatingSourceTemplates.C
jouleHeatingSource.cxx
jouleHeatingSourceImpl.cxx
\*---------------------------------------------------------------------------*/
@ -188,13 +195,13 @@ class jouleHeatingSource
void initialiseSigma
(
const dictionary& dict,
autoPtr<Function1<Type>>& sigmaVsTPtr
autoPtr<Function1<Type>>& sigmaFunctionPtr
);
//- Update the electrical conductivity field
template<class Type>
const GeometricField<Type, faPatchField, areaMesh>&
updateSigma(const autoPtr<Function1<Type>>& sigmaVsTPtr) const;
updateSigma(const autoPtr<Function1<Type>>& sigmaFunctionPtr) const;
public:
@ -229,22 +236,22 @@ public:
// Member Functions
// Evaluation
// Evaluation
//- Add explicit contribution to compressible momentum equation
virtual void addSup
(
const areaScalarField& h,
const areaScalarField& rho,
faMatrix<scalar>& eqn,
const label fieldi
);
//- Add explicit contribution to energy equation
virtual void addSup
(
const areaScalarField& h,
const areaScalarField& rho,
faMatrix<scalar>& eqn,
const label fieldi
);
// IO
// IO
//- Read source dictionary
virtual bool read(const dictionary& dict);
//- Read source dictionary
virtual bool read(const dictionary& dict);
};
@ -255,12 +262,6 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "jouleHeatingSourceTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -42,6 +42,12 @@ namespace fa
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Implementation
#include "jouleHeatingSourceImpl.cxx"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fa::jouleHeatingSource::jouleHeatingSource
@ -59,7 +65,7 @@ Foam::fa::jouleHeatingSource::jouleHeatingSource
(
IOobject
(
IOobject::scopedName(typeName, "V_" + regionName_),
suffixed(IOobject::scopedName(typeName, "V")),
regionMesh().thisDb().time().timeName(),
regionMesh().thisDb(),
IOobject::MUST_READ,
@ -68,8 +74,6 @@ Foam::fa::jouleHeatingSource::jouleHeatingSource
),
regionMesh()
),
scalarSigmaVsTPtr_(nullptr),
tensorSigmaVsTPtr_(nullptr),
curTimeIndex_(-1),
nIter_(1),
anisotropicElectricalConductivity_(false)
@ -78,6 +82,8 @@ Foam::fa::jouleHeatingSource::jouleHeatingSource
fa::option::resetApplied();
read(dict);
if (anisotropicElectricalConductivity_)
{
Info<< " Using tensor electrical conductivity" << endl;
@ -90,8 +96,6 @@ Foam::fa::jouleHeatingSource::jouleHeatingSource
initialiseSigma(coeffs_, scalarSigmaVsTPtr_);
}
read(dict);
}
@ -105,12 +109,14 @@ void Foam::fa::jouleHeatingSource::addSup
const label fieldi
)
{
if (isActive())
if (!isActive())
{
DebugInfo
<< name() << ": applying source to "
<< eqn.psi().name() << endl;
return;
}
DebugInfo<< name() << ": applying source to " << eqn.psi().name() << endl;
{
if (curTimeIndex_ != mesh().time().timeIndex())
{
for (label i = 0; i < nIter_; ++i)
@ -118,8 +124,7 @@ void Foam::fa::jouleHeatingSource::addSup
if (anisotropicElectricalConductivity_)
{
// Update sigma as a function of T if required
const areaTensorField& sigma =
updateSigma(tensorSigmaVsTPtr_);
const auto& sigma = updateSigma(tensorSigmaVsTPtr_);
// Solve the electrical potential equation
faScalarMatrix VEqn(fam::laplacian(h*sigma, V_));
@ -129,8 +134,7 @@ void Foam::fa::jouleHeatingSource::addSup
else
{
// Update sigma as a function of T if required
const areaScalarField& sigma =
updateSigma(scalarSigmaVsTPtr_);
const auto& sigma = updateSigma(scalarSigmaVsTPtr_);
// Solve the electrical potential equation
faScalarMatrix VEqn(fam::laplacian(h*sigma, V_));
@ -145,7 +149,7 @@ void Foam::fa::jouleHeatingSource::addSup
// Add the Joule heating contribution
const word sigmaName
(
IOobject::scopedName(typeName, "sigma_" + regionName_)
IOobject::scopedName(typeName, "sigma") + suffixHint()
);
areaVectorField gradV("gradV", fac::grad(V_));
@ -162,15 +166,13 @@ void Foam::fa::jouleHeatingSource::addSup
if (anisotropicElectricalConductivity_)
{
const auto& sigma =
obr.lookupObject<areaTensorField>(sigmaName);
const auto& sigma = obr.lookupObject<areaTensorField>(sigmaName);
tsource = (h*sigma & gradV) & gradV;
}
else
{
const auto& sigma =
obr.lookupObject<areaScalarField>(sigmaName);
const auto& sigma = obr.lookupObject<areaScalarField>(sigmaName);
tsource = (h*sigma*gradV) & gradV;
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019-2024 OpenCFD Ltd.
Copyright (C) 2019-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -33,16 +33,21 @@ template<class Type>
void Foam::fa::jouleHeatingSource::initialiseSigma
(
const dictionary& dict,
autoPtr<Function1<Type>>& sigmaVsTPtr
autoPtr<Function1<Type>>& sigmaFunctionPtr
)
{
typedef GeometricField<Type, faPatchField, areaMesh> FieldType;
const word sigmaName
(
IOobject::scopedName(typeName, "sigma") + suffixHint()
);
auto& obr = regionMesh().thisDb();
IOobject io
(
IOobject::scopedName(typeName, "sigma_" + regionName_),
sigmaName,
obr.time().timeName(),
obr,
IOobject::NO_READ,
@ -52,11 +57,11 @@ void Foam::fa::jouleHeatingSource::initialiseSigma
autoPtr<FieldType> tsigma;
if (dict.found("sigma"))
{
// Sigma to be defined using a Function1 type
sigmaVsTPtr = Function1<Type>::New("sigma", dict, &mesh_);
// Is sigma defined using a Function1 type?
sigmaFunctionPtr = Function1<Type>::NewIfPresent("sigma", dict, &mesh_);
if (sigmaFunctionPtr)
{
tsigma.reset
(
new FieldType
@ -89,31 +94,34 @@ template<class Type>
const Foam::GeometricField<Type, Foam::faPatchField, Foam::areaMesh>&
Foam::fa::jouleHeatingSource::updateSigma
(
const autoPtr<Function1<Type>>& sigmaVsTPtr
const autoPtr<Function1<Type>>& sigmaFunctionPtr
) const
{
typedef GeometricField<Type, faPatchField, areaMesh> FieldType;
const word sigmaName
(
IOobject::scopedName(typeName, "sigma") + suffixHint()
);
const auto& obr = regionMesh().thisDb();
auto& sigma =
obr.lookupObjectRef<FieldType>
(
IOobject::scopedName(typeName, "sigma_" + regionName_)
);
auto& sigma = obr.lookupObjectRef<FieldType>(sigmaName);
if (!sigmaVsTPtr)
if (!sigmaFunctionPtr)
{
// Electrical conductivity field, sigma, was specified by the user
return sigma;
}
const auto& sigmaFunction = sigmaFunctionPtr();
const auto& T = obr.lookupObject<areaScalarField>(TName_);
// Internal field
forAll(sigma, i)
{
sigma[i] = sigmaVsTPtr->value(T[i]);
sigma[i] = sigmaFunction.value(T[i]);
}
@ -127,7 +135,7 @@ Foam::fa::jouleHeatingSource::updateSigma
const scalarField& Tbf = T.boundaryField()[patchi];
forAll(pf, facei)
{
pf[facei] = sigmaVsTPtr->value(Tbf[facei]);
pf[facei] = sigmaFunction.value(Tbf[facei]);
}
}
}

View File

@ -34,7 +34,7 @@ SourceFiles
ensightCase.C
ensightCaseI.H
ensightCaseOptions.C
ensightCaseTemplates.C
ensightCase.txx
\*---------------------------------------------------------------------------*/
@ -548,7 +548,7 @@ public:
#include "ensightCaseI.H"
#ifdef NoRepository
#include "ensightCaseTemplates.C"
#include "ensightCase.txx"
#endif
#endif

View File

@ -394,7 +394,7 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "ensightFileTemplates.C"
#include "ensightFile.txx"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -31,7 +31,7 @@ Description
SourceFiles
ensightOutput.C
ensightOutputTemplates.C
ensightOutput.txx
\*---------------------------------------------------------------------------*/
@ -557,7 +557,7 @@ bool writeFaceLocalField
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "ensightOutputTemplates.C"
#include "ensightOutput.txx"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -38,7 +38,7 @@ Note
SourceFiles
ensightOutputSurface.C
ensightOutputSurfaceTemplates.C
ensightOutputSurface.txx
\*---------------------------------------------------------------------------*/
@ -136,7 +136,7 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "ensightOutputSurfaceTemplates.C"
#include "ensightOutputSurface.txx"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -42,8 +42,8 @@ Description
SourceFiles
foamVtkFileWriter.C
foamVtkFileWriter.txx
foamVtkFileWriterI.H
foamVtkFileWriterTemplates.C
\*---------------------------------------------------------------------------*/
@ -350,7 +350,7 @@ public:
#include "foamVtkFileWriterI.H"
#ifdef NoRepository
#include "foamVtkFileWriterTemplates.C"
#include "foamVtkFileWriter.txx"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2023 OpenCFD Ltd.
Copyright (C) 2018-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -64,13 +64,17 @@ namespace Foam
// 2. natural sort (name)
struct seriesLess
{
bool operator()(const fileNameInstant a, const fileNameInstant b) const
template<class StringType>
bool operator()
(
const Instant<StringType>& a,
const Instant<StringType>& b
) const
{
scalar val = compareOp<scalar>()(a.value(), b.value());
if (val == 0)
{
return
stringOps::natural_sort::compare(a.name(), b.name()) < 0;
return stringOps::natural_sort::less(a.name(), b.name());
}
return val < 0;
}
@ -78,7 +82,7 @@ namespace Foam
// Check if value is less than upper, with some tolerance.
static inline bool lessThan(const scalar& val, const scalar& upper)
static inline bool lessThan(scalar val, scalar upper)
{
return (val < upper && Foam::mag(val - upper) > ROOTVSMALL);
}

Some files were not shown because too many files have changed in this diff Show More