preCICE
Loading...
Searching...
No Matches
MappingConfiguration.cpp
Go to the documentation of this file.
2#include <Eigen/Core>
3#include <algorithm>
4#include <cstring>
5#include <list>
6#include <memory>
7#include <ostream>
8#include <utility>
9#include <variant>
10#include "logging/LogMacros.hpp"
14#include "mapping/Mapping.hpp"
24#include "mesh/Mesh.hpp"
27#include "utils/Parallel.hpp"
28#include "utils/Petsc.hpp"
29#include "utils/assertion.hpp"
30#include "xml/ConfigParser.hpp"
31#include "xml/XMLAttribute.hpp"
32#include "xml/XMLTag.hpp"
33namespace precice::mapping {
34
35namespace {
36
37// given a list of subtags and parent tags, this function adds all subtags to all
38// parent tags
39void addSubtagsToParents(std::list<xml::XMLTag> &subtags,
40 std::list<xml::XMLTag> &parents)
41{
42 for (auto &p : parents) {
43 p.addSubtags(subtags);
44 }
45}
46
47// this function uses std::variant in order to add attributes of any type (double, string, bool)
48// to all tags in the list of tags \p storage.
49using variant_t = std::variant<xml::XMLAttribute<double>, xml::XMLAttribute<std::string>, xml::XMLAttribute<bool>, xml::XMLAttribute<int>>;
50template <typename TagStorage>
51void addAttributes(TagStorage &storage, const std::vector<variant_t> &attributes)
52{
53 for (auto &s : storage) {
54 for (auto &a : attributes)
55 std::visit([&s](auto &&arg) { s.addAttribute(arg); }, a);
56 }
57}
58
59// Enum required for the RBF instantiations
60enum struct RBFBackend {
61 Eigen,
62 PETSc,
63 Ginkgo,
64 PUM
65};
66
67// Helper in order to resolve the template instantiations.
68// Only the template specializations are of interest
69template <RBFBackend Backend, typename RBF>
70struct BackendSelector {
71 typedef RBF type;
72};
73
74// Specialization for the RBF Eigen backend
75template <typename RBF>
76struct BackendSelector<RBFBackend::Eigen, RBF> {
77 typedef mapping::RadialBasisFctMapping<RadialBasisFctSolver<RBF>> type;
78};
79
80// Specialization for the PETSc RBF backend
81#ifndef PRECICE_NO_PETSC
82template <typename RBF>
83struct BackendSelector<RBFBackend::PETSc, RBF> {
84 typedef mapping::PetRadialBasisFctMapping<RBF> type;
85};
86#endif
87
88// Specialization for the Ginkgo RBF backend
89#ifndef PRECICE_NO_GINKGO
90template <typename RBF>
91struct BackendSelector<RBFBackend::Ginkgo, RBF> {
92 typedef mapping::RadialBasisFctMapping<GinkgoRadialBasisFctSolver<RBF>, MappingConfiguration::GinkgoParameter> type;
93};
94#endif
95// Specialization for the RBF PUM backend
96template <typename RBF>
97struct BackendSelector<RBFBackend::PUM, RBF> {
98 typedef mapping::PartitionOfUnityMapping<RBF> type;
99};
100
101// Variant holding all available RBF classes
102using rbf_variant_t = std::variant<CompactPolynomialC0, CompactPolynomialC2, CompactPolynomialC4, CompactPolynomialC6, CompactPolynomialC8, CompactThinPlateSplinesC2, ThinPlateSplines, VolumeSplines, Multiquadrics, InverseMultiquadrics, Gaussian>;
103
104// The actual instantiation of the mapping class, which is called by the visitor \ref getRBFMapping
105template <RBFBackend T, typename RADIAL_BASIS_FUNCTION_T, typename... Args>
106PtrMapping instantiateRBFMapping(mapping::Mapping::Constraint &constraint, int dimension, RADIAL_BASIS_FUNCTION_T function,
107 Args &&...args)
108{
109 return PtrMapping(new typename BackendSelector<T, RADIAL_BASIS_FUNCTION_T>::type(constraint, dimension, function, std::forward<Args>(args)...));
110}
111
112// Constructs the RBF function based on the functionType
113rbf_variant_t constructRBF(BasisFunction functionType, double supportRadius, double shapeParameter)
114{
115 try {
116 switch (functionType) {
118 return mapping::CompactPolynomialC0(supportRadius);
119 }
121 return mapping::CompactPolynomialC2(supportRadius);
122 }
124 return mapping::CompactPolynomialC4(supportRadius);
125 }
127 return mapping::CompactPolynomialC6(supportRadius);
128 }
130 return mapping::CompactPolynomialC8(supportRadius);
131 }
133 return mapping::CompactThinPlateSplinesC2(supportRadius);
134 }
137 }
139 return mapping::VolumeSplines();
140 }
142 return mapping::Multiquadrics(shapeParameter);
143 }
145 return mapping::InverseMultiquadrics(shapeParameter);
146 }
148 return mapping::Gaussian(shapeParameter);
149 }
150 default:
151 PRECICE_UNREACHABLE("No instantiation was found for the selected basis function.");
152 }
153 } catch (std::invalid_argument &e) {
154 logging::Logger _log{"MappingConfiguration"};
155 PRECICE_ERROR(e.what());
156 }
157}
158
159// The actual instantion helper, which avoids enumerating all mapping implementations (more will come) with all RBF kernels
160// The first three arguments of the constructor are prescribed: constraint, dimension and the RBF function object, all other
161// constructor arguments are just forwarded. The first argument (BasisFunction) indicates then the actual instantiation to return.
162template <RBFBackend T, typename... Args>
163PtrMapping getRBFMapping(BasisFunction functionType, mapping::Mapping::Constraint &constraint, int dimension, double supportRadius, double shapeParameter,
164 Args &&...args)
165{
166 // First, construct the RBF function
167 auto functionVariant = constructRBF(functionType, supportRadius, shapeParameter);
168 // ... and instantiate the corresponding RBF mapping class
169 return std::visit([&](auto &&func) { return instantiateRBFMapping<T>(constraint, dimension, func, std::forward<Args>(args)...); }, functionVariant);
170}
171} // namespace
172
174 xml::XMLTag &parent,
175 mesh::PtrMeshConfiguration meshConfiguration)
176 : _meshConfig(std::move(meshConfiguration))
177{
179 using namespace xml;
180
181 // First, we create the available tags
182 XMLTag::Occurrence occ = XMLTag::OCCUR_ARBITRARY;
183 std::list<XMLTag> projectionTags{
184 XMLTag{*this, TYPE_NEAREST_NEIGHBOR, occ, TAG}.setDocumentation("Nearest-neighbour mapping which uses a rstar-spatial index tree to index meshes and run nearest-neighbour queries."),
185 XMLTag{*this, TYPE_NEAREST_PROJECTION, occ, TAG}.setDocumentation("Nearest-projection mapping which uses a rstar-spatial index tree to index meshes and locate the nearest projections."),
186 XMLTag{*this, TYPE_NEAREST_NEIGHBOR_GRADIENT, occ, TAG}.setDocumentation("Nearest-neighbor-gradient mapping which uses nearest-neighbor mapping with an additional linear approximation using gradient data."),
187 XMLTag{*this, TYPE_LINEAR_CELL_INTERPOLATION, occ, TAG}.setDocumentation("Linear cell interpolation mapping which uses a rstar-spatial index tree to index meshes and locate the nearest cell. Only supports 2D meshes.")};
188 std::list<XMLTag> rbfDirectTags{
189 XMLTag{*this, TYPE_RBF_GLOBAL_DIRECT, occ, TAG}.setDocumentation("Radial-basis-function mapping using a direct solver with a gather-scatter parallelism.")};
190 std::list<XMLTag> rbfIterativeTags{
191 XMLTag{*this, TYPE_RBF_GLOBAL_ITERATIVE, occ, TAG}.setDocumentation("Radial-basis-function mapping using an iterative solver with a distributed parallelism.")};
192 std::list<XMLTag> pumDirectTags{
193 XMLTag{*this, TYPE_RBF_PUM_DIRECT, occ, TAG}.setDocumentation("Radial-basis-function mapping using a partition of unity method, which supports a distributed parallelism.")};
194 std::list<XMLTag> rbfAliasTag{
195 XMLTag{*this, TYPE_RBF_ALIAS, occ, TAG}.setDocumentation("Alias tag, which auto-selects a radial-basis-function mapping depending on the simulation parameter,")};
196 std::list<XMLTag> coarseGrainingTags{
197 XMLTag{*this, TYPE_COARSE_GRAINING, occ, TAG}.setDocumentation("Coarse graining specifically designed for particle-mesh coupling to write data from the particles to the mesh. The mapping transforms an extensive quantity (e.g., volume, force) into an intensive quantity (e.g., porosity, force-density). "
198 " Currently implemented as just-in-time mapping. Although the constraint does not really fit here (the input is conservative, the output not), we classify it as \"conservative\" for the configuration.")};
199 std::list<XMLTag> axialGeoMultiscaleTags{
200 XMLTag{*this, TYPE_AXIAL_GEOMETRIC_MULTISCALE, occ, TAG}
201 .setDocumentation("Axial geometric multiscale mapping between one 1D and multiple 3D vertices.")};
202 std::list<XMLTag> radialGeoMultiscaleTags{
203 XMLTag{*this, TYPE_RADIAL_GEOMETRIC_MULTISCALE, occ, TAG}
204 .setDocumentation("Radial geometric multiscale mapping between multiple 1D and multiple 3D vertices, distributed along a principle axis.")};
205
206 // List of all attributes with corresponding documentation
207 auto attrDirection = XMLAttribute<std::string>(ATTR_DIRECTION)
208 .setOptions({DIRECTION_WRITE, DIRECTION_READ})
209 .setDocumentation("Write mappings map written data prior to communication, thus in the same participant who writes the data. "
210 "Read mappings map received data after communication, thus in the same participant who reads the data.");
211
212 auto attrFromMesh = XMLAttribute<std::string>(ATTR_FROM, "")
213 .setDocumentation("The mesh to map the data from. The default name is an empty mesh name, which is only valid for a just-in-time mapping (using the API functions \"writeAndMapData\" or \"mapAndReadData\").");
214
215 auto attrToMesh = XMLAttribute<std::string>(ATTR_TO, "")
216 .setDocumentation("The mesh to map the data to. The default name is an empty mesh name, which is only valid for a just-in-time mapping (using the API functions \"writeAndMapData\" or \"mapAndReadData\").");
217
218 auto attrConstraint = XMLAttribute<std::string>(ATTR_CONSTRAINT)
219 .setDocumentation("Use conservative to conserve the nodal sum of the data over the interface (needed e.g. for force mapping). Use consistent for normalized quantities such as temperature or pressure. Use scaled-consistent-surface or scaled-consistent-volume for normalized quantities where conservation of integral values (surface or volume) is needed (e.g. velocities when the mass flow rate needs to be conserved). Mesh connectivity is required to use scaled-consistent.")
221 auto attrXDead = makeXMLAttribute(ATTR_X_DEAD, false)
222 .setDocumentation("If set to true, the x axis will be ignored for the mapping");
223 auto attrYDead = makeXMLAttribute(ATTR_Y_DEAD, false)
224 .setDocumentation("If set to true, the y axis will be ignored for the mapping");
225 auto attrZDead = makeXMLAttribute(ATTR_Z_DEAD, false)
226 .setDocumentation("If set to true, the z axis will be ignored for the mapping");
227 auto attrPolynomial = makeXMLAttribute(ATTR_POLYNOMIAL, POLYNOMIAL_SEPARATE)
228 .setDocumentation("Toggles use of the global polynomial")
230 auto attrPumPolynomial = makeXMLAttribute(ATTR_POLYNOMIAL, POLYNOMIAL_SEPARATE)
231 .setDocumentation("Toggles use a local (per cluster) polynomial")
232 .setOptions({POLYNOMIAL_OFF, POLYNOMIAL_SEPARATE});
233
234 auto attrcgRadius = makeXMLAttribute<double>(ATTR_CG_RADIUS, 0.)
235 .setDocumentation("Radius or range of the coarsening function (Lucy function).");
236
237 auto attrSolverRtol = makeXMLAttribute(ATTR_SOLVER_RTOL, 1e-9)
238 .setDocumentation("Solver relative tolerance for convergence");
239 // TODO: Discuss whether we wanto to introduce this attribute
240 // auto attrMaxIterations = makeXMLAttribute(ATTR_MAX_ITERATIONS, 1e6)
241 // .setDocumentation("Maximum number of iterations of the solver");
242
243 auto verticesPerCluster = XMLAttribute<int>(ATTR_VERTICES_PER_CLUSTER, 50)
244 .setDocumentation("Average number of vertices per cluster (partition) applied in the rbf partition of unity method.");
245 auto relativeOverlap = makeXMLAttribute(ATTR_RELATIVE_OVERLAP, 0.15)
246 .setDocumentation("Value between 0 and 1 indicating the relative overlap between clusters. A value of 0.15 is usually a good trade-off between accuracy and efficiency.");
247 auto projectToInput = XMLAttribute<bool>(ATTR_PROJECT_TO_INPUT, true)
248 .setDocumentation("If enabled, places the cluster centers at the closest vertex of the input mesh. Should be enabled in case of non-uniform point distributions such as for shell structures.");
249
250 auto attrGeoMultiscaleDimension = XMLAttribute<std::string>(ATTR_GEOMETRIC_MULTISCALE_DIMENSION)
251 .setDocumentation("Specifies the dimensionality pairing used in geometric multiscale mapping. Options: '1D-3D', '1D-2D' or '2D-3D'.")
253 auto attrGeoMultiscaleType = XMLAttribute<std::string>(ATTR_GEOMETRIC_MULTISCALE_TYPE)
254 .setDocumentation("Type of geometric multiscale mapping. Either 'spread' or 'collect'.")
256 auto attrGeoMultiscaleAxis = XMLAttribute<std::string>(ATTR_GEOMETRIC_MULTISCALE_AXIS)
257 .setDocumentation("Principle axis along which geometric multiscale mapping is performed.")
259 auto attrGeoMultiscaleRadius = XMLAttribute<double>(ATTR_GEOMETRIC_MULTISCALE_RADIUS)
260 .setDocumentation("Radius of the cross-sectional interface between the participants.");
261 auto attrGeoMultiscaleCrossSectionProfile = XMLAttribute<std::string>(ATTR_GEOMETRIC_MULTISCALE_CROSS_SECTION_PROFILE)
262 .setDocumentation("Profile of the mapped variable along the cross-sectional interface: 'uniform' or 'parabolic'")
265 auto attrGeoMultiscaleCrossSection = XMLAttribute<std::string>(ATTR_GEOMETRIC_MULTISCALE_CROSS_SECTION)
266 .setDocumentation("Cross section of the interface of the participants: 'circle' or 'square'")
269
270 // Add the relevant attributes to the relevant tags
271 addAttributes(projectionTags, {attrFromMesh, attrToMesh, attrDirection, attrConstraint});
272 addAttributes(rbfDirectTags, {attrFromMesh, attrToMesh, attrDirection, attrConstraint, attrPolynomial, attrXDead, attrYDead, attrZDead});
273 addAttributes(rbfIterativeTags, {attrFromMesh, attrToMesh, attrDirection, attrConstraint, attrPolynomial, attrXDead, attrYDead, attrZDead, attrSolverRtol});
274 addAttributes(pumDirectTags, {attrFromMesh, attrToMesh, attrDirection, attrConstraint, attrPumPolynomial, verticesPerCluster, relativeOverlap, projectToInput});
275 addAttributes(rbfAliasTag, {attrFromMesh, attrToMesh, attrDirection, attrConstraint, attrXDead, attrYDead, attrZDead});
276 addAttributes(coarseGrainingTags, {attrFromMesh, attrToMesh, attrDirection, attrConstraint, attrcgRadius});
277 addAttributes(axialGeoMultiscaleTags, {attrFromMesh, attrToMesh, attrDirection, attrConstraint});
278 addAttributes(radialGeoMultiscaleTags, {attrFromMesh, attrToMesh, attrDirection, attrConstraint});
279 addAttributes(axialGeoMultiscaleTags, {attrGeoMultiscaleDimension, attrGeoMultiscaleType, attrGeoMultiscaleAxis, attrGeoMultiscaleRadius, attrGeoMultiscaleCrossSectionProfile, attrGeoMultiscaleCrossSection});
280 addAttributes(radialGeoMultiscaleTags, {attrGeoMultiscaleType, attrGeoMultiscaleAxis, attrGeoMultiscaleRadius});
281
282 // Now we take care of the subtag executor. We repeat some of the subtags in order to add individual documentation
283 XMLTag::Occurrence once = XMLTag::OCCUR_NOT_OR_ONCE;
284 // TODO, make type an int
285 auto attrDeviceId = makeXMLAttribute(ATTR_DEVICE_ID, static_cast<std::string>("0"))
286 .setDocumentation("Setting of the GPU device: Set \"auto\" to assign GPUs to each MPI rank in a round robin fashion or specify a number between 0 and the number of available GPUs-1 to assign all MPI ranks to one GPU device with the given ID.");
287 auto attrNThreads = makeXMLAttribute(ATTR_N_THREADS, static_cast<int>(0))
288 .setDocumentation("Specifies the number of threads for the OpenMP executor that should be used for the Ginkgo OpenMP backend. If a value of \"0\" is set, preCICE doesn't set the number of threads and the default behavior of OpenMP applies.");
289
290 // First, we have the executors for the direct solvers
291 {
292 std::list<XMLTag> cpuExecutor{
293 XMLTag{*this, EXECUTOR_CPU, once, SUBTAG_EXECUTOR}.setDocumentation("The default executor, which uses a single-core CPU with a gather-scatter parallelism.")};
294 std::list<XMLTag> deviceExecutors{
295 XMLTag{*this, EXECUTOR_CUDA, once, SUBTAG_EXECUTOR}.setDocumentation("Cuda (Nvidia) executor, which uses cuSolver/Ginkgo and a direct QR decomposition with a gather-scatter parallelism."),
296 XMLTag{*this, EXECUTOR_HIP, once, SUBTAG_EXECUTOR}.setDocumentation("Hip (AMD/Nvidia) executor, which uses hipSolver/Ginkgo and a direct QR decomposition with a gather-scatter parallelism.")};
297
298 addAttributes(deviceExecutors, {attrDeviceId});
299 addSubtagsToParents(cpuExecutor, rbfDirectTags);
300 addSubtagsToParents(deviceExecutors, rbfDirectTags);
301 }
302 // Second, the executors for the iterative solver
303 {
304 std::list<XMLTag> cpuExecutor{
305 XMLTag{*this, EXECUTOR_CPU, once, SUBTAG_EXECUTOR}.setDocumentation("The default executor relying on PETSc, which uses CPUs and distributed memory parallelism via MPI.")};
306 std::list<XMLTag> deviceExecutors{
307 XMLTag{*this, EXECUTOR_CUDA, once, SUBTAG_EXECUTOR}.setDocumentation("Cuda (Nvidia) executor, which uses Ginkgo with a gather-scatter parallelism."),
308 XMLTag{*this, EXECUTOR_HIP, once, SUBTAG_EXECUTOR}.setDocumentation("Hip (AMD/Nvidia) executor, which uses hipSolver with a gather-scatter parallelism.")};
309 std::list<XMLTag> ompExecutor{
310 XMLTag{*this, EXECUTOR_OMP, once, SUBTAG_EXECUTOR}.setDocumentation("OpenMP executor, which uses Ginkgo with a gather-scatter parallelism.")};
311
312 addAttributes(deviceExecutors, {attrDeviceId});
313 addAttributes(ompExecutor, {attrNThreads});
314 addSubtagsToParents(cpuExecutor, rbfIterativeTags);
315 addSubtagsToParents(deviceExecutors, rbfIterativeTags);
316 addSubtagsToParents(ompExecutor, rbfIterativeTags);
317 }
318 {
319 std::list<XMLTag> cpuExecutor{
320 XMLTag{*this, EXECUTOR_CPU, once, SUBTAG_EXECUTOR}.setDocumentation("The default executor using a CPU and a distributed memory parallelism via MPI.")};
321 std::list<XMLTag> deviceExecutors{
322 XMLTag{*this, EXECUTOR_CUDA, once, SUBTAG_EXECUTOR}.setDocumentation("Cuda (Nvidia) executor, which uses Kokkos-kernels, fully parallel"),
323 XMLTag{*this, EXECUTOR_HIP, once, SUBTAG_EXECUTOR}.setDocumentation("Hip (AMD/Nvidia) executor, which uses Kokkos-kernels, fully parallel."),
324 XMLTag{*this, EXECUTOR_SYCL, once, SUBTAG_EXECUTOR}.setDocumentation("SYCL (e.g. Intel) executor, which uses Kokkos-kernels, fully parallel.")};
325 std::list<XMLTag> ompExecutor{
326 XMLTag{*this, EXECUTOR_OMP, once, SUBTAG_EXECUTOR}.setDocumentation("OpenMP executor, which uses Kokkos-kernel, fully parallel.")};
327
328 auto attrExecutionMode = makeXMLAttribute(ATTR_EXECUTION_MODE, "minimal-memory")
329 .setDocumentation("Toggle to switch between a minimal-memory vs a minimal-compute algorithm. For option \"minimal-memory\", the RBF evaluation is recomputed for each data mapping on-the-fly, which saves approximately half the memory consumption (if meshes have a similar resolution), but may (!) be slower (depends heavily on the hardware). "
330 "For the option \"minimal-compute\", the RBF evaluation is precomputed, which may be faster, but consumes more memory.")
331 .setOptions({"minimal-memory", "minimal-compute"});
332
333 addAttributes(deviceExecutors, {attrDeviceId, attrExecutionMode});
334 addAttributes(ompExecutor, {attrNThreads, attrExecutionMode});
335 addSubtagsToParents(cpuExecutor, pumDirectTags);
336 addSubtagsToParents(deviceExecutors, pumDirectTags);
337 addSubtagsToParents(ompExecutor, pumDirectTags);
338 }
339 // The alias tag doesn't receive the subtag at all
340
341 // Now we take care of the subtag basis function
342 // First, we have the tags using a support radius
343 std::list<XMLTag> supportRadiusRBF{
344 XMLTag{*this, RBF_CPOLYNOMIAL_C0, once, SUBTAG_BASIS_FUNCTION}.setDocumentation("Wendland C0 function"),
345 XMLTag{*this, RBF_CPOLYNOMIAL_C2, once, SUBTAG_BASIS_FUNCTION}.setDocumentation("Wendland C2 function"),
346 XMLTag{*this, RBF_CPOLYNOMIAL_C4, once, SUBTAG_BASIS_FUNCTION}.setDocumentation("Wendland C4 function"),
347 XMLTag{*this, RBF_CPOLYNOMIAL_C6, once, SUBTAG_BASIS_FUNCTION}.setDocumentation("Wendland C6 function"),
348 XMLTag{*this, RBF_CPOLYNOMIAL_C8, once, SUBTAG_BASIS_FUNCTION}.setDocumentation("Wendland C8 function"),
349 XMLTag{*this, RBF_CTPS_C2, once, SUBTAG_BASIS_FUNCTION}.setDocumentation("Compact thin-plate-spline C2")};
350
351 auto attrSupportRadius = XMLAttribute<double>(ATTR_SUPPORT_RADIUS)
352 .setDocumentation("Support radius of each RBF basis function (global choice).");
353
354 addAttributes(supportRadiusRBF, {attrSupportRadius});
355 addSubtagsToParents(supportRadiusRBF, rbfIterativeTags);
356 addSubtagsToParents(supportRadiusRBF, rbfDirectTags);
357 addSubtagsToParents(supportRadiusRBF, pumDirectTags);
358 addSubtagsToParents(supportRadiusRBF, rbfAliasTag);
359
360 // Now the tags using a shape parameter
361 std::list<XMLTag> shapeParameterRBF{
362 XMLTag{*this, RBF_MULTIQUADRICS, once, SUBTAG_BASIS_FUNCTION}.setDocumentation("Multiquadrics"),
363 XMLTag{*this, RBF_INV_MULTIQUADRICS, once, SUBTAG_BASIS_FUNCTION}.setDocumentation("Inverse multiquadrics")};
364
365 auto attrShapeParam = XMLAttribute<double>(ATTR_SHAPE_PARAM)
366 .setDocumentation("Specific shape parameter for RBF basis function.");
367
368 addAttributes(shapeParameterRBF, {attrShapeParam});
369 addSubtagsToParents(shapeParameterRBF, rbfIterativeTags);
370 addSubtagsToParents(shapeParameterRBF, rbfDirectTags);
371 addSubtagsToParents(shapeParameterRBF, pumDirectTags);
372 addSubtagsToParents(shapeParameterRBF, rbfAliasTag);
373
374 // For the Gaussian, we need default values as the user can pass a support radius or a shape parameter
375 std::list<XMLTag> GaussRBF{
376 XMLTag{*this, RBF_GAUSSIAN, once, SUBTAG_BASIS_FUNCTION}.setDocumentation("Gaussian basis function accepting a support radius or a shape parameter.")};
377 attrShapeParam.setDefaultValue(std::numeric_limits<double>::quiet_NaN());
378 attrSupportRadius.setDefaultValue(std::numeric_limits<double>::quiet_NaN());
379 addAttributes(GaussRBF, {attrShapeParam, attrSupportRadius});
380 addSubtagsToParents(GaussRBF, rbfIterativeTags);
381 addSubtagsToParents(GaussRBF, rbfDirectTags);
382 addSubtagsToParents(GaussRBF, pumDirectTags);
383 addSubtagsToParents(GaussRBF, rbfAliasTag);
384
385 // tags without an attribute
386 std::list<XMLTag> attributelessRBFs{
387 XMLTag{*this, RBF_TPS, once, SUBTAG_BASIS_FUNCTION}.setDocumentation("Thin-plate-splines"),
388 XMLTag{*this, RBF_VOLUME_SPLINES, once, SUBTAG_BASIS_FUNCTION}.setDocumentation("Volume splines")};
389
390 addSubtagsToParents(attributelessRBFs, rbfIterativeTags);
391 addSubtagsToParents(attributelessRBFs, rbfDirectTags);
392 addSubtagsToParents(attributelessRBFs, pumDirectTags);
393 addSubtagsToParents(attributelessRBFs, rbfAliasTag);
394
395 // Add all tags to the mapping tag
396 parent.addSubtags(projectionTags);
397 parent.addSubtags(rbfIterativeTags);
398 parent.addSubtags(rbfDirectTags);
399 parent.addSubtags(pumDirectTags);
400 parent.addSubtags(rbfAliasTag);
401 parent.addSubtags(coarseGrainingTags);
402 parent.addSubtags(axialGeoMultiscaleTags);
403 parent.addSubtags(radialGeoMultiscaleTags);
404}
405
407 bool experimental)
408{
409 _experimental = experimental;
410}
411
413 const xml::ConfigurationContext &context,
414 xml::XMLTag &tag)
415{
416 PRECICE_TRACE(tag.getName());
417 if (tag.getNamespace() == TAG) {
418 // Mandatory tags
419 std::string dir = tag.getStringAttributeValue(ATTR_DIRECTION);
420 std::string fromMesh = tag.getStringAttributeValue(ATTR_FROM);
421 std::string toMesh = tag.getStringAttributeValue(ATTR_TO);
422 std::string type = tag.getName();
423 std::string constraint = tag.getStringAttributeValue(ATTR_CONSTRAINT);
424
425 // Check that either of the two is provided
426 PRECICE_CHECK(!toMesh.empty() || !fromMesh.empty(), "Neither a \"to\" nor a \"from\" mesh was defined in a preCICE mapping. Most data mappings require a \"to\" and a \"from\" mesh. "
427 "For just-in-time mapping, at least one of both attributes has to be specified.");
428
429 // Restrict to read-consistent and write-conservative for just-in-time mapping
430
431 // The from mesh cannot be empty due to the check above
432 PRECICE_CHECK(!toMesh.empty() || (toMesh.empty() && dir == DIRECTION_READ && constraint == CONSTRAINT_CONSISTENT),
433 "The mapping from mesh \"{0}\" has no \"to\" mesh, which configures a just-in-time mapping for the mesh \"{0}\". For just-in-time mapping, only read-consistent (direction = \"read\" and no \"to\" mesh) and write-conservative (direction = \"write\" and no \"from\" mesh) are implemented.", fromMesh);
434 PRECICE_CHECK(!fromMesh.empty() || (fromMesh.empty() && dir == DIRECTION_WRITE && constraint == CONSTRAINT_CONSERVATIVE),
435 "The mapping to mesh \"{0}\" has no \"from\" mesh, which configures a just-in-time mapping for the mesh \"{0}\". For just-in-time mapping, only read-consistent (direction = \"read\" and no \"to\" mesh) and write-conservative (direction = \"write\" and no \"from\" mesh) are implemented.", toMesh);
436
437 PRECICE_INFO_IF(toMesh.empty(), "Using just-in-time mapping from mesh \"{}\"", fromMesh);
438 PRECICE_INFO_IF(fromMesh.empty(), "Using just-in-time mapping to mesh \"{}\"", toMesh);
439
440 // optional tags
441 // We set here default values, but their actual value doesn't really matter.
442 // It's just for the mapping methods, which do not use these attributes at all.
443 bool xDead = tag.getBooleanAttributeValue(ATTR_X_DEAD, false);
444 bool yDead = tag.getBooleanAttributeValue(ATTR_Y_DEAD, false);
445 bool zDead = tag.getBooleanAttributeValue(ATTR_Z_DEAD, false);
446 double cgRadius = tag.getDoubleAttributeValue(ATTR_CG_RADIUS, 0.);
447 double solverRtol = tag.getDoubleAttributeValue(ATTR_SOLVER_RTOL, 1e-9);
448 std::string strPolynomial = tag.getStringAttributeValue(ATTR_POLYNOMIAL, POLYNOMIAL_SEPARATE);
449
450 // geometric multiscale related tags
451 std::string geoMultiscaleDimension = tag.getStringAttributeValue(ATTR_GEOMETRIC_MULTISCALE_DIMENSION, "");
452 std::string geoMultiscaleType = tag.getStringAttributeValue(ATTR_GEOMETRIC_MULTISCALE_TYPE, "");
453 std::string geoMultiscaleAxis = tag.getStringAttributeValue(ATTR_GEOMETRIC_MULTISCALE_AXIS, "");
454 double multiscaleRadius = tag.getDoubleAttributeValue(ATTR_GEOMETRIC_MULTISCALE_RADIUS, 1.0);
455 std::string geoMultiscaleProfile = tag.getStringAttributeValue(ATTR_GEOMETRIC_MULTISCALE_CROSS_SECTION_PROFILE, "");
456 std::string geoMultiscaleCrossSection = tag.getStringAttributeValue(ATTR_GEOMETRIC_MULTISCALE_CROSS_SECTION, "");
457
459 PRECICE_CHECK(_experimental, "The configured mapping \"{}\" is experimental and the configuration can change between minor releases. Set experimental=\"on\" in the precice-configuration tag.", type);
460 }
461
462 if (type == TYPE_AXIAL_GEOMETRIC_MULTISCALE && context.size > 1) {
463 throw std::runtime_error{"Axial geometric multiscale mapping is not available for parallel participants."};
464 }
465
466 if (type == TYPE_RADIAL_GEOMETRIC_MULTISCALE && context.size > 1) {
467 throw std::runtime_error{"Radial geometric multiscale mapping is not available for parallel participants."};
468 }
469
470 // pum related tags
471 int verticesPerCluster = tag.getIntAttributeValue(ATTR_VERTICES_PER_CLUSTER, 100);
472 double relativeOverlap = tag.getDoubleAttributeValue(ATTR_RELATIVE_OVERLAP, 0.3);
473 bool projectToInput = tag.getBooleanAttributeValue(ATTR_PROJECT_TO_INPUT, true);
474
475 // Convert raw string into enum types as the constructors take enums
476 if (constraint == CONSTRAINT_CONSERVATIVE) {
478 } else if (constraint == CONSTRAINT_CONSISTENT) {
480 } else if (constraint == CONSTRAINT_SCALED_CONSISTENT_SURFACE) {
482 } else if (constraint == CONSTRAINT_SCALED_CONSISTENT_VOLUME) {
484 } else {
485 PRECICE_UNREACHABLE("Unknown mapping constraint \"{}\".", constraint);
486 }
487
488 ConfiguredMapping configuredMapping = createMapping(dir, type, fromMesh, toMesh, cgRadius, geoMultiscaleDimension, geoMultiscaleType, geoMultiscaleAxis, multiscaleRadius, geoMultiscaleProfile, geoMultiscaleCrossSection);
489
490 _rbfConfig = configureRBFMapping(type, strPolynomial, xDead, yDead, zDead, solverRtol, verticesPerCluster, relativeOverlap, projectToInput);
491
492 checkDuplicates(configuredMapping);
493 _mappings.push_back(configuredMapping);
494 } else if (tag.getNamespace() == SUBTAG_BASIS_FUNCTION) {
495
496 PRECICE_ASSERT(!_mappings.empty());
497 PRECICE_CHECK(_mappings.back().requiresBasisFunction == true, "A basis-function was defined for the mapping "
498 "from mesh \"{}\" to mesh \"{}\", but no basis-function is required for this mapping type. "
499 "Please remove the basis-function tag or configure an rbf mapping, which requires a basis-function.",
500 _mappings.back().fromMesh->getName(), _mappings.back().toMesh->getName());
501 // We can only set one subtag
502 PRECICE_CHECK(_rbfConfig.basisFunctionDefined == false, "More than one basis-function was defined for the mapping "
503 "from mesh \"{}\" to mesh \"{}\".",
504 _mappings.back().fromMesh->getName(), _mappings.back().toMesh->getName());
505
506 std::string basisFctName = tag.getName();
507 double supportRadius = tag.getDoubleAttributeValue(ATTR_SUPPORT_RADIUS, 0.);
508 double shapeParameter = tag.getDoubleAttributeValue(ATTR_SHAPE_PARAM, 0.);
509
510 _rbfConfig.basisFunction = parseBasisFunctions(basisFctName);
511 _rbfConfig.basisFunctionDefined = true;
512 // The Gaussian RBF is always treated as a shape-parameter RBF. Hence, we have to convert the support radius, if necessary
513 if (_rbfConfig.basisFunction == BasisFunction::Gaussian) {
514 const bool exactlyOneSet = (std::isfinite(supportRadius) && !std::isfinite(shapeParameter)) ||
515 (std::isfinite(shapeParameter) && !std::isfinite(supportRadius));
516 PRECICE_CHECK(exactlyOneSet, "The specified parameters for the Gaussian RBF mapping are invalid. Please specify either a \"shape-parameter\" or a \"support-radius\".");
517
518 if (std::isfinite(supportRadius) && !std::isfinite(shapeParameter)) {
519 shapeParameter = std::sqrt(-std::log(Gaussian::cutoffThreshold)) / supportRadius;
520 }
521 }
522
523 _rbfConfig.supportRadius = supportRadius;
524 _rbfConfig.shapeParameter = shapeParameter;
525 } else if (tag.getNamespace() == SUBTAG_EXECUTOR) {
526 _executorConfig = std::make_unique<ExecutorConfiguration>();
527
528 if (tag.getName() == EXECUTOR_CPU) {
530 } else if (tag.getName() == EXECUTOR_CUDA) {
532 } else if (tag.getName() == EXECUTOR_HIP) {
534 } else if (tag.getName() == EXECUTOR_SYCL) {
536 } else if (tag.getName() == EXECUTOR_OMP) {
538 }
539
540 auto did = tag.getStringAttributeValue(ATTR_DEVICE_ID, "0");
541 if (did == "auto") {
542 _executorConfig->deviceId = -1;
543 } else {
544 try {
545 _executorConfig->deviceId = std::stoi(did);
546 PRECICE_CHECK(_executorConfig->deviceId >= 0, "The argument provided to \"gpu-device-id\" in the precice configuration file is invalid (negative device id)");
547 } catch (const std::invalid_argument &e) {
548 throw precice::Error("The argument provided to \"gpu-device-id\" in the precice configuration file is invalid (not a valid input).");
549 } catch (const std::out_of_range &e) {
550 throw precice::Error("The argument provided to \"gpu-device-id\" in the precice configuration file is invalid (out of range).");
551 }
552 }
553
555 auto mode = tag.getStringAttributeValue(ATTR_EXECUTION_MODE, "minimal-compute");
556 if (mode == "minimal-memory")
557 _executorConfig->computeEvaluationOffline = false;
558 else if (mode == "minimal-compute")
559 _executorConfig->computeEvaluationOffline = true;
560 else {
561 PRECICE_UNREACHABLE("Unknown execution mode");
562 }
563 }
564}
565
567 const std::string &polynomial,
568 bool xDead, bool yDead, bool zDead,
569 double solverRtol,
570 double verticesPerCluster,
571 double relativeOverlap,
572 bool projectToInput) const
573{
575
576 if (type == TYPE_RBF_GLOBAL_ITERATIVE)
578 else if (type == TYPE_RBF_GLOBAL_DIRECT)
580 else if (type == TYPE_RBF_PUM_DIRECT)
582 else {
583 // Rather simple auto-selection (for now), consisting of the PUM Eigen backend
585
586 // A more sophisticated criterion here could take the globalNumberOfVertices into account
587 // (the mesh pointer is stored in the configuredMapping anyway), but this quantity is not yet computed
588 // during the configuration time.
589 }
590
591 if (polynomial == POLYNOMIAL_SEPARATE)
592 rbfConfig.polynomial = Polynomial::SEPARATE;
593 else if (polynomial == POLYNOMIAL_ON)
594 rbfConfig.polynomial = Polynomial::ON;
595 else if (polynomial == POLYNOMIAL_OFF)
596 rbfConfig.polynomial = Polynomial::OFF;
597 else
598 PRECICE_UNREACHABLE("Unknown polynomial configuration.");
599
600 rbfConfig.deadAxis = {{xDead, yDead, zDead}};
601 rbfConfig.solverRtol = solverRtol;
602
603 rbfConfig.verticesPerCluster = verticesPerCluster;
604 rbfConfig.relativeOverlap = relativeOverlap;
605 rbfConfig.projectToInput = projectToInput;
606
607 return rbfConfig;
608}
609
611 const std::string &direction,
612 const std::string &type,
613 const std::string &fromMeshName,
614 const std::string &toMeshName,
615 const double cgRadius,
616 const std::string &geoMultiscaleDimension,
617 const std::string &geoMultiscaleType,
618 const std::string &geoMultiscaleAxis,
619 const double &multiscaleRadius,
620 const std::string &geoMultiscaleProfile,
621 const std::string &geoMultiscaleCrossSection) const
622{
623 PRECICE_TRACE(direction, type);
624
625 ConfiguredMapping configuredMapping;
626 mesh::PtrMesh fromMesh(_meshConfig->getMesh(fromMeshName));
627 mesh::PtrMesh toMesh(_meshConfig->getMesh(toMeshName));
628
629 // Handle for just-in-time mapping, we copy over the dimension and leave everything else
630 if (!fromMesh && fromMeshName.empty()) {
631 PRECICE_CHECK(toMesh,
632 "Mesh \"{0}\" was not found while creating a mapping. "
633 "Please correct the to=\"{0}\" attribute.",
634 toMeshName);
636 }
637 if (!toMesh && toMeshName.empty()) {
638 PRECICE_CHECK(fromMesh,
639 "Mesh \"{0}\" was not found while creating a mapping. "
640 "Please correct the from=\"{0}\" attribute.",
641 fromMeshName);
643 }
644
645 PRECICE_CHECK(fromMesh,
646 "Mesh \"{0}\" was not found while creating a mapping. "
647 "Please correct the from=\"{0}\" attribute.",
648 fromMeshName);
649 PRECICE_CHECK(toMesh,
650 "Mesh \"{0}\" was not found while creating a mapping. "
651 "Please correct the to=\"{0}\" attribute.",
652 toMeshName);
653
654 PRECICE_CHECK((!toMesh->isJustInTime() && !fromMesh->isJustInTime()) ||
655 ((toMesh->isJustInTime() || fromMesh->isJustInTime()) && (type == TYPE_NEAREST_NEIGHBOR || type == TYPE_RBF_PUM_DIRECT || type == TYPE_RBF_ALIAS || type == TYPE_COARSE_GRAINING)),
656 "A just-in-time mapping was configured from mesh \"{}\" to mesh \"{}\" using \"mapping:{}\", which is currently not implemented. "
657 "Available mapping types are \"mapping:{}\", \"mapping:{}\", \"mapping:{}\" and \"mapping:{}\".",
659
660 // Check for compatible mesh dimensions
661 PRECICE_CHECK(fromMesh->getDimensions() == toMesh->getDimensions(),
662 "Mapping between meshes of different dimensions is not allowed yet. "
663 "Please set the same dimensions attribute to meshes \"{}\" and \"{}\", "
664 "or choose different meshes.",
665 fromMeshName, toMeshName);
666
667 configuredMapping.fromMesh = fromMesh;
668 configuredMapping.toMesh = toMesh;
669
670 if (direction == DIRECTION_WRITE) {
671 configuredMapping.direction = WRITE;
672 } else if (direction == DIRECTION_READ) {
673 configuredMapping.direction = READ;
674 } else {
675 PRECICE_UNREACHABLE("Unknown mapping direction type \"{}\".", direction);
676 }
677
678 // Create all projection based mappings
679 if (type == TYPE_NEAREST_NEIGHBOR) {
680 configuredMapping.mapping = PtrMapping(new NearestNeighborMapping(constraintValue, fromMesh->getDimensions()));
681 } else if (type == TYPE_NEAREST_PROJECTION) {
682 configuredMapping.mapping = PtrMapping(new NearestProjectionMapping(constraintValue, fromMesh->getDimensions()));
683 } else if (type == TYPE_LINEAR_CELL_INTERPOLATION) {
685 } else if (type == TYPE_COARSE_GRAINING) {
686 configuredMapping.mapping = PtrMapping(new CoarseGrainingMapping(constraintValue, fromMesh->getDimensions(), cgRadius));
687 } else if (type == TYPE_NEAREST_NEIGHBOR_GRADIENT) {
688
689 // NNG is not applicable with the conservative constraint
691 "Nearest-neighbor-gradient mapping is not implemented using a \"conservative\" constraint. "
692 "Please select constraint=\" consistent\" or a different mapping method.");
693
695
696 } else if (type == TYPE_AXIAL_GEOMETRIC_MULTISCALE) {
697
698 // Axial geometric multiscale is not applicable with the conservative constraint
700 "Axial geometric multiscale mapping is not implemented for the \"conservative\" constraint. "
701 "Please select constraint=\" consistent\" or a different mapping method.");
702
703 // Convert strings into enums
705 if (geoMultiscaleAxis == "x") {
707 } else if (geoMultiscaleAxis == "y") {
709 } else if (geoMultiscaleAxis == "z") {
711 } else {
712 PRECICE_UNREACHABLE("Unknown geometric multiscale axis \"{}\".", geoMultiscaleAxis);
713 }
714
716 if (geoMultiscaleDimension == "1d-3d") {
718 } else if (geoMultiscaleDimension == "1d-2d") {
720 } else if (geoMultiscaleDimension == "2d-3d") {
722 } else {
723 PRECICE_UNREACHABLE("Unknown dimension \"{}\".", geoMultiscaleDimension);
724 }
725
727 if (geoMultiscaleType == "spread") {
729 } else if (geoMultiscaleType == "collect") {
731 } else {
732 PRECICE_UNREACHABLE("Unknown geometric multiscale type \"{}\".", geoMultiscaleType);
733 }
734
736 if (geoMultiscaleProfile == "parabolic") {
738 } else if (geoMultiscaleProfile == "uniform") {
740 } else {
741 PRECICE_UNREACHABLE("Unknown cross-section profile \"{}\".", geoMultiscaleProfile);
742 }
743
745 if (geoMultiscaleCrossSection == "circle") {
747 } else if (geoMultiscaleCrossSection == "square") {
749 } else {
750 PRECICE_UNREACHABLE("Unknown geometric cross section \"{}\".", geoMultiscaleCrossSection);
751 }
752
753 configuredMapping.mapping = PtrMapping(new AxialGeoMultiscaleMapping(constraintValue, fromMesh->getDimensions(), multiscaleDimension, multiscaleType, multiscaleAxis, multiscaleRadius, multiscaleProfile, multiscaleCrossSection));
754
755 } else if (type == TYPE_RADIAL_GEOMETRIC_MULTISCALE) {
756
757 // Radial geometric multiscale is not applicable with the conservative constraint
759 "Radial geometric multiscale mapping is not implemented for the \"conservative\" constraint. "
760 "Please select constraint=\" consistent\" or a different mapping method.");
761
762 // Convert strings into enums
764 if (geoMultiscaleAxis == "x") {
766 } else if (geoMultiscaleAxis == "y") {
768 } else if (geoMultiscaleAxis == "z") {
770 } else {
771 PRECICE_UNREACHABLE("Unknown geometric multiscale axis \"{}\".", geoMultiscaleAxis);
772 }
773
775 if (geoMultiscaleType == "spread") {
777 } else if (geoMultiscaleType == "collect") {
779 } else {
780 PRECICE_UNREACHABLE("Unknown geometric multiscale type \"{}\".", geoMultiscaleType);
781 }
782
783 configuredMapping.mapping = PtrMapping(new RadialGeoMultiscaleMapping(constraintValue, fromMesh->getDimensions(), multiscaleType, multiscaleAxis));
784
785 } else {
786 // We need knowledge about the basis function in order to instantiate the rbf related mapping
788 configuredMapping.mapping = nullptr;
789 configuredMapping.configuredWithAliasTag = type == TYPE_RBF_ALIAS;
790 }
791
792 configuredMapping.requiresBasisFunction = requiresBasisFunction(type);
793
794 return configuredMapping;
795}
796
798{
799 for (const ConfiguredMapping &configuredMapping : _mappings) {
800 bool sameToMesh = mapping.toMesh->getName() == configuredMapping.toMesh->getName();
801 bool sameFromMesh = mapping.fromMesh->getName() == configuredMapping.fromMesh->getName();
802 bool sameMapping = sameToMesh && sameFromMesh;
803 PRECICE_CHECK(!sameMapping,
804 "There cannot be two mappings from mesh \"{}\" to mesh \"{}\". "
805 "Please remove one of the duplicated meshes. ",
806 mapping.fromMesh->getName(), mapping.toMesh->getName());
807 }
808 for (const ConfiguredMapping &configuredMapping : _mappings) {
809 bool sameToMesh = mapping.toMesh->getName() == configuredMapping.toMesh->getName();
810 bool isWrite = mapping.direction == mapping::MappingConfiguration::WRITE && configuredMapping.direction == mapping::MappingConfiguration::WRITE;
811 bool sameMapping = sameToMesh && isWrite && (mapping.fromMesh->isJustInTime() || configuredMapping.fromMesh->isJustInTime());
812 PRECICE_CHECK(!sameMapping,
813 "There cannot be two mappings to mesh \"{}\". "
814 "Here, we have a mixture of just-in-time mapping and a conventional mapping. ",
815 mapping.toMesh->getName());
816 }
817}
818
820{
821 if (tag.getNamespace() == TAG) {
822 if (requiresBasisFunction(tag.getName())) {
823 PRECICE_CHECK(_rbfConfig.basisFunctionDefined, "No basis-function was defined for the \"{}\" mapping from mesh \"{}\" to mesh \"{}\".", tag.getName(), _mappings.back().fromMesh->getName(), _mappings.back().toMesh->getName());
824 if (!_executorConfig) {
825 _executorConfig = std::make_unique<ExecutorConfiguration>();
826 }
828 _executorConfig.reset();
829 }
830 PRECICE_ASSERT(_mappings.back().mapping != nullptr);
831 }
832}
833
835{
838
839 // Instantiate the RBF mapping classes
840 // We first categorize according to the executor
841 // 1. the CPU executor
844 mapping.mapping = getRBFMapping<RBFBackend::Eigen>(_rbfConfig.basisFunction, constraintValue, mapping.fromMesh->getDimensions(), _rbfConfig.supportRadius, _rbfConfig.shapeParameter, _rbfConfig.deadAxis, _rbfConfig.polynomial);
846#ifndef PRECICE_NO_PETSC
847 // for petsc initialization
849
850 mapping.mapping = getRBFMapping<RBFBackend::PETSc>(_rbfConfig.basisFunction, constraintValue, mapping.fromMesh->getDimensions(), _rbfConfig.supportRadius, _rbfConfig.shapeParameter, _rbfConfig.deadAxis, _rbfConfig.solverRtol, _rbfConfig.polynomial);
851#else
852 PRECICE_ERROR("The global-iterative RBF solver on a CPU requires a preCICE build with PETSc enabled.");
853#endif
856 _ginkgoParameter.executor = "cpu";
857 mapping.mapping = getRBFMapping<RBFBackend::PUM>(_rbfConfig.basisFunction, constraintValue, mapping.fromMesh->getDimensions(), _rbfConfig.supportRadius, _rbfConfig.shapeParameter, _rbfConfig.polynomial, _rbfConfig.verticesPerCluster, _rbfConfig.relativeOverlap, _rbfConfig.projectToInput, _ginkgoParameter);
858 } else {
859 PRECICE_UNREACHABLE("Unknown RBF solver.");
860 }
861 // 2. any other executor is configured via Ginkgo
862 } else {
864 _ginkgoParameter.usePreconditioner = false;
865 _ginkgoParameter.deviceId = _executorConfig->deviceId;
867 _ginkgoParameter.executor = "cuda-executor";
868#ifndef PRECICE_WITH_CUDA
869 PRECICE_ERROR("The cuda-executor (configured for the mapping from mesh {} to mesh {}) requires a Kokkos and preCICE build with Cuda enabled.", mapping.fromMesh->getName(), mapping.toMesh->getName());
870#endif
872 _ginkgoParameter.executor = "hip-executor";
873#ifndef PRECICE_WITH_HIP
874 PRECICE_ERROR("The hip-executor (configured for the mapping from mesh {} to mesh {}) requires a Kokkos and preCICE build with HIP enabled.", mapping.fromMesh->getName(), mapping.toMesh->getName());
875#endif
877 _ginkgoParameter.executor = "sycl-executor";
878#ifndef PRECICE_WITH_SYCL
879 PRECICE_ERROR("The sycl-executor (configured for the mapping from mesh {} to mesh {}) requires a Kokkos and preCICE build with SYCL enabled.", mapping.fromMesh->getName(), mapping.toMesh->getName());
880#endif
882 _ginkgoParameter.executor = "omp-executor";
883 _ginkgoParameter.nThreads = _executorConfig->nThreads;
884#ifndef PRECICE_WITH_OPENMP
885 PRECICE_ERROR("The omp-executor (configured for the mapping from mesh {} to mesh {}) requires a Kokkos and preCICE build with OpenMP enabled.", mapping.fromMesh->getName(), mapping.toMesh->getName());
886#endif
887 }
889#ifndef PRECICE_NO_GINKGO
890 _ginkgoParameter.solver = "qr-solver";
891 mapping.mapping = getRBFMapping<RBFBackend::Ginkgo>(_rbfConfig.basisFunction, constraintValue, mapping.fromMesh->getDimensions(), _rbfConfig.supportRadius, _rbfConfig.shapeParameter, _rbfConfig.deadAxis, _rbfConfig.polynomial, _ginkgoParameter);
892#else
893 PRECICE_ERROR("The selected direct solver for the global RBF mapping on executor {} from mesh {} to mesh {} requires a preCICE build with Ginkgo enabled.", _ginkgoParameter.executor, mapping.fromMesh->getName(), mapping.toMesh->getName());
894#endif
896#ifndef PRECICE_NO_GINKGO
897 _ginkgoParameter.solver = "cg-solver";
898 _ginkgoParameter.residualNorm = _rbfConfig.solverRtol;
899 mapping.mapping = getRBFMapping<RBFBackend::Ginkgo>(_rbfConfig.basisFunction, constraintValue, mapping.fromMesh->getDimensions(), _rbfConfig.supportRadius, _rbfConfig.shapeParameter, _rbfConfig.deadAxis, _rbfConfig.polynomial, _ginkgoParameter);
900#else
901 PRECICE_ERROR("The selected iterative solver for the global RBF mapping on executor {} from mesh {} to mesh {} requires a preCICE build with Ginkgo enabled.", _ginkgoParameter.executor, mapping.fromMesh->getName(), mapping.toMesh->getName());
902#endif
904#ifndef PRECICE_NO_KOKKOS_KERNELS
905 PRECICE_CHECK(!(mapping.fromMesh->isJustInTime() || mapping.toMesh->isJustInTime()), "Executor \"{}\" is not implemented as just-in-time mapping.", _ginkgoParameter.executor);
906 mapping.mapping = getRBFMapping<RBFBackend::PUM>(_rbfConfig.basisFunction, constraintValue, mapping.fromMesh->getDimensions(), _rbfConfig.supportRadius, _rbfConfig.shapeParameter, _rbfConfig.polynomial, _rbfConfig.verticesPerCluster, _rbfConfig.relativeOverlap, _rbfConfig.projectToInput, _ginkgoParameter, _executorConfig->computeEvaluationOffline);
907#else
908 PRECICE_ERROR("The selected pu-rbf solver using executor \"{}\" for the mapping from mesh {} to mesh {} requires a preCICE build with Kokkos-kernels enabled.", _ginkgoParameter.executor, mapping.fromMesh->getName(), mapping.toMesh->getName());
909#endif
910 } else {
911 PRECICE_UNREACHABLE("Unknown solver type.");
912 }
913 }
914}
915
916const std::vector<MappingConfiguration::ConfiguredMapping> &MappingConfiguration::mappings()
917{
918 return _mappings;
919}
920
921bool MappingConfiguration::requiresBasisFunction(const std::string &mappingType) const
922{
923 return mappingType == TYPE_RBF_PUM_DIRECT || mappingType == TYPE_RBF_GLOBAL_DIRECT || mappingType == TYPE_RBF_GLOBAL_ITERATIVE || mappingType == TYPE_RBF_ALIAS;
924}
925
926BasisFunction MappingConfiguration::parseBasisFunctions(const std::string &basisFctName) const
927{
928 BasisFunction basisFunction{};
929 if (basisFctName == RBF_TPS)
930 basisFunction = BasisFunction::ThinPlateSplines;
931 else if (basisFctName == RBF_MULTIQUADRICS)
932 basisFunction = BasisFunction::Multiquadrics;
933 else if (basisFctName == RBF_INV_MULTIQUADRICS)
935 else if (basisFctName == RBF_VOLUME_SPLINES)
936 basisFunction = BasisFunction::VolumeSplines;
937 else if (basisFctName == RBF_GAUSSIAN)
938 basisFunction = BasisFunction::Gaussian;
939 else if (basisFctName == RBF_CTPS_C2)
941 else if (basisFctName == RBF_CPOLYNOMIAL_C0)
942 basisFunction = BasisFunction::WendlandC0;
943 else if (basisFctName == RBF_CPOLYNOMIAL_C2)
944 basisFunction = BasisFunction::WendlandC2;
945 else if (basisFctName == RBF_CPOLYNOMIAL_C4)
946 basisFunction = BasisFunction::WendlandC4;
947 else if (basisFctName == RBF_CPOLYNOMIAL_C6)
948 basisFunction = BasisFunction::WendlandC6;
949 else if (basisFctName == RBF_CPOLYNOMIAL_C8)
950 basisFunction = BasisFunction::WendlandC8;
951 else
952 PRECICE_UNREACHABLE("Unknown basis function \"{}\".", basisFctName);
953 return basisFunction;
954}
955} // namespace precice::mapping
#define PRECICE_ERROR(...)
Definition LogMacros.hpp:16
#define PRECICE_TRACE(...)
Definition LogMacros.hpp:92
#define PRECICE_INFO_IF(condition,...)
Definition LogMacros.hpp:25
#define PRECICE_CHECK(check,...)
Definition LogMacros.hpp:32
#define PRECICE_ASSERT(...)
Definition assertion.hpp:85
#define PRECICE_UNREACHABLE(...)
Definition assertion.hpp:93
int getDimensions() const
Definition Mesh.cpp:99
const std::string & getName() const
Returns the name of the mesh, as set in the config file.
Definition Mesh.cpp:242
bool isJustInTime() const
Definition Mesh.hpp:340
Geometric multiscale mapping in axial direction.
MultiscaleType
Geometric multiscale nature of the mapping (spread or collect).
MultiscaleProfile
Profile to use when type == SPREAD.
static constexpr double cutoffThreshold
Below that value the function is supposed to be zero. Defines the support radius if not explicitly gi...
Mapping using orthogonal projection to nearest triangle/edge/vertex and linear interpolation from pro...
RBFConfiguration configureRBFMapping(const std::string &type, const std::string &polynomial, bool xDead, bool yDead, bool zDead, double solverRtol, double verticesPerCluster, double relativeOverlap, bool projectToInput) const
void xmlTagCallback(const xml::ConfigurationContext &context, xml::XMLTag &callingTag) override
Callback function required for use of automatic configuration.
ConfiguredMapping createMapping(const std::string &direction, const std::string &type, const std::string &fromMeshName, const std::string &toMeshName, const double cgRange, const std::string &geoMultiscaleDimension, const std::string &geoMultiscaleType, const std::string &geoMultiscaleAxis, const double &multiscaleRadius, const std::string &geoMultiscaleProfile, const std::string &geoMultiscaleCrossSection) const
const std::vector< ConfiguredMapping > & mappings()
Returns all configured mappings.
std::unique_ptr< ExecutorConfiguration > _executorConfig
bool requiresBasisFunction(const std::string &mappingType) const
BasisFunction parseBasisFunctions(const std::string &basisFctName) const
Given a basis function name (as a string), transforms the string into an enum of the BasisFunction.
std::vector< ConfiguredMapping > _mappings
const std::string GEOMETRIC_MULTISCALE_CROSS_SECTION_PROFILE_UNIFORM
void checkDuplicates(const ConfiguredMapping &mapping)
Check whether a mapping to and from the same mesh already exists.
void xmlEndTagCallback(const xml::ConfigurationContext &context, xml::XMLTag &callingTag) override
Callback function required for use of automatic configuration.
const std::string GEOMETRIC_MULTISCALE_CROSS_SECTION_PROFILE_PARABOLIC
const RBFConfiguration & rbfConfig() const
MappingConfiguration(xml::XMLTag &parent, mesh::PtrMeshConfiguration meshConfiguration)
Constraint
Specifies additional constraints for a mapping.
Definition Mapping.hpp:30
Mapping using nearest neighboring vertices and their local gradient values.
Mapping using nearest neighboring vertices.
Mapping using orthogonal projection to nearest triangle/edge/vertex and linear interpolation from pro...
Geometric multiscale mapping in radial direction.
MultiscaleType
Geometric multiscale type of the mapping (spread or collect).
static mesh::PtrMesh getJustInTimeMappingMesh(int dimension)
static CommStatePtr current()
Returns an owning pointer to the current CommState.
Definition Parallel.cpp:147
static void initialize(utils::Parallel::Communicator comm)
Initializes the Petsc environment.
Definition Petsc.cpp:39
Represents an XML tag to be configured automatically.
Definition XMLTag.hpp:28
const std::string & getNamespace() const
Returns xml namespace.
Definition XMLTag.hpp:159
void addSubtags(const Container &subtags)
Definition XMLTag.hpp:143
std::string getStringAttributeValue(const std::string &name, std::optional< std::string > default_value=std::nullopt) const
Definition XMLTag.cpp:145
bool getBooleanAttributeValue(const std::string &name, std::optional< bool > default_value=std::nullopt) const
Definition XMLTag.cpp:159
const std::string & getName() const
Returns name (without namespace).
Definition XMLTag.hpp:153
int getIntAttributeValue(const std::string &name, std::optional< int > default_value=std::nullopt) const
Definition XMLTag.cpp:131
double getDoubleAttributeValue(const std::string &name, std::optional< double > default_value=std::nullopt) const
Definition XMLTag.cpp:117
contains data mapping from points to meshes.
std::shared_ptr< Mapping > PtrMapping
std::shared_ptr< Mesh > PtrMesh
std::shared_ptr< MeshConfiguration > PtrMeshConfiguration
contains the XML configuration parser.
STL namespace.
static precice::logging::Logger _log("precicec")
Direction direction
Direction of mapping (important to set input and output mesh).
bool configuredWithAliasTag
used the automatic rbf alias tag in order to set the mapping
Tightly coupled to the parameters of Participant()
Definition XMLTag.hpp:21