14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/Convert.h"
16#include "arcane/utils/CheckedConvert.h"
17#include "arcane/utils/Array.h"
18#include "arcane/utils/StringBuilder.h"
19#include "arcane/utils/Iostream.h"
20#include "arcane/utils/ScopedPtr.h"
21#include "arcane/utils/NotImplementedException.h"
22#include "arcane/utils/ArgumentException.h"
24#include "arcane/core/ISubDomain.h"
25#include "arcane/core/IParallelMng.h"
27#include "arcane/core/IMeshSubMeshTransition.h"
28#include "arcane/core/ItemGroup.h"
29#include "arcane/core/Service.h"
30#include "arcane/core/Timer.h"
31#include "arcane/core/FactoryService.h"
32#include "arcane/core/ItemPrinter.h"
33#include "arcane/core/IItemFamily.h"
34#include "arcane/core/MeshVariable.h"
35#include "arcane/core/VariableBuildInfo.h"
36#include "arcane/core/CommonVariables.h"
37#include "arcane/utils/HashTableMap.h"
39#include "arcane_internal_config.h"
42#define MPICH_SKIP_MPICXX
43#define OMPI_SKIP_MPICXX
46#include "arcane/std/MeshPartitionerBase.h"
47#include "arcane/std/ZoltanMeshPartitioner_axl.h"
56#define ARCANE_DEBUG_ZOLTAN
72 ZOLTAN_GRAPH = (1 << 1),
73 ZOLTAN_GEOM = (1 << 2)
88 ZoltanInfo(
MeshPartitionerBase* basePartitionner, ostream* ofile,
int model = 1,
const Real edgeWeightMultiplier = 1.)
90 , m_mesh_partitionner_base(basePartitionner)
96 , m_edge_weight_multiplier(edgeWeightMultiplier)
98 m_own_cells = m_mesh_partitionner_base->mesh()->ownCells();
111 Real m_edge_weight_multiplier;
112 std::set<std::pair<Int64, Int64>> m_weight_set;
118 info() <<
"ZoltanInfo::build()";
119 if (m_model & ZOLTAN_GEOM)
122 Integer nbOwnCells = m_own_cells.size();
125 if (m_model & ZOLTAN_HG) {
126 nbOwnEdges += nbOwnCells;
128 if (m_model & ZOLTAN_GRAPH) {
130 nbOwnEdges += nbOwnCells * 6;
134 IParallelMng* pm = m_mesh_partitionner_base->mesh()->parallelMng();
137 scanouille[pm->
commRank()] = nbOwnEdges;
140 for (
int i = 0; i < pm->
commRank(); ++i) {
141 m_edgeGIDStart += scanouille[i];
147 if (!m_mesh_partitionner_base->cellUsedWithConstraints(*iCell))
150 int nbNgb = m_mesh_partitionner_base->nbNeighbourCellsWithConstraints(*iCell);
151 if (m_model & ZOLTAN_HG) {
153 m_nbPins += nbNgb + 1;
155 if (m_model & ZOLTAN_GRAPH) {
157 m_nbPins += (nbNgb * 2);
161 info() <<
"nbEdges=" << m_nbEdges <<
" ; nbPins=" << m_nbPins;
163 if (m_mesh_partitionner_base->haveWeakConstraints()) {
165 ENUMERATE_FACE (iface, m_mesh_partitionner_base->mesh()->ownFaces()) {
166 const Face& face = *iface;
167 const Cell& bCell = iface->backCell();
168 const Cell& fCell = iface->frontCell();
171 if (weak_constraint[face] == 2) {
181 static int getHgNumVertices(
void* data,
int* ierr)
185 ZoltanInfo* zi = (ZoltanInfo*)data;
196 return zi->m_mesh_partitionner_base->nbOwnCellsWithConstraints();
199 static void getHgVerticesAndWeights(
void* data,
int num_gid_entries,
200 int num_lid_entries, ZOLTAN_ID_PTR gids, ZOLTAN_ID_PTR lids,
201 int wgt_dim,
float* obj_weights,
int* ierr)
203 ARCANE_UNUSED(num_gid_entries);
204 ARCANE_UNUSED(num_lid_entries);
206 ZoltanInfo* zi = (ZoltanInfo*)data;
219 if (zi->m_mesh_partitionner_base->nbCellWeight() <= wgt_dim) {
220 cells_weights = zi->m_mesh_partitionner_base->cellsWeightsWithConstraints(wgt_dim);
224 cells_weights = zi->m_mesh_partitionner_base->cellsSizeWithConstraints();
227 view_weights.
copy(cells_weights);
232 if (!zi->m_mesh_partitionner_base->cellUsedWithConstraints(*icell))
235 gids[index] = (*icell).uniqueId().asInt32();
236 lids[index] = zi->m_mesh_partitionner_base->localIdWithConstraints(*icell);
239 for (
int j = 0; j < wgt_dim; ++j) {
240 float weight = cells_weights[lids[index] * wgt_dim + j];
241 *obj_weights++ = weight;
243 (*zi->m_ofile) <<
" Weight uid=" << gids[index] <<
" w=" << weight <<
'\n';
251 static void getHgSizeAndFormat(
void* data,
int* num_lists,
int* num_pins,
int* format,
int* ierr)
253 ZoltanInfo* zi = (ZoltanInfo*)data;
255 zi->
info() <<
" ZoltanInfo::getHgSizeAndFormat() ";
264 *format = ZOLTAN_COMPRESSED_EDGE;
265 *num_pins = zi->m_nbPins;
266 *num_lists = zi->m_nbEdges;
271 zi->
info() <<
" ZoltanInfo::getHgSizeAndFormat() " <<
" num_list= " << *num_lists <<
" num_pins= " << *num_pins;
275 static void getHg(
void* data,
int num_gid_entries,
276 int nrowcol,
int npins,
int format,
277 ZOLTAN_ID_PTR z_vtxedge_GID,
int* z_vtxedge_ptr, ZOLTAN_ID_PTR z_pin_GID,
int* ierr)
279 ZoltanInfo* zi = (ZoltanInfo*)data;
281 zi->
info() <<
" ZoltanInfo::getHg() "
282 <<
" num_gid_entries= " << num_gid_entries
283 <<
" nrowcol= " << nrowcol
284 <<
" npins= " << npins
285 <<
" format= " << format;
292 int gid = zi->m_edgeGIDStart;
293 z_vtxedge_ptr[0] = 0;
295 const Cell& item = *i_item;
297 if (!zi->m_mesh_partitionner_base->cellUsedWithConstraints(item))
300 neighbour_cells.
resize(0);
301 zi->m_mesh_partitionner_base->getNeighbourCellsUidWithConstraints(item,
304 if (zi->m_model & ZOLTAN_HG) {
305 for (
Integer z = 0; z < neighbour_cells.
size(); ++z)
306 z_pin_GID[indexPin++] = CheckedConvert::toInteger(neighbour_cells[z]);
307 z_pin_GID[indexPin++] = item.
uniqueId().asInt32();
308 z_vtxedge_GID[indexEdge] = gid++;
310 z_vtxedge_ptr[indexEdge + 1] = z_vtxedge_ptr[indexEdge] + neighbour_cells.
size() + 1;
314 if (zi->m_model & ZOLTAN_GRAPH) {
317 for (
Integer z = 0; z < neighbour_cells.
size(); ++z) {
318 z_pin_GID[indexPin++] = CheckedConvert::toInteger(neighbour_cells[z]);
319 z_pin_GID[indexPin++] = (item.
uniqueId().asInt32());
320 z_vtxedge_GID[indexEdge] = gid++;
321 z_vtxedge_ptr[indexEdge + 1] = z_vtxedge_ptr[indexEdge] + 2;
327 for (
int i = 0; i < nrowcol; ++i) {
328 (*zi->m_ofile) <<
"*topo GID " << z_vtxedge_GID[i]
329 <<
" : " << z_vtxedge_ptr[i + 1] - z_vtxedge_ptr[i];
330 for (
int j = z_vtxedge_ptr[i]; j < z_vtxedge_ptr[i + 1]; ++j) {
331 (*zi->m_ofile) <<
'\t' << z_pin_GID[j];
333 (*zi->m_ofile) <<
'\n';
345 static void getHgVertexSizes(
void* data,
int num_gid_entries,
int num_lid_entries,
346 int num_ids, ZOLTAN_ID_PTR global_ids, ZOLTAN_ID_PTR local_ids,
347 int* sizes,
int* ierr)
349 ARCANE_UNUSED(num_gid_entries);
350 ARCANE_UNUSED(num_lid_entries);
351 ARCANE_UNUSED(global_ids);
353 ZoltanInfo* zi = (ZoltanInfo*)data;
355 SharedArray<float> cellSizes = zi->m_mesh_partitionner_base->cellsSizeWithConstraints();
357 for (
int i = 0; i < num_ids; ++i) {
364 static void getHgEdgeWeightSize(
void* data,
int* num_edges,
int* ierr)
366 ZoltanInfo* zi = (ZoltanInfo*)data;
377 *num_edges = zi->m_nbEdges;
381 static void getHgEdgeWeights(
void* data,
int num_gid_entries,
382 int num_lid_entries,
int nedges,
int edge_weight_dim,
383 ZOLTAN_ID_PTR edge_GID, ZOLTAN_ID_PTR edge_LID,
float* edge_weight,
int* ierr)
385 ARCANE_UNUSED(num_lid_entries);
387 ZoltanInfo* zi = (ZoltanInfo*)data;
393 zi->
info() <<
" ZoltanInfo::getHgEdgeWeights() "
394 <<
" num_gid_entries= " << num_gid_entries
395 <<
" nedges= " << nedges
396 <<
" edge_weight_dim= " << edge_weight_dim;
401 connectivityWeights.
reserve(6);
407 if (!zi->m_mesh_partitionner_base->cellUsedWithConstraints(item))
410 connectivityWeights.
resize(0);
411 neighbour_cells.
resize(0);
412 bool hg_model = (zi->m_model & ZOLTAN_HG);
415 zi->m_mesh_partitionner_base->getNeighbourCellsUidWithConstraints(item,
416 neighbour_cells, &connectivityWeights, hg_model);
418 if (zi->m_model & ZOLTAN_HG) {
419 if (!(zi->m_model & ZOLTAN_GRAPH)) {
421 for (
Integer z = 0; z < neighbour_cells.
size(); ++z) {
422 he_weight += connectivityWeights[z];
425 edge_GID[indexEdge] = indexEdge + zi->m_edgeGIDStart;
426 edge_LID[indexEdge] = indexEdge;
427 edge_weight[indexEdge++] = (float)he_weight;
430 if (zi->m_model & ZOLTAN_GRAPH) {
433 for (
Integer z = 0; z < neighbour_cells.
size(); ++z) {
434 edge_GID[indexEdge] = indexEdge + zi->m_edgeGIDStart;
435 edge_LID[indexEdge] = indexEdge;
436 Real w = connectivityWeights[z];
437 edge_weight[indexEdge] = (float)w;
438 if (zi->m_mesh_partitionner_base->haveWeakConstraints()) {
439 std::pair<Int64, Int64> items(item.
uniqueId(), neighbour_cells[z]);
440 if (zi->m_mesh_partitionner_base->cellUsedWithWeakConstraints(items)) {
441 edge_weight[indexEdge] *= (float)zi->m_edge_weight_multiplier;
452 static int get_num_geometry(
void* data,
int* ierr)
460 static void get_geometry_list(
void* data,
int sizeGID,
int sizeLID,
462 ZOLTAN_ID_PTR global_ids, ZOLTAN_ID_PTR local_ids,
463 int num_dim,
double* geom_vec,
int* ierr)
465 ARCANE_UNUSED(global_ids);
466 ARCANE_UNUSED(local_ids);
468 ZoltanInfo* zi = (ZoltanInfo*)data;
470 if ((sizeGID != 1) || (sizeLID != 1) || (num_dim > 3)) {
471 *ierr = ZOLTAN_FATAL;
479 if (!zi->m_mesh_partitionner_base->cellUsedWithConstraints(*icell))
486 for (
Integer z = 0, zs = (*icell).nbNode(); z < zs; ++z) {
487 const Node& node = (*icell).node(z);
492 geom_vec[num_dim * i] = bar.x;
493 geom_vec[num_dim * i + 1] = bar.y;
494 geom_vec[num_dim * i + 2] = bar.z;
499 if (!s.
null() && (s ==
"MYGEOM")) {
500 for (
int i = 0; i < num_obj; ++i) {
501 geom_vec[num_dim * i + num_dim - 1] = 0.0;
516class ZoltanMeshPartitioner
540ZoltanMeshPartitioner::
541ZoltanMeshPartitioner(
const ServiceBuildInfo& sbi)
542: ArcaneZoltanMeshPartitionerObject(sbi)
552 Int32 nb_part =
mesh()->parallelMng()->commSize();
562 info() <<
"Load balancing with Zoltan\n";
566 int rc = ::Zoltan_Initialize(0, 0, &ver);
567 Zoltan_Memory_Debug(2);
569 fatal() <<
"Can not initialize zoltan (r=" << rc <<
")";
574 if (nb_part < nb_rank)
578 warning() <<
"Unable to test load balancing on a single sub-domain";
582 Integer nb_weight = nbCellWeight();
584 struct Zoltan_Struct* zz;
589 ZOLTAN_ID_PTR importGlobalIds;
590 ZOLTAN_ID_PTR importLocalIds;
594 ZOLTAN_ID_PTR exportGlobalIds;
605 zz = Zoltan_Create(*(MPI_Comm*)getCommunicator());
607 Zoltan_Set_Param(zz,
"RCB_REUSE",
"1");
616 if (!s.null() &&
options()->model.isPresent())
617 fatal() <<
"Conflicting configuration between ZOLTAN_MODEL environment variable and user data set";
618 usePHG =
options()->useHypergraphe();
630 if (subDomain()->commonVariables().globalIteration() <= 2)
636 String algo =
"HYPERGRAPH";
637 if (s ==
"MYHG" || s ==
"OLDHG" || s ==
"DUALHG" || s ==
"GRAPH") {
641 else if (s ==
"RIB" || s ==
"HSFC") {
645 else if (s ==
"RCB" || s ==
"MYGEOM") {
650 fatal() <<
"Undefined zoltan model '" << s <<
"'";
653 int model = ZOLTAN_HG;
654 if (usePHG ==
false) {
659 model |= ZOLTAN_GRAPH;
661 else if (s ==
"GRAPH") {
662 model = ZOLTAN_GRAPH;
669 Real edgeWeightMultiplier = 1;
670 Integer repartitionFrequency = 10;
671 Real imbalanceTol = 1.05;
672 Real phgRepartMultiplier = 10;
677 edgeWeightMultiplier =
options()->edgeWeightMultiplier();
678 repartitionFrequency =
options()->repartFrequency();
679 imbalanceTol =
options()->imbalanceTol();
680 phgRepartMultiplier =
options()->phgRepartMultiplier();
681 phgOutputLevel =
options()->phgOutputLevel();
682 debugLevel =
options()->debugLevel();
686 info() <<
"Zoltan: utilise un repartitionnement " << algo <<
" (" << s <<
").";
687 Zoltan_Set_Param(zz,
"LB_METHOD", algo.localstr());
688 Zoltan_Set_Param(zz,
"HYPERGRAPH_PACKAGE",
"PHG");
690 if (
mesh->subDomain()->commonVariables().globalIteration() == 1) {
691 Zoltan_Set_Param(zz,
"LB_APPROACH",
"PARTITION");
692 info() <<
"Zoltan: Partition";
694 else if (
mesh->subDomain()->commonVariables().globalIteration() % repartitionFrequency == 0 && repartitionFrequency != -1) {
695 Zoltan_Set_Param(zz,
"LB_APPROACH",
"REPARTITION");
696 info() <<
"Zoltan: Repartition";
699 Zoltan_Set_Param(zz,
"LB_APPROACH",
"REFINE");
700 info() <<
"Zoltan: Refine";
703 String s_imbalaceTol(String::fromNumber(imbalanceTol));
704 Zoltan_Set_Param(zz,
"IMBALANCE_TOL", s_imbalaceTol.localstr());
706 String s_nb_part(String::fromNumber(nb_part));
707 Zoltan_Set_Param(zz,
"NUM_GLOBAL_PARTS", s_nb_part.localstr());
709 Zoltan_Set_Param(zz,
"NUM_GID_ENTRIES",
"1");
710 Zoltan_Set_Param(zz,
"NUM_LID_ENTRIES",
"1");
711 Zoltan_Set_Param(zz,
"RETURN_LISTS",
"EXPORT");
712 String s_nb_weight(String::fromNumber(nb_weight));
714 Zoltan_Set_Param(zz,
"OBJ_WEIGHT_DIM", s_nb_weight.localstr());
717 Zoltan_Set_Param(zz,
"ADD_OBJ_WEIGHT",
"NONE");
721 Zoltan_Set_Param(zz,
"FINAL_OUTPUT",
"0");
722 Zoltan_Set_Param(zz,
"PHG_USE_TIMERS",
"1");
724 String s_phgOutputLevel(String::fromNumber(phgOutputLevel));
725 Zoltan_Set_Param(zz,
"PHG_OUTPUT_LEVEL", s_phgOutputLevel.localstr());
728 Zoltan_Set_Param(zz,
"CHECK_HYPERGRAPH",
"0");
729 String s_debugLevel(String::fromNumber(debugLevel));
730 Zoltan_Set_Param(zz,
"DEBUG_LEVEL", s_debugLevel.localstr());
735 Zoltan_Set_Param(zz,
"PHG_COARSENING_METHOD",
"IPM");
739 Zoltan_Set_Param(zz,
"EDGE_WEIGHT_DIM",
"1");
740 Zoltan_Set_Param(zz,
"PHG_EDGE_WEIGHT_OPERATION",
"add");
742 if (!initial_partition) {
745 String s_phgRepartMultiplier(String::fromNumber(phgRepartMultiplier));
746 Zoltan_Set_Param(zz,
"PHG_REPART_MULTIPLIER", s_phgRepartMultiplier.localstr());
750 Zoltan_Set_Param(zz,
"KEEP_CUTS",
"0");
751 Zoltan_Set_Param(zz,
"RCB_OUTPUT_LEVEL",
"0");
752 Zoltan_Set_Param(zz,
"RCB_RECTILINEAR_BLOCKS",
"0");
755 Zoltan_Set_Param(zz,
"OBJ_WEIGHTS_COMPARABLE",
"0");
759 Zoltan_Set_Param(zz,
"RCB_MULTICRITERIA_NORM",
"3");
760 Zoltan_Set_Param(zz,
"RCB_MAX_ASPECT_RATIO",
"10");
763 bool dump_infos =
false;
769 Integer iteration =
mesh->subDomain()->commonVariables().globalIteration();
775 ofile.open(f.localstr());
787 ScopedPtrT<ZoltanInfo> zoltan_info(
new ZoltanInfo(
this, zofile, model, edgeWeightMultiplier));
788 Zoltan_Set_Num_Obj_Fn(zz, &ZoltanInfo::getHgNumVertices, zoltan_info.get());
789 Zoltan_Set_Obj_List_Fn(zz, &ZoltanInfo::getHgVerticesAndWeights, zoltan_info.get());
790 if (!initial_partition) {
791 Zoltan_Set_Obj_Size_Multi_Fn(zz, &ZoltanInfo::getHgVertexSizes,
795 info() <<
"Setting up HG Callbacks";
796 Zoltan_Set_HG_Size_CS_Fn(zz, &ZoltanInfo::getHgSizeAndFormat, zoltan_info.get());
797 Zoltan_Set_HG_CS_Fn(zz, &ZoltanInfo::getHg, zoltan_info.get());
798 Zoltan_Set_HG_Size_Edge_Weights_Fn(zz, &ZoltanInfo::getHgEdgeWeightSize, zoltan_info.get());
799 Zoltan_Set_HG_Edge_Weights_Fn(zz, &ZoltanInfo::getHgEdgeWeights, zoltan_info.get());
802 info() <<
"Setting up Geom Callbacks";
803 Zoltan_Set_Num_Geom_Fn(zz, ZoltanInfo::get_num_geometry, zoltan_info.get());
804 Zoltan_Set_Geom_Multi_Fn(zz, ZoltanInfo::get_geometry_list, zoltan_info.get());
809 int* export_partitions = 0;
810 ZOLTAN_ID_PTR export_local_ids = 0;
812 info() <<
"Doing partition";
813 rc = Zoltan_LB_Partition(zz, &changes, &numGidEntries, &numLidEntries,
814 &numImport, &importGlobalIds, &importLocalIds,
815 &importProcs, &importToPart,
816 &numExport, &exportGlobalIds, &export_local_ids,
817 &exportProcs, &export_partitions);
822 cells_new_owner[icell] = (*icell).owner();
825 invertArrayLid2LidCompacted();
828 CellInfoListView items_internal(m_cell_family);
830 info() <<
"numExport = " << numExport;
831 for (
Integer i = 0; i < nb_export; ++i) {
832 Item item = items_internal[localIdWithConstraints(export_local_ids[i])];
834 changeCellOwner(item, cells_new_owner, export_partitions[i]);
836 ofile <<
"EXPORT: uid=" << ItemPrinter(item) <<
" OLD=" << item.owner()
837 <<
" NEW=" << cells_new_owner[item] <<
" PROC=" << exportProcs[i] <<
'\n';
851 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
854 Zoltan_LB_Free_Part(&exportGlobalIds, &export_local_ids,
855 &exportProcs, &export_partitions);
862 cells_new_owner.synchronize();
883#if ARCANE_DEFAULT_PARTITIONER == ZOLTAN_DEFAULT_PARTITIONER
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro to declare an interface when registering a service.
Integer size() const
Number of elements in the vector.
CaseOptionsZoltanMeshPartitioner * options() const
Options du jeu de données du service.
ArcaneZoltanMeshPartitionerObject(const Arcane::ServiceBuildInfo &sbi)
Constructeur.
Exception when an argument is invalid.
Modifiable view of an array of type T.
void copy(const U ©_array)
Copies the array copy_array into the instance.
void fill(ConstReferenceType value)
Fills the array with the value value.
void resize(Int64 s)
Changes the number of elements in the array to s.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
Cell frontCell() const
Cell in front of the face (null cell if none).
Cell backCell() const
Cell behind the face (null cell if none).
virtual ITraceMng * traceMng()=0
Associated message manager.
Interface of a mesh partitioner.
Interface of a mesh partitioner.
virtual IMesh * mesh() const =0
Mesh associated with the partitioner.
virtual VariableNodeReal3 & nodesCoordinates()=0
Node coordinates.
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual void scan(eReduceType rt, ArrayView< char > v)=0
Applies a prefix-sum algorithm on the values of v using the rt operation.
virtual Int32 commSize() const =0
Number of instances in the communicator.
virtual void barrier()=0
Performs a barrier.
ItemUniqueId uniqueId() const
Unique identifier across all domains.
constexpr bool null() const
true if the entity is null (i.e. not connected to the mesh)
Base class for a load balancing service.
IMesh * mesh() const override
Mesh associated with the partitioner.
virtual void changeOwnersFromCells()
Positions the new owners of nodes, edges and faces based on the cells.
Scalar variable on a mesh entity type.
Class managing a 3-dimensional real vector.
Structure containing the information to create a service.
Service creation properties.
1D vector of data with reference semantics.
Unicode character string.
bool null() const
Returns true if the string is null.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage fatal() const
Flow for a fatal error message.
TraceMessage info() const
Flow for an information message.
TraceMessage warning() const
Flow for a warning message.
1D data vector with value semantics (STL style).
Parameters necessary for building a variable.
Mesh partitioner using the Zoltan library.
virtual void notifyEndPartition()
Notification when a re-partitioning finishes (after entity exchange).
virtual void build()
Build-level construction of the service.
virtual void partitionMesh(bool initial_partition)
ItemGroupT< Cell > CellGroup
Group of cells.
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro for registering a service.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
ItemVariableScalarRefT< Int32 > VariableItemInt32
32-bit integer type quantity
Integer toInteger(Real r)
Converts a Real to Integer.
double toDouble(Real r)
Converts a Real to double.
@ ReduceSum
Sum of values.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
Int32 Integer
Type representing an integer.
@ ST_SubDomain
The service is used at the subdomain level.
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
@ IK_Cell
Cell mesh entity.
double Real
Type representing a real number.
std::int32_t Int32
Signed integer type of 32 bits.