Commit Graph

1534 Commits

Author SHA1 Message Date
e121db6e86 ENH: extend sigFpe::fillNan() interfaces
- provide separate float/double UList interfaces, which improves
  flexibility (eg, with SPDP)

- sigFpe::fillNan_if() interface, for filling in when using alternative
  memory allocators
2025-03-31 18:50:29 +02:00
e720f823d3 ENH: simplify SubStrings class/handling (remove template parameters)
- previous code used derived string iterators, but these would
  be largely ignored anyhow since the underlying std::sub_match
  str() method would just yields a std::string anyhow.

  The SubStrings::str(size_t) method wasn't used in any code, so now
  just use std::string iterators only.

  This change simplfies overall handling, since it removes an unneeded
  template dependency.
2025-03-31 16:00:07 +02:00
a9863d9a3f ENH: add size_type to Matrix and VectorSpace
- easier to create type-specific looping in templated code

STYLE: pass 'direction' and 'label' by value instead of reference

COMP: qualify Foam::min() in dense matrix classes
2025-03-31 15:58:55 +02:00
bdb890d4e2 COMP: disambiguate pTraits for long/unsigned long on Darwin 2025-03-25 16:02:42 +01:00
aaa9af9ee8 DEFEATURE: remove POSIX regex interface (#3343)
- compiler versions are now sufficient that only the C++ regex
  interface is now being used. Can remove the old POSIX code
  accordingly.

  This change also removes any dependency on the SubStrings class to
  manage the matching results.

ENH: remove OpenFOAM dependencies from MacOS addr2line utility
2025-03-21 14:41:43 +01:00
dcbd546d51 FIX: incorrect parameters for IN_PLACE MPI_Gather, MPI_Scatter
STYLE: mark Pstream::scatterList() as deprecated

- this entry point is not directly used anywhere, only the
  scatterList_algorithm backend is actually used.

  The scatterList() routine is misnomer since it actually works like a
  broadcast that skips overwriting the local rank, but only if used in
  combination with the gatherList() manual implementation that uses
  the same walk pattern.
2025-03-14 17:55:12 +01:00
2d246cd5d1 ENH: add token::read(Istream&) method
- can be used to simplify some logic. For example,

      if
      (
          (tok.read(is) && tok.isWord("FoamFile"))
       && (tok.read(is) && tok.isPunctuation(token::BEGIN_BLOCK))
      )
      ...
  vs
      if
      (
          (is.good() && (is >> tok) && tok.isWord("FoamFile")) ...
       && (is.good() && (is >> tok) && tok.isPunctuation(token::BEGIN_BLOCK))
      ) ...
2025-03-12 20:09:00 +01:00
38e08fc092 COMP: avoid constructor ambiguity for ISpanStream
- compiler cannot decide between std::string and std::string_view
  when creating from 'const char*' without also supplying the size,
  so also supply a 'const char*' constructor.

ENH: additional string_view handling for ITstream and SubStrings
2025-03-12 10:04:43 +01:00
36ae93d017 ENH: components to support one-sided communication 2025-03-10 16:32:35 +01:00
ab7cfdcf49 ENH: add UList move construct and move assignment (shallow copy)
- the 'move' treatment performs a shallow copy but does not alter
  the passed parameter. Identical semantics as per std::span.

ENH: constexpr for basic HashTable constructors

STYLE: 'Foam::zero' instead of 'const Foam::zero' for containers

- this is simply a compiler dispatch flag, so the additional 'const'
  qualifier is unnecessary
2025-03-10 16:32:23 +01:00
f0b844eb47 ENH: generalize MPI broadcast to basic and user-defined MPI types
- simplify and rationalize some of the broadcast methods for more code
  reuse.

  The bottom level UPstream::broadcast is now always to/from "root=0".
  This was previously passed as a default parameter, but never used
  anything other than '0' in the code. Fixing it as '0' makes it
  consistent with the 'top-down' logical for node-based broadcast.
2025-03-06 16:54:31 +01:00
7ac83f22c7 ENH: refine the dataTypes handling
- now distinguish between basic MPI types and user-defined types.

  The new front-facing trait UPstream_basic_dataType unwinds components
  and other types, but only for MPI fundamental types
  (including any aliases)

- additional helper to combine a test for binary operator validity and
  basic data type validity, which better expresses intent:

     template<class BinaryOp, class T>
     UPstream_data_opType;

- relax bit-wise operators to also accept signed integrals
  and 'void' generic
2025-03-06 16:54:31 +01:00
8c395357f3 STYLE: more consistency in communicator types (int vs label) 2025-03-06 16:54:31 +01:00
be30598e3d ENH: add UPstream::localNode_parentProcs() method
- returns the (start/size) range of the commLocalNode ranks in terms
  of the (const) world communicator processors. This allows mapping
  back into lists defined in terms of the world ranks.
2025-03-06 16:54:30 +01:00
d64682a7af ENH: expand VectorSpaceOps to include copy_n/fill_n methods
- similar to what std::copy_n and std::fill_n would do, except with
  templated loops. This allows compile-time transcribing with loop
  unrolling. For example,

     vector vec1 = ..., vec2 = ...;

     FixedList<scalar, 6> values;

     VectorSpaceOps<3>::copy_n(vec1.begin(), values.begin());
     VectorSpaceOps<3>::copy_n(vec2.begin(), values.begin(3))

     // do something with all of these values

STYLE: make start index of VectorSpaceOps optional

ENH: add clamped begin(int) versions to FixedList as per UList
2025-03-06 16:54:30 +01:00
dccdb263e8 ENH: add UPstreamTraits support to map data types and opcodes
The front-end traits:

- UPstream_dataType trait:
  This wrapper is unwinds the type to check against base/alias, but also
  checks if it is a component aggregate of a supported UPstream data type.
  This will be that main entry point for usage.

- UPstream_opType trait:
  Provides a mapping of OpenFOAM ops to their MPI equivalent.
  The \c opcode_id is the corresponding internal representation.

The lower-level traits (not normally used within coding)

- UPstream_base_dataType trait:
  Tests true/false if the specified data type has an internal MPI equivalent.
  The \c datatype_id is the corresponding internal enumeration.
  Even if this tests as false, it will always return \c type_byte as the
  fallback for general contiguous data

- UPstream_alias_dataType trait:
  Provides mapping for <int/long/long long,...> to the fundamental 32/64
  integrals, since <int/long/long long,...> may not otherwise directly map
  on all systems.

NOTE: can use the updates Test-machine-sizes test application to
determine if all data types and aliases are properly defined on
different systems
2025-02-25 10:09:38 +01:00
c448ea2a11 ENH: add simple handling for point-to-point barriers
- provides an additional means of process synchronization
2025-02-25 09:44:44 +01:00
0aecb25024 ENH: update MinMax to accept multiple values for add()
- now also provide its own member data (previously inherited from
  Tuple2) to provide better isolation from future changes
2025-02-24 09:03:19 +01:00
14b2302b38 COMP: remove 'special purpose' minMaxOp (#3326)
- replace with plusOp for reductions. The old use didn't necessarily work
  well with compiler resolution in all cases.
  Simplify to use plusOp (and removed the old version).
  [Does not affect very much code...]

COMP: incorrect include ordering for GeometricFieldFunctions

- header was included after the template code

REGRESSION: combineAllGather mapped to incorrect method (81fa7d08ee)

STYLE: use UPstream::commWarn(...) setter method
2025-02-24 08:57:36 +01:00
d655c2d343 ENH: print node/topology information in human-readable form at startup 2025-02-24 08:56:25 +01:00
81fa7d08ee ENH: extend Pstream gather templates to support combine or assign operation
- eliminates nearly identical code between 'gather' and 'combineGather'

  * Normal gather updates by assigning the result of the binary operation.
  * Combine gather updates by using a binary operator that modifies
    its first parameter in-place

  By-product of this refactoring are these new variants:

      listGather(), listGatherReduce()
      mapGather(), mapGatherReduce()

  that mirror the previously existing ones

      listCombineGather(), listCombineReduce()
      mapCombineGather(), mapCombineReduce()

  except that they use the 'regular' binary operator
2025-02-17 13:40:44 +01:00
eb4345ed44 ENH: misc Pstream adjustments
- additional startup guard for inter-node/local-node queries (UPstream)

- impose linear communication tree for inter-node/local-node
  communicators. Was previously defaulted to a basic tree, but more
  consistent to have flat addressing for these types of connections.

- demand-driven UPstream::interNode_offsets() for walking
  inter-node ranges instead of creating it manually in various places.

- (style): List<int> instead of labelList for internal commsStruct
  since the communication structures are tied to MPI sizes
  and not to the OpenFOAM label sizes

- reduce the number of intermediate buffer allocations within
  gatherList, scatterList.
2025-02-17 13:40:44 +01:00
3e8b0a2c73 ENH: introduce UPstream::commsStructList class
- was previously simply a List<commsStruct>, but now wrap it into a
  class so that the associated communicator index can be easily
  recovered etc.
2025-02-13 12:31:16 +01:00
831a55f1ba ENH: expand UPstream communicator support
- split/duplicate functionality

- rework inter-node/intra-node handling to allow selection of
  splitting based on 'shared' or hostname (default).

- always creates node communicators at startup:
  * commInterNode() - between nodes
  * commLocalNode() - within a node

- world-comm is now always a duplicate of MPI_COMM_WORLD to provide
  better separation from other processes.

NB:
   the inter-node comm is a slight exception to other communicators
   in that we always retain its list of (global) ranks, even if the
   local process is not in that communicator.
   This can help when constructing topology-aware patterns.

FIX: non-participating ranks still had knowledge of their potential siblings

- after create by group, the procIDs_ of non-participating ranks
  should be empty (except for the inter-node exception)
2025-02-13 12:31:12 +01:00
3b40dd8c29 ENH: add prescan handling of -debug-switch etc
- allows use of registered switches before startup of UPstream etc.
2025-02-10 14:27:51 +01:00
0cc5273d0a GIT: cleanup old 'removed' files (ones left only for dependency checks)
GIT: minor directory structure cleanup
2025-02-04 08:27:55 +01:00
cf2b305b4f ENH: upgrade to use some C++17 constructs
- 'if constexpr (...)'
   * instead of std::enable_if
   * terminate template recursion
   * compile-time elimination of code

- use C++14 '_t', '_v' versions,
  eg, std::is_integral_v<T> instead of std::is_integral<T>::value

- std::begin, std::end, std::void_t instead of prev stdFoam versions

- provide is_contiguous_v<..> as short form of is_contiguous<..>::value
  with the additional benefit of removing any cv qualifiers.

ENH: include is_rotational_vectorspace trait

- tests for vector-space and nComponents > 1 (ie, not sphericalTensor)

ENH: improve robustness of pTraits_.. tests by removing cv qualifiers
2025-01-31 09:51:44 +01:00
a18c15a4cf ENH: add VectorSpace component fill() method
- as per std::array and FixedList

STYLE: rename Scalar.[CH] -> scalarImpl.[CH] (these are internal files)

- added inclusion guards to protect against bad use
2025-01-27 10:31:09 +01:00
d3949086ce RELEASE: Updated headers to v2412 2024-12-24 11:17:31 +00:00
009faad912 ENH: Test-GAMG: not normalise agglomeration unless specified 2024-12-14 16:58:28 +00:00
de5d34787c ENH: snappyHexMesh: add buffer layers before snapping 2024-12-12 16:13:32 +00:00
630d60de3b RELEASE: Updated headers to v2406 2024-06-24 09:58:36 +01:00
d859f7b00f ENH: add comparison operators to exprValue, integrate exprValueFieldTag
- exprValueFieldTag is an extended version of exprValue,
  with additional Field/List uniformity handling

- the exprValueFieldTag reduce() method provides a more efficient
  method than using a regular combine operator. Since fields are
  usually non-uniform, will mostly only need the bitwise reduce and
  not a more expensive gather/combine.

ENH: output of exprValue (scalar type) now includes '.'

- prevents scalar/label ambiguity for values like '100.0', which would
  otherwise be written as '100' and thus interpreted as a label value
  when re-reading.
2024-06-10 16:47:09 +02:00
dfc9a8923a ENH: read support for EnSight single-file transient (#3154)
- the ensightReadFile init() now automatically sets up binary/ascii
  (for geometry files) and checks for the transient "BEGIN TIME STEP"
  marker. If found, will also populate the file offsets for each of
  the timesteps.  If no corresponding footer is found (which would be
  very inefficient), it simply pretends that there is only a single
  time step instead of performing a costly file scan.

- parsing of the ensight case file now also supports the use of

      filename numbers:

  as an alternative to

      filename start number:
      filename increment:

- improved parsing robustness of "time values:" entry.
  Can now also have contents on the same line as the introducer.

ENH: base-level adjustments for writing transient single-file

- beginGeometry() is now separated out from file creation.

- in append mode, ensightFile and ensightGeoFile will attempt to
  parse existing time-step information.
2024-05-29 14:04:52 +00:00
ee895577ae ENH: improve OFstream append behaviour (#3160)
- previous support for file appending (largely unused) always
  specified opening with the std::ios_base::app flag.

  Now differentiate between append behaviours:

  APPEND_APP
  ~~~~~~~~~~
  Corresponds to std::ios_base::app behaviour:

  - Existing files will be preserved and a seek-to-end is performed at
    every write. With this mode seeks/repositioning within the file
    will effectively be ignored on output.

  APPEND_ATE
  ~~~~~~~~~~
  Largely approximates std::ios_base::ate behaviour:

  - Existing files will be preserved and a seek-to-end is performed
    immediately after opening, but not subsequently. Can use seekp()
    to overwrite parts of a file.
2024-05-29 14:04:52 +00:00
ffc9894033 STYLE: more consistency in writeEntry() signatures
- boundary entries with writeEntry(const word&, ...) instead of
  writeEntry(const keyType&, ...) to match with most other
  writeEntry() signatures. Also, this content will not be used
  to supply regex matched sub-dictionaries.

STYLE: more consistent patch initEvaluate()/evaluate() coding
2024-05-28 17:50:03 +01:00
bbde236be5 ENH: simpler internal handling of stderr in message streams
- delay construction of message buffer

- OStringStream count() method to test if anything has been streamed

STYLE: explicit use of std::ios_base in IOstreams

- document the return information of set flag methods
2024-05-23 13:51:53 +02:00
3b9176665f ENH: add dictionary::findStream() - symmetric with findDict()
- can be used with this type of code:

  ITstream* streamPtr = dict.findStream(name);
  if (streamPtr)
  {
      auto& is = *streamPtr;
      ...
  }

  versus:

  const entry* eptr = dict.findEntry(name);
  if (eptr && eptr->isStream())
  {
      auto& is = eptr->stream();
      ...
  }

ENH: add findStream(), streamPtr(), isStream() to dictionary search

- symmetric with findDict(), dictPtr(), isDict() methods

STYLE: use findDict() instead of found() + subDict() pairing

COMP: define is_globalIOobject trait at top of IOobject header

- more visibility, permits reuse for specializations etc.
2024-05-23 13:51:53 +02:00
d9c73ae489 ENH: improve handling of multi-pass send/recv (#3152)
- the maxCommsSize variable is used to 'chunk' large data transfers
  (eg, with PstreamBuffers) into a multi-pass send/recv sequence.

  The send/recv windows for chunk-wise transfers:

      iter    data window
      ----    -----------
      0       [0, 1*chunk]
      1       [1*chunk, 2*chunk]
      2       [2*chunk, 3*chunk]
      ...

  Since we mostly send/recv in bytes, the current internal limit
  for MPI counts (INT_MAX) can be hit rather quickly.

  The chunking limit should thus also be INT_MAX, but since it is
  rather tedious to specify such large numbers, can instead use

      maxCommsSize = -1

  to specify (INT_MAX-1) as the limit.
  The default value of maxCommsSize = 0 (ie, no chunking).

Note
~~~~
  In previous versions, the number of chunks was determined by the
  sender sizes. This required an additional MPI_Allreduce to establish
  an overall consistent number of chunks to walk. This additional
  overhead each time meant that maxCommsSize was rarely actually
  enabled.

  We can, however, instead rely on the send/recv buffers having been
  consistently sized and simply walk through the local send/recvs until
  no further chunks need to be exchanged. As an additional enhancement,
  the message tags are connected to chunking iteration, which allows
  the setup of all send/recvs without an intermediate Allwait.

ENH: extend UPstream::probeMessage to use int64 instead of int for sizes
2024-05-07 15:33:02 +02:00
dbfd1f90b1 ENH: add single-time handling to timeSelector
- the timeSelector is often used to select single or multiple times
  (eg, for post-processing). However, there are a few applications
  where only a *single* time should be selected and set.

  These are now covered by this type of use:

      timeSelector::addOptions_singleTime();  // Single-time options
      ...
      // Allow override of time from specified time options, or no-op
      timeSelector::setTimeIfPresent(runTime, args);

   In some cases, if can be desirable to force starting from the
   initial Time=0 when no time options have been specified:

      // Set time from specified time options, or force start from Time=0
      timeSelector::setTimeIfPresent(runTime, args, true);

   These changes make a number of includes redundant:

     * addTimeOptions.H
     * checkConstantOption.H
     * checkTimeOption.H
     * checkTimeOptions.H
     * checkTimeOptionsNoConstant.H

ENH: add time handling to setFields, setAlphaField (#3143)

    Co-authored-by: Johan Roenby <>

STYLE: replace instant("constant") with instant(0, "constant")

- avoids relying on atof parse behaviour returning zero
2024-05-06 22:22:42 +02:00
883196981d ENH: add offset support to stringOps::split functions
- for example,

     string buffer = ...;
     SubStrings<string> split;
     {
         auto colon = buffer.find(':');

         if (colon != std::string::npos)
         {
             split = stringOps::splitSpace(buffer, colon+1);
         }
     }

    Not really possible with a substr() since that would create a new
    temporary which then disappears.  Similarly awkward to split and
    then scan for the ':' to decide how many to discard.

ENH: add pop_front() and pop_back() methods to SubStrings

- the content is trivial enough (a pair of iterators) and the total
  number of elements is usually reasonable short so that removal of
  elements is inexpensive

  For example,

     string buffer = ...;
     auto split = stringOps::splitSpace(buffer);

     if (!split.empty() && split[0].str() == "face")
     {
         split.pop_front();
     }
2024-05-02 17:53:53 +02:00
7b38b148fa STYLE: use PstreamBuffers default construct
- PstreamBuffers are nonBlocking by default, so no need to re-specify
2024-04-29 10:21:25 +02:00
7f355ba343 STYLE: communication name "buffered" instead of "blocking"
- "buffered" corresponds to MPI_Bsend (buffered send),
  whereas the old name "blocking" is misleading since the
  regular MPI_Send also blocks until completion
  (ie, buffer can be reused).

ENH: IPstream::read() returns std::streamsize instead of label (#3152)

- previously returned a 'label' but std::streamsize is consistent with
  the input parameter and will help with later adjustments.

- use <label> instead of <int> for internal accounting of the message
  size, for consistency with the underyling List<char> buffers used.

- improve handling for corner case of IPstream receive with
  non-blocking, although this combination is not used anywhere
2024-04-29 10:19:40 +02:00
411ac5fcfa ENH: adjust return type for token compound factory method
- return autoPtr<token::compound> instead of the derived type,
  otherwise cannot easily construct a token from it

ENH: additional typed version of refCompoundToken()

- symmetric with typed version of transferCompoundToken()
  and isCompound()

- add ITstream::findCompound<Type>() method.
  Useful for searching within token streams
2024-04-23 16:51:38 +02:00
2889dc7248 ENH: add wrapped accessor for MPI_Comm
- UPstream::Communicator is similar to UPstream::Request to
  wrap/unwrap MPI_Comm. Provides a 'lookup' method to transcribe
  the internal OpenFOAM communicator tracking to the opaque wrapped
  version.

- provide an 'openfoam_mpi.H' interfacing file, which includes
  the <mpi.h> as well as casting routines.

  Example (caution: ugly!)

     MPI_Comm myComm =
         PstreamUtils::Cast::to_mpi
         (
             UPstream::Communicator::lookup(UPstream::worldComm)
         );
2024-04-23 10:58:38 +02:00
b5435cc83e ENH: separate registry and revised file locations for finite-area
- The internal storage location of finite-area changes from being
  piggybacked on the polyMesh registry to a having its own dedicated
  registry:

  * allows a clearer separation of field types without name clashes.
  * prerequisite for supporting multiple finite-area regions (future)

Old Locations:
```
   0/Us
   constant/faMesh
   system/faMeshDefinition
   system/faSchemes
   system/faSolution
```

New Locations:
```
   0/finite-area/Us
   constant/finite-area/faMesh
   system/finite-area/faMeshDefinition  (or system/faMeshDefinition)
   system/finite-area/faSchemes
   system/finite-area/faSolution
```

NOTES:
    The new locations represent a hard change (breaking change) that
    is normally to be avoided, but seamless compatibility handling
    within the code was found to be unworkable.

    The `foamUpgradeFiniteArea` script provides assistance with migration.

    As a convenience, the system/faMeshDefinition location continues
    to be supported (may be deprecated in the future).
2024-04-19 17:20:09 +02:00
1b212789e5 ENH: add MeshObject Release() static method
- Delete() will perform a 'checkOut()' which does the following:
  * remove the object from the registry
  * delete the pointer (if owned by the registry)

- Release() does the following:
  * transfer ownership of the pointer (if owned by the registry)

- Store() does the following:
  * transfer ownership of the pointer to the registry

ENH: use UPtrList of sorted objects for MeshObject updates

- few allocations and lower overhead than using a HashTable,
  ensures the same walk order over the objects (in parallel)

STYLE: adjust meshObject debug statements
2024-04-16 10:18:08 +02:00
d578d48a4f ENH: improve findInstance handling for optional files
- previously would always return "constant" as the instance for
  an optional dir/file that wasn't found.
  However, this meant retesting to screen out false positives.
  Now support an additional parameter
      'bool constant_fallback = ...'
  to return "constant" or an empty word.

  The method signature changes slightly with a new optional bool
  parameter:

      //! Return \c "constant" instead of \c "" if the search failed
      const bool constant_fallback = true

ENH: code consolidation for findInstancePath

- relocate from Time to TimePaths and provide an additional static
  version that is reused in fileOperations

BUG: distributedTriSurfaceMesh:::findLocalInstance broken (#3135)

- was not checking the parent at all.

COMP: remove unused findInstancePath(const fileName&, ..) method
2024-04-10 15:55:29 +02:00
0c84e50583 ENH: refine renumberMesh and renumberMethod (addenda to !669)
- provide no_topology() characteristic to avoid triggering potentially
  expensive mesh connectivity calculations when they are not required.

- remove/deprecate unused pointField references from the renumber
  methods. These appear to have crept in from outer similarities
  with decompositionMethod, but have no meaning for renumbering.

- remove/deprecate various unused aggregation renumberings since these
  have been previously replaced by pre-calling calcCellCells, or
  using bandCompression directly.

- make regionFaceOrder for block-wise renumbering optional and
  treat as experimental (ie, default is now disabled).

  The original idea was to sort the intra-region and inter-region faces
  separately. However, this will mostly lead to non-upper triangular
  ordering between regions, which checkMesh and others don't really like.

ENH: add timing information for various renumberMesh stages

ENH: add reset of clockTime and cpuTime increment

- simplifies section-wise timings

ENH: add globalIndex::null() and fieldTypes::processorType conveniences

- provides more central management of these characteristics
2024-03-10 17:45:44 +01:00
61aaacd088 ENH: adjust renumbering methods, extend renumberMesh options
- renumberMesh now has -dry-run, -write-maps, -no-fields,
  -renumber-method, -renumber-coeffs options.

  * Use -dry-run with -write-maps to visualize the before/after
    effects of renumbering (creates a VTK file).

  * -no-fields to renumber the mesh only.
    This is useful and faster when the input fields are uniform
    and the -overwrite option is specified.

  * -renumber-method allows a quick means of specifying a different
    default renumber method (instead of Cuthill-McKee).

    The -renumber-coeffs option allows passing of dictionary content
    for the method.

    Examples,

       // Different ways to specify reverse Cuthill-McKee

       *  -renumber-method RCM
       *  -renumber-coeffs 'reverse true;'
       *  -renumber-method CuthillMcKee
       *  -renumber-coeffs 'reverse true;'
       *  -renumber-coeffs 'method CuthillMcKee; reverse true;'

       // Other (without dictionary coefficients)
       *  renumberMesh -renumber-method random

       // Other (with dictionary coefficients)
       renumberMesh \
           -renumber-method spring \
           -renumber-coeffs 'maxCo 0.1; maxIter 1000; freezeFraction 0.99;'

       // Other (with additional libraries)
       renumberMesh -renumber-method zoltan -lib zoltanRenumber

COMP: build zoltan renumbering to MPI-specific location

- zoltan and Sloan renumbering are now longer automatically linked to
  the renumberMesh utility but must be separately loaded by a
  command-line option or through a dictionary "libs" entry.

ENH: add output cellID for decomposePar -dry-run -cellDist
2024-03-06 17:58:47 +01:00