preCICE
Loading...
Searching...
No Matches
CouplingSchemeConfiguration.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <cstddef>
3#include <memory>
4#include <ostream>
5#include <stdexcept>
6#include <utility>
7#include <vector>
8
25#include "logging/LogMacros.hpp"
26#include "m2n/SharedPointer.hpp"
28#include "mesh/Data.hpp"
29#include "mesh/Mesh.hpp"
34#include "utils/Helpers.hpp"
35#include "utils/assertion.hpp"
36#include "xml/ConfigParser.hpp"
37#include "xml/XMLAttribute.hpp"
38#include "xml/XMLTag.hpp"
39
40namespace precice::cplscheme {
41
42const int CouplingSchemeConfiguration::DEFAULT_MIN_ITERATIONS(1); // min 1 iteration
44
46 xml::XMLTag &parent,
50 : TAG("coupling-scheme"),
51 TAG_PARTICIPANTS("participants"),
52 TAG_PARTICIPANT("participant"),
53 TAG_EXCHANGE("exchange"),
54 TAG_MAX_TIME("max-time"),
55 TAG_MAX_TIME_WINDOWS("max-time-windows"),
56 TAG_TIME_WINDOW_SIZE("time-window-size"),
57 TAG_ABS_CONV_MEASURE("absolute-convergence-measure"),
58 TAG_ABS_OR_REL_CONV_MEASURE("absolute-or-relative-convergence-measure"),
59 TAG_REL_CONV_MEASURE("relative-convergence-measure"),
60 TAG_RES_REL_CONV_MEASURE("residual-relative-convergence-measure"),
61 TAG_MIN_ITERATIONS("min-iterations"),
62 TAG_MAX_ITERATIONS("max-iterations"),
63 ATTR_DATA("data"),
64 ATTR_MESH("mesh"),
65 ATTR_PARTICIPANT("participant"),
66 ATTR_INITIALIZE("initialize"),
67 ATTR_EXCHANGE_SUBSTEPS("substeps"),
68 ATTR_TYPE("type"),
69 ATTR_FIRST("first"),
70 ATTR_SECOND("second"),
71 ATTR_VALUE("value"),
72 ATTR_METHOD("method"),
73 ATTR_LIMIT("limit"),
74 ATTR_ABS_LIMIT("abs-limit"),
75 ATTR_REL_LIMIT("rel-limit"),
76 ATTR_NAME("name"),
77 ATTR_FROM("from"),
78 ATTR_TO("to"),
79 ATTR_SUFFICES("suffices"),
80 ATTR_STRICT("strict"),
81 ATTR_CONTROL("control"),
82 VALUE_SERIAL_EXPLICIT("serial-explicit"),
83 VALUE_PARALLEL_EXPLICIT("parallel-explicit"),
84 VALUE_SERIAL_IMPLICIT("serial-implicit"),
85 VALUE_PARALLEL_IMPLICIT("parallel-implicit"),
86 VALUE_MULTI("multi"),
87 VALUE_FIXED("fixed"),
88 VALUE_FIRST_PARTICIPANT("first-participant"),
89 _config(),
90 _meshConfig(std::move(meshConfig)),
91 _m2nConfig(std::move(m2nConfig)),
92 _participantConfig(participantConfig),
95{
96 using namespace xml;
97
98 XMLTag::Occurrence occ = XMLTag::OCCUR_ARBITRARY;
99 std::vector<XMLTag> tags;
100 {
101 XMLTag tag(*this, VALUE_SERIAL_EXPLICIT, occ, TAG);
102 tag.setDocumentation("Explicit coupling scheme according to conventional serial staggered procedure (CSS).");
104 tags.push_back(tag);
105 }
106 {
107 XMLTag tag(*this, VALUE_PARALLEL_EXPLICIT, occ, TAG);
108 tag.setDocumentation("Explicit coupling scheme according to conventional parallel staggered procedure (CPS).");
110 tags.push_back(tag);
111 }
112 {
113 XMLTag tag(*this, VALUE_SERIAL_IMPLICIT, occ, TAG);
114 tag.setDocumentation("Implicit coupling scheme according to block Gauss-Seidel iterations (S-System). "
115 "Improved implicit iterations are achieved by using a acceleration (recommended!).");
117 tags.push_back(tag);
118 }
119 {
120 XMLTag tag(*this, VALUE_PARALLEL_IMPLICIT, occ, TAG);
121 tag.setDocumentation("Parallel Implicit coupling scheme according to block Jacobi iterations (V-System). "
122 "Improved implicit iterations are achieved by using a acceleration (recommended!).");
124 tags.push_back(tag);
125 }
126 {
127 XMLTag tag(*this, VALUE_MULTI, occ, TAG);
128 tag.setDocumentation("Multi coupling scheme according to block Jacobi iterations. "
129 "Improved implicit iterations are achieved by using a acceleration (recommended!).");
131 tags.push_back(tag);
132 }
133
134 for (XMLTag &tag : tags) {
135 parent.addSubtag(tag);
136 }
137}
138
140 const std::string &participantName) const
141{
142 return utils::contained(participantName, _couplingSchemes);
143}
144
146 const std::string &participantName) const
147{
149 "No coupling scheme defined for participant \"{}\". "
150 "Please make sure to provide at least one <coupling-scheme:TYPE> in your "
151 "precice-config.xml that couples this participant using the <participants .../> tag.",
152 participantName);
153 return _couplingSchemes.find(participantName)->second;
154}
155
157 const xml::ConfigurationContext &context,
158 xml::XMLTag &tag)
159{
161 if (tag.getNamespace() == TAG) {
162 _config.type = tag.getName();
163 _accelerationConfig->clear();
164 } else if (tag.getName() == TAG_PARTICIPANTS) {
165 std::string first = tag.getStringAttributeValue(ATTR_FIRST);
166 std::string second = tag.getStringAttributeValue(ATTR_SECOND);
167
168 PRECICE_CHECK(_participantConfig->hasParticipant(first),
169 "First participant in coupling-scheme <participants first=\"{}\" second=\"{}\" /> is unknown. {}",
170 first, second, _participantConfig->hintFor(first));
171 PRECICE_CHECK(_participantConfig->hasParticipant(second),
172 "Second participant in coupling-scheme <participants first=\"{}\" second=\"{}\" /> is unknown. {}",
173 first, second, _participantConfig->hintFor(second));
174 PRECICE_CHECK(first != second,
175 "First and second participant in coupling scheme are the same. "
176 "Please choose different in the <participants first=\"{}\" second=\"{}\" /> tag in the <coupling-scheme:...> of your precice-config.xml",
177 first, second);
178 _config.participants.push_back(first);
179 _config.participants.push_back(second);
180 } else if (tag.getName() == TAG_PARTICIPANT) {
182 bool control = tag.getBooleanAttributeValue(ATTR_CONTROL);
183 std::string participantName = tag.getStringAttributeValue(ATTR_NAME);
184 PRECICE_CHECK(_participantConfig->hasParticipant(participantName),
185 "Provided participant in multi coupling-scheme <participant name=\"{}\" ... /> is unknown. {}",
186 participantName, _participantConfig->hintFor(participantName));
187 PRECICE_CHECK(std::find(_config.participants.begin(), _config.participants.end(), participantName) == _config.participants.end() && participantName.compare(_config.controller) != 0,
188 "Participant \"{0}\" is provided multiple times to multi coupling scheme. "
189 "Please make sure that you do not provide the participant multiple times via the <participant name=\"{0}\" /> "
190 "tag in the <coupling-scheme:...> of your precice-config.xml",
191 participantName);
192 if (control) {
193 PRECICE_CHECK(not _config.setController,
194 "Only one controller per MultiCouplingScheme can be defined. "
195 "Please check the <participant name=\"{}\" control=\"{}\" /> tag in the <coupling-scheme:...> of your precice-config.xml",
196 participantName, control);
197 _config.controller = participantName;
198 _config.setController = true;
199 }
200 _config.participants.push_back(participantName);
201 } else if (tag.getName() == TAG_MAX_TIME) {
203 PRECICE_CHECK(_config.maxTime > 0,
204 "Maximum time has to be larger than zero. "
205 "Please check the <max-time value=\"{}\" /> tag in the <coupling-scheme:...> of your precice-config.xml",
206 _config.maxTime);
207 } else if (tag.getName() == TAG_MAX_TIME_WINDOWS) {
208 _config.maxTimeWindows = tag.getIntAttributeValue(ATTR_VALUE);
209 PRECICE_CHECK(_config.maxTimeWindows > 0,
210 "Maximum number of time windows has to be larger than zero. "
211 "Please check the <max-time-windows value=\"{}\" /> tag in the <coupling-scheme:...> of your precice-config.xml",
212 _config.maxTimeWindows);
213 } else if (tag.getName() == TAG_TIME_WINDOW_SIZE) {
214 _config.timeWindowSize = tag.getDoubleAttributeValue(ATTR_VALUE);
215 // Attribute does not exist for parallel coupling schemes as it is always fixed.
217
220 "The minimal time window size supported by preCICE is {}. "
221 "Please check the <time-window-size value=\"{}\" /> tag "
222 "in the <coupling-scheme:...> of your precice-config.xml and pick an appropriate time window size.",
224 } else {
227 "You combined a custom time-window-size of {} with method=\"first-participant\". "
228 "The given time-window-size will be ignored as it is prescribed by the participant.",
229 _config.timeWindowSize);
231 }
232 } else if (tag.getName() == TAG_ABS_CONV_MEASURE) {
233 const std::string &dataName = tag.getStringAttributeValue(ATTR_DATA);
234 const std::string &meshName = tag.getStringAttributeValue(ATTR_MESH);
235 double limit = tag.getDoubleAttributeValue(ATTR_LIMIT);
236 bool suffices = tag.getBooleanAttributeValue(ATTR_SUFFICES);
237 bool strict = tag.getBooleanAttributeValue(ATTR_STRICT);
239 addAbsoluteConvergenceMeasure(dataName, meshName, limit, suffices, strict);
240 } else if (tag.getName() == TAG_ABS_OR_REL_CONV_MEASURE) {
241 const std::string &dataName = tag.getStringAttributeValue(ATTR_DATA);
242 const std::string &meshName = tag.getStringAttributeValue(ATTR_MESH);
243 double absLimit = tag.getDoubleAttributeValue(ATTR_ABS_LIMIT);
244 double relLimit = tag.getDoubleAttributeValue(ATTR_REL_LIMIT);
245 bool suffices = tag.getBooleanAttributeValue(ATTR_SUFFICES);
246 bool strict = tag.getBooleanAttributeValue(ATTR_STRICT);
248 addAbsoluteOrRelativeConvergenceMeasure(dataName, meshName, absLimit, relLimit, suffices, strict);
249 } else if (tag.getName() == TAG_REL_CONV_MEASURE) {
250 const std::string &dataName = tag.getStringAttributeValue(ATTR_DATA);
251 const std::string &meshName = tag.getStringAttributeValue(ATTR_MESH);
252 double limit = tag.getDoubleAttributeValue(ATTR_LIMIT);
253 bool suffices = tag.getBooleanAttributeValue(ATTR_SUFFICES);
254 bool strict = tag.getBooleanAttributeValue(ATTR_STRICT);
256 addRelativeConvergenceMeasure(dataName, meshName, limit, suffices, strict);
257 } else if (tag.getName() == TAG_RES_REL_CONV_MEASURE) {
258 const std::string &dataName = tag.getStringAttributeValue(ATTR_DATA);
259 const std::string &meshName = tag.getStringAttributeValue(ATTR_MESH);
260 double limit = tag.getDoubleAttributeValue(ATTR_LIMIT);
261 bool suffices = tag.getBooleanAttributeValue(ATTR_SUFFICES);
262 bool strict = tag.getBooleanAttributeValue(ATTR_STRICT);
264 addResidualRelativeConvergenceMeasure(dataName, meshName, limit, suffices, strict);
265 } else if (tag.getName() == TAG_EXCHANGE) {
266 std::string nameData = tag.getStringAttributeValue(ATTR_DATA);
267 std::string nameMesh = tag.getStringAttributeValue(ATTR_MESH);
268 std::string nameParticipantFrom = tag.getStringAttributeValue(ATTR_FROM);
269 std::string nameParticipantTo = tag.getStringAttributeValue(ATTR_TO);
270 bool initialize = tag.getBooleanAttributeValue(ATTR_INITIALIZE);
271 bool exchangeSubsteps = tag.getBooleanAttributeValue(ATTR_EXCHANGE_SUBSTEPS);
272
273 PRECICE_CHECK(_meshConfig->hasMeshName(nameMesh) && _meshConfig->getMesh(nameMesh)->hasDataName(nameData),
274 "Mesh \"{}\" with data \"{}\" not defined. "
275 "Please check the <exchange data=\"{}\" mesh=\"{}\" from=\"{}\" to=\"{}\" /> "
276 "tag in the <coupling-scheme:... /> of your precice-config.xml.",
277 nameMesh, nameData, nameData, nameMesh, nameParticipantFrom, nameParticipantTo);
278
279 mesh::PtrMesh exchangeMesh = _meshConfig->getMesh(nameMesh);
280 PRECICE_ASSERT(exchangeMesh);
281 mesh::PtrData exchangeData = exchangeMesh->data(nameData);
282 PRECICE_ASSERT(exchangeData);
283
284 Config::Exchange newExchange{exchangeData, exchangeMesh, nameParticipantFrom, nameParticipantTo, initialize, exchangeSubsteps};
285 PRECICE_CHECK(!_config.hasExchange(newExchange),
286 R"(Data "{}" of mesh "{}" cannot be exchanged multiple times between participants "{}" and "{}". Please remove one of the exchange tags.)",
287 nameData, nameMesh, nameParticipantFrom, nameParticipantTo);
288
289 _meshConfig->addNeededMesh(nameParticipantFrom, nameMesh);
290 _meshConfig->addNeededMesh(nameParticipantTo, nameMesh);
291 _config.exchanges.emplace_back(std::move(newExchange));
292 } else if (tag.getName() == TAG_MIN_ITERATIONS) {
294 _config.minIterations = tag.getIntAttributeValue(ATTR_VALUE);
295 PRECICE_CHECK(_config.minIterations > 0,
296 "Minimum iteration limit has to be larger than zero. Please check the <min-iterations value = \"{}\" /> subtag in the <coupling-scheme:... /> of your precice-config.xml.",
297 _config.minIterations);
298 } else if (tag.getName() == TAG_MAX_ITERATIONS) {
300 _config.maxIterations = tag.getIntAttributeValue(ATTR_VALUE);
301 PRECICE_CHECK(_config.maxIterations > 0,
302 "Maximal iteration limit has to be larger than zero. "
303 "Please check the <max-iterations value=\"{0}\" /> subtag in the <coupling-scheme:... /> of your precice-config.xml. "
304 "To disable the iteration limit, remove the <max-iterations value=\"{0}\" /> subtag.",
305 _config.maxIterations);
306 }
307
308 // Additional consistency checks
309 if (_config.minIterations > 0 && _config.maxIterations > 0) {
310 PRECICE_CHECK(_config.minIterations <= _config.maxIterations,
311 "Maximum iteration limit {1} has to be larger or equal than the minimum iteration limit {0}. "
312 "Please check the <min-iterations value = \"{0}\" /> and <max-iterations value = \"{1}\" /> subtags in the <coupling-scheme:... /> of your precice-config.xml.",
313 _config.minIterations,
314 _config.maxIterations);
315 }
316}
317
319 const xml::ConfigurationContext &context,
320 xml::XMLTag &tag)
321{
323 if (tag.getNamespace() == TAG) {
326 "At least one termination condition is required "
327 "for the coupling scheme of type \"{}\". "
328 "Please add a <max-time value=\"...\"/> or <max-time-windows value=\"...\"/> tag "
329 "inside your <coupling-scheme:{}> configuration.",
330 _config.type, _config.type);
331 if (_config.type == VALUE_SERIAL_EXPLICIT) {
332 PRECICE_CHECK(!_allowRemeshing, "Remeshing is currently incompatible with serial coupling schemes. Try using a parallel or a multi coupling scheme instead.");
333 std::string accessor(_config.participants[0]);
335 addCouplingScheme(scheme, accessor);
336 //_couplingSchemes[accessor] = scheme;
337 accessor = _config.participants[1];
338 scheme = createSerialExplicitCouplingScheme(accessor);
339 addCouplingScheme(scheme, accessor);
340 //_couplingSchemes[accessor] = scheme;
341 _config = Config();
342 } else if (_config.type == VALUE_PARALLEL_EXPLICIT) {
343 std::string accessor(_config.participants[0]);
345 addCouplingScheme(scheme, accessor);
346 //_couplingSchemes[accessor] = scheme;
347 accessor = _config.participants[1];
348 scheme = createParallelExplicitCouplingScheme(accessor);
349 addCouplingScheme(scheme, accessor);
350 //_couplingSchemes[accessor] = scheme;
351 _config = Config();
352 } else if (_config.type == VALUE_SERIAL_IMPLICIT) {
353 PRECICE_CHECK(!_allowRemeshing, "Remeshing is currently incompatible with serial coupling schemes. Try using a parallel or a multi coupling scheme instead.");
355 std::string accessor(_config.participants[0]);
357 addCouplingScheme(scheme, accessor);
358 //_couplingSchemes[accessor] = scheme;
359 accessor = _config.participants[1];
360 scheme = createSerialImplicitCouplingScheme(accessor);
361 addCouplingScheme(scheme, accessor);
362 //_couplingSchemes[accessor] = scheme;
363 _config = Config();
364 } else if (_config.type == VALUE_PARALLEL_IMPLICIT) {
365 PRECICE_INFO_IF(_allowRemeshing, "Remeshing for implicit coupling schemes is in development. Currently, the acceleration data is deleted on remeshing.");
367 std::string accessor(_config.participants[0]);
369 addCouplingScheme(scheme, accessor);
370 accessor = _config.participants[1];
371 scheme = createParallelImplicitCouplingScheme(accessor);
372 addCouplingScheme(scheme, accessor);
373 _config = Config();
374 } else if (_config.type == VALUE_MULTI) {
376 PRECICE_CHECK(!_allowRemeshing, "Remeshing is currently incompatible with multi coupling schemes. Try using a parallel coupling scheme instead.");
377 PRECICE_INFO_IF(_allowRemeshing, "Remeshing for implicit coupling schemes is in development. Currently, the acceleration data is deleted on remeshing.");
379 PRECICE_CHECK(_config.setController,
380 "One controller per MultiCoupling needs to be defined. "
381 "Please check the <participant name=... /> tags in the <coupling-scheme:... /> of your precice-config.xml. "
382 "Make sure that at least one participant tag provides the attribute <participant name=... control=\"True\"/>.");
383 for (const std::string &accessor : _config.participants) {
385 addCouplingScheme(scheme, accessor);
386 }
387 _config = Config();
388 } else {
389 PRECICE_ASSERT(false, _config.type);
390 }
391 }
392}
393
395 const PtrCouplingScheme &cplScheme,
396 const std::string &participantName)
397{
398 PRECICE_TRACE(participantName);
399 if (!utils::contained(participantName, _couplingSchemes)) {
400 PRECICE_DEBUG("No coupling scheme exists for the participant");
401 // Store the new coupling scheme.
402 _couplingSchemes[participantName] = cplScheme;
403 return;
404 }
405 PRECICE_ASSERT(_couplingSchemes.count(participantName) > 0);
406
407 PRECICE_CHECK(!_allowRemeshing, "Remeshing is currently incompatible with compositional coupling schemes. If you need remeshing, try using a multi coupling scheme to compose your participants.");
408
409 // Create a composition to add the new cplScheme to
410 if (!utils::contained(participantName, _couplingSchemeCompositions)) {
411 PRECICE_DEBUG("Creating a compositional coupling scheme for the participant");
412 auto composition = std::make_shared<CompositionalCouplingScheme>();
413 composition->addCouplingScheme(_couplingSchemes[participantName]);
414 _couplingSchemeCompositions[participantName] = composition.get();
415 _couplingSchemes[participantName] = std::move(composition);
416 }
417
418 PRECICE_ASSERT(_couplingSchemeCompositions.count(participantName) > 0);
419
420 // Add the new scheme to the composition
421 auto composition = _couplingSchemeCompositions.at(participantName);
422 PRECICE_CHECK(!cplScheme->isImplicitCouplingScheme() || !composition->isImplicitCouplingScheme(),
423 "You attempted to define a second implicit coupling-scheme for the participant \"{}\", which is not allowed. "
424 "Please use a multi coupling-scheme for true implicit coupling of multiple participants.",
425 participantName);
426 _couplingSchemeCompositions[participantName]->addCouplingScheme(cplScheme);
427}
428
430 const std::string &type,
431 xml::XMLTag &tag)
432{
433 PRECICE_TRACE(type);
434 addTransientLimitTags(type, tag);
435 _config.type = type;
436 //_config.name = name;
437
438 if (type == VALUE_SERIAL_EXPLICIT) {
440 addTagExchange(tag, false);
441 } else if (type == VALUE_PARALLEL_EXPLICIT) {
443 addTagExchange(tag, false);
444 } else if (type == VALUE_PARALLEL_IMPLICIT) {
446 addTagExchange(tag, true);
454 } else if (type == VALUE_MULTI) {
456 addTagExchange(tag, true);
464 } else if (type == VALUE_SERIAL_IMPLICIT) {
466 addTagExchange(tag, true);
474 } else {
475 // If wrong coupling scheme type is provided, this is already caught by the config parser. If the assertion below is triggered, it's a bug in preCICE, not wrong usage.
476 PRECICE_ASSERT(false, "Unknown coupling scheme.");
477 }
478}
479
481 const std::string &type,
482 xml::XMLTag &tag)
483{
484 using namespace xml;
485 XMLTag tagMaxTime(*this, TAG_MAX_TIME, XMLTag::OCCUR_NOT_OR_ONCE);
486 tagMaxTime.setDocumentation("Defined the end of the simulation as total time.");
487
488 XMLAttribute<double> attrValueMaxTime(ATTR_VALUE);
489 attrValueMaxTime.setDocumentation("The value of the maximum simulation time.");
490 tagMaxTime.addAttribute(attrValueMaxTime);
491 tag.addSubtag(tagMaxTime);
492
493 XMLTag tagMaxTimeWindows(*this, TAG_MAX_TIME_WINDOWS, XMLTag::OCCUR_NOT_OR_ONCE);
494 tagMaxTimeWindows.setDocumentation("Defined the end of the simulation as a total count of time windows.");
495 XMLAttribute<int> attrValueMaxTimeWindows(ATTR_VALUE);
496 attrValueMaxTimeWindows.setDocumentation("The maximum count of time windows.");
497 tagMaxTimeWindows.addAttribute(attrValueMaxTimeWindows);
498 tag.addSubtag(tagMaxTimeWindows);
499
500 XMLTag tagTimeWindowSize(*this, TAG_TIME_WINDOW_SIZE, XMLTag::OCCUR_ONCE);
501 tagTimeWindowSize.setDocumentation("Defines the size of the time window.");
502 auto attrValueTimeWindowSize = makeXMLAttribute(ATTR_VALUE, CouplingScheme::UNDEFINED_TIME_WINDOW_SIZE)
503 .setDocumentation("The maximum time window size.");
504 tagTimeWindowSize.addAttribute(attrValueTimeWindowSize);
505 if (type == VALUE_SERIAL_EXPLICIT || type == VALUE_SERIAL_IMPLICIT) {
506 // method="first-participant" is only allowed for serial coupling schemes
507 auto attrMethod = makeXMLAttribute(ATTR_METHOD, VALUE_FIXED)
509 .setDocumentation("The method used to determine the time window size. Use `fixed` to fix the time window size for the participants.");
510 tagTimeWindowSize.addAttribute(attrMethod);
511 } else {
512 tagTimeWindowSize.addAttributeHint(ATTR_METHOD, "This feature is only available for serial coupling schemes.");
513 }
514 tag.addSubtag(tagTimeWindowSize);
515}
516
518 xml::XMLTag &tag)
519{
520 using namespace xml;
521 XMLTag tagParticipants(*this, TAG_PARTICIPANTS, XMLTag::OCCUR_ONCE);
522 tagParticipants.setDocumentation("Defines the participants of the coupling scheme.");
523 XMLAttribute<std::string> attrFirst(ATTR_FIRST);
524 attrFirst.setDocumentation("First participant to run the solver.");
525 tagParticipants.addAttribute(attrFirst);
526 XMLAttribute<std::string> attrSecond(ATTR_SECOND);
527 attrSecond.setDocumentation("Second participant to run the solver.");
528 tagParticipants.addAttribute(attrSecond);
529 tag.addSubtag(tagParticipants);
530}
531
533 xml::XMLTag &tag)
534{
535 using namespace xml;
536 XMLTag tagParticipant(*this, TAG_PARTICIPANT, XMLTag::OCCUR_ONCE_OR_MORE);
537 XMLAttribute<std::string> attrName(ATTR_NAME);
538 attrName.setDocumentation("Name of the participant.");
539 tagParticipant.addAttribute(attrName);
540 XMLAttribute<bool> attrControl(ATTR_CONTROL, false);
541 attrControl.setDocumentation("Does this participant control the coupling?");
542 tagParticipant.addAttribute(attrControl);
543 tag.addSubtag(tagParticipant);
544}
545
547 xml::XMLTag &tag, bool substepsDefault)
548{
549 using namespace xml;
550 XMLTag tagExchange(*this, TAG_EXCHANGE, XMLTag::OCCUR_ONCE_OR_MORE);
551 tagExchange.setDocumentation("Defines the flow of data between meshes of participants.");
552
553 auto attrData = XMLAttribute<std::string>(ATTR_DATA).setDocumentation("The data to exchange.");
554 tagExchange.addAttribute(attrData);
555 auto attrMesh = XMLAttribute<std::string>(ATTR_MESH).setDocumentation("The mesh which uses the data.");
556 tagExchange.addAttribute(attrMesh);
557 auto participantFrom = XMLAttribute<std::string>(ATTR_FROM).setDocumentation("The participant sending the data.");
558 tagExchange.addAttribute(participantFrom);
559 auto participantTo = XMLAttribute<std::string>(ATTR_TO).setDocumentation("The participant receiving the data.");
560 tagExchange.addAttribute(participantTo);
561 auto attrInitialize = XMLAttribute<bool>(ATTR_INITIALIZE, false).setDocumentation("Should this data be initialized during initialize?");
562 tagExchange.addAttribute(attrInitialize);
563 auto attrExchangeSubsteps = XMLAttribute<bool>(ATTR_EXCHANGE_SUBSTEPS, substepsDefault).setDocumentation("Should this data exchange substeps?");
564 tagExchange.addAttribute(attrExchangeSubsteps);
565 tag.addSubtag(tagExchange);
566}
567
569 xml::XMLTag &tag)
570{
571 using namespace xml;
572 XMLTag tagConvergenceMeasure(*this, TAG_ABS_CONV_MEASURE, XMLTag::OCCUR_ARBITRARY);
573 tagConvergenceMeasure.setDocumentation(
574 "Absolute convergence criterion based on the two-norm difference of data values between iterations.\n"
575 "\\$$\\left\\lVert H(x^k) - x^k \\right\\rVert_2 < \\text{limit}\\$$");
576 addBaseAttributesTagConvergenceMeasure(tagConvergenceMeasure);
577 XMLAttribute<double> attrLimit(ATTR_LIMIT);
578 attrLimit.setDocumentation("Limit under which the measure is considered to have converged. Must be in \\((0, 1]\\).");
579 tagConvergenceMeasure.addAttribute(attrLimit);
580 tag.addSubtag(tagConvergenceMeasure);
581}
582
584 xml::XMLTag &tag)
585{
586 using namespace xml;
587 XMLTag tagConvergenceMeasure(*this, TAG_ABS_OR_REL_CONV_MEASURE, XMLTag::OCCUR_ARBITRARY);
588 tagConvergenceMeasure.setDocumentation(
589 "Absolute or relative convergence, which is the disjunction of an absolute criterion based on the two-norm difference of data values between iterations and a relative criterion based on the relative two-norm difference of data values between iterations,i.e. convergence is reached as soon as one of the both criteria is fulfilled. "
590 "\\$$\\left\\lVert H(x^k) - x^k \\right\\rVert_2 < \\text{abs-limit}\\quad\\text{or}\\quad\\frac{\\left\\lVert H(x^k) - x^k \\right\\rVert_2}{\\left\\lVert H(x^k) \\right\\rVert_2} < \\text{rel-limit} \\$$ ");
591 addBaseAttributesTagConvergenceMeasure(tagConvergenceMeasure);
592 XMLAttribute<double> attrAbsLimit(ATTR_ABS_LIMIT);
593 attrAbsLimit.setDocumentation(R"(Absolute limit under which the measure is considered to have converged.)");
594 tagConvergenceMeasure.addAttribute(attrAbsLimit);
595 XMLAttribute<double> attrRelLimit(ATTR_REL_LIMIT);
596 attrAbsLimit.setDocumentation(R"(Relative limit under which the measure is considered to have converged. Must be in \\‍((0, 1]\\).)");
597 tagConvergenceMeasure.addAttribute(attrRelLimit);
598 tag.addSubtag(tagConvergenceMeasure);
599}
600
602 xml::XMLTag &tag)
603{
604 using namespace xml;
605 XMLTag tagConvergenceMeasure(*this, TAG_RES_REL_CONV_MEASURE,
606 XMLTag::OCCUR_ARBITRARY);
607 tagConvergenceMeasure.setDocumentation(
608 "Relative convergence criterion comparing the currently measured residual to the residual of the first iteration in the time window.\n"
609 "\\$$\\frac{\\left\\lVert H(x^k) - x^k \\right\\rVert_2}{\\left\\lVert H(x^0) - x^0 \\right\\rVert_2} < \\text{limit}\\$$");
610 addBaseAttributesTagConvergenceMeasure(tagConvergenceMeasure);
611 XMLAttribute<double> attrLimit(ATTR_LIMIT);
612 attrLimit.setDocumentation("Limit under which the measure is considered to have converged. Must be in \\((0, 1]\\).");
613 tagConvergenceMeasure.addAttribute(attrLimit);
614 tag.addSubtag(tagConvergenceMeasure);
615}
616
618 xml::XMLTag &tag)
619{
620 using namespace xml;
621 XMLTag tagConvergenceMeasure(*this, TAG_REL_CONV_MEASURE, XMLTag::OCCUR_ARBITRARY);
622 tagConvergenceMeasure.setDocumentation(
623 "Relative convergence criterion based on the relative two-norm difference of data values between iterations.\n"
624 "\\$$\\frac{\\left\\lVert H(x^k) - x^k \\right\\rVert_2}{\\left\\lVert H(x^k) \\right\\rVert_2} < \\text{limit} \\$$");
625 addBaseAttributesTagConvergenceMeasure(tagConvergenceMeasure);
626 XMLAttribute<double> attrLimit(ATTR_LIMIT);
627 attrLimit.setDocumentation(R"(Limit under which the measure is considered to have converged. Must be in \\‍((0, 1]\\).)");
628 tagConvergenceMeasure.addAttribute(attrLimit);
629 tag.addSubtag(tagConvergenceMeasure);
630}
631
633 xml::XMLTag &tag)
634{
635 using namespace xml;
636 auto attrData = XMLAttribute<std::string>(ATTR_DATA)
637 .setDocumentation("Data to be measured.");
638 tag.addAttribute(attrData);
639 auto attrMesh = XMLAttribute<std::string>(ATTR_MESH)
640 .setDocumentation("Mesh holding the data.");
641 tag.addAttribute(attrMesh);
642 auto attrSuffices = makeXMLAttribute(ATTR_SUFFICES, false)
643 .setDocumentation("If true, convergence of this measure is sufficient for overall convergence.");
644 tag.addAttribute(attrSuffices);
645 auto attrStrict = makeXMLAttribute(ATTR_STRICT, false)
646 .setDocumentation("If true, non-convergence of this measure ends the simulation. \"strict\" overrules \"suffices\".");
647 tag.addAttribute(attrStrict);
648}
649
651 xml::XMLTag &tag)
652{
653 using namespace xml;
654 XMLTag tagMinIterations(*this, TAG_MIN_ITERATIONS, XMLTag::OCCUR_NOT_OR_ONCE);
655 tagMinIterations.setDocumentation("Allows to specify a minimum amount of iterations that must be performed per time window.");
656 XMLAttribute<int> attrValue(ATTR_VALUE);
657 attrValue.setDocumentation("The minimum amount of iterations.");
658 tagMinIterations.addAttribute(attrValue);
659 tag.addSubtag(tagMinIterations);
660}
661
663 xml::XMLTag &tag)
664{
665 using namespace xml;
666 XMLTag tagMaxIterations(*this, TAG_MAX_ITERATIONS, XMLTag::OCCUR_NOT_OR_ONCE);
667 tagMaxIterations.setDocumentation("Allows to specify a maximum amount of iterations per time window.");
668 XMLAttribute<int> attrValue(ATTR_VALUE);
669 attrValue.setDocumentation("The maximum value of iterations.");
670 tagMaxIterations.addAttribute(attrValue);
671 tag.addSubtag(tagMaxIterations);
672}
673
675 xml::XMLTag &tag)
676{
678 if (!_accelerationConfig) {
679 _accelerationConfig = std::make_shared<acceleration::AccelerationConfiguration>(
681 }
682 _accelerationConfig->connectTags(tag);
683}
684
686 const std::string &dataName,
687 const std::string &meshName,
688 double limit,
689 bool suffices,
690 bool strict)
691{
693 PRECICE_CHECK(math::greater(limit, 0.0),
694 "Absolute convergence limit has to be greater than zero. "
695 "Please check the <absolute-convergence-measure limit=\"{}\" data=\"{}\" mesh=\"{}\" /> subtag "
696 "in your <coupling-scheme ... /> in the preCICE configuration file.",
697 limit, dataName, meshName);
698 ConvergenceMeasureDefintion convMeasureDef;
699 convMeasureDef.data = getData(dataName, meshName);
700 convMeasureDef.suffices = suffices;
701 convMeasureDef.strict = strict;
702 convMeasureDef.meshName = meshName;
703 convMeasureDef.measure = std::make_shared<impl::AbsoluteConvergenceMeasure>(limit);
704 _config.convergenceMeasureDefinitions.push_back(convMeasureDef);
705}
706
708 const std::string &dataName,
709 const std::string &meshName,
710 double absLimit,
711 double relLimit,
712 bool suffices,
713 bool strict)
714{
716 PRECICE_CHECK(math::greater(absLimit, 0.0),
717 "Absolute convergence limit has to be greater than zero. "
718 "Please check the <absolute-or-relative-convergence-measure abs-limit=\"{}\" rel-limit=\"{}\" data=\"{}\" mesh=\"{}\" /> subtag "
719 "in your <coupling-scheme ... /> in the preCICE configuration file.",
720 absLimit, relLimit, dataName, meshName);
721 PRECICE_CHECK(math::greater(relLimit, 0.0) && math::greaterEquals(1.0, relLimit),
722 "Relative convergence limit has to be in ]0;1]. "
723 "Please check the <absolute-or-relative-convergence-measure abs-limit=\"{}\" rel-limit=\"{}\" data=\"{}\" mesh=\"{}\" /> subtag "
724 "in your <coupling-scheme ... /> in the preCICE configuration file.",
725 absLimit, relLimit, dataName, meshName);
726 ConvergenceMeasureDefintion convMeasureDef;
727 convMeasureDef.data = getData(dataName, meshName);
728 convMeasureDef.suffices = suffices;
729 convMeasureDef.strict = strict;
730 convMeasureDef.meshName = meshName;
731 convMeasureDef.measure = std::make_shared<impl::AbsoluteOrRelativeConvergenceMeasure>(absLimit, relLimit);
732 _config.convergenceMeasureDefinitions.push_back(convMeasureDef);
733}
734
736 const std::string &dataName,
737 const std::string &meshName,
738 double limit,
739 bool suffices,
740 bool strict)
741{
743 PRECICE_CHECK(math::greater(limit, 0.0) && math::greaterEquals(1.0, limit),
744 "Relative convergence limit has to be in ]0;1]. "
745 "Please check the <relative-convergence-measure limit=\"{}\" data=\"{}\" mesh=\"{}\" /> subtag "
746 "in your <coupling-scheme ... /> in the preCICE configuration file.",
747 limit, dataName, meshName);
750 "The relative convergence limit=\"{}\" is close to the hard-coded numerical resolution=\"{}\" of preCICE. "
751 "This may lead to instabilities. The minimum relative convergence limit should be > \"{}\"",
753
754 ConvergenceMeasureDefintion convMeasureDef;
755 convMeasureDef.data = getData(dataName, meshName);
756 convMeasureDef.suffices = suffices;
757 convMeasureDef.strict = strict;
758 convMeasureDef.meshName = meshName;
759 convMeasureDef.measure = std::make_shared<impl::RelativeConvergenceMeasure>(limit);
760 _config.convergenceMeasureDefinitions.push_back(convMeasureDef);
761}
762
764 const std::string &dataName,
765 const std::string &meshName,
766 double limit,
767 bool suffices,
768 bool strict)
769{
771 PRECICE_CHECK(math::greater(limit, 0.0) && math::greaterEquals(1.0, limit),
772 "Relative convergence limit has to be in ]0;1]. "
773 "Please check the <residual-relative-convergence-measure limit=\"{}\" data=\"{}\" mesh=\"{}\" /> subtag "
774 "in your <coupling-scheme ... /> in the preCICE configuration file.",
775 limit, dataName, meshName);
778 "The relative convergence limit=\"{}\" is close to the hard-coded numerical resolution=\"{}\" of preCICE. "
779 "This may lead to instabilities. The minimum relative convergence limit should be > \"{}\"",
781
782 ConvergenceMeasureDefintion convMeasureDef;
783 convMeasureDef.data = getData(dataName, meshName);
784 convMeasureDef.suffices = suffices;
785 convMeasureDef.strict = strict;
786 convMeasureDef.meshName = meshName;
787 convMeasureDef.measure = std::make_shared<impl::ResidualRelativeConvergenceMeasure>(limit);
788 _config.convergenceMeasureDefinitions.push_back(convMeasureDef);
789}
790
792 const std::string &dataName,
793 const std::string &meshName) const
794{
795 PRECICE_CHECK(_meshConfig->hasMeshName(meshName) && _meshConfig->getMesh(meshName)->data(dataName),
796 "Data \"{}\" used by mesh \"{}\" is not configured.", dataName, meshName);
797 const mesh::PtrMesh &mesh = _meshConfig->getMesh(meshName);
798 return mesh->data(dataName);
799}
800
802 int ID) const
803{
804 for (const mesh::PtrMesh &mesh : _meshConfig->meshes()) {
805 if (mesh->hasDataID(ID)) {
806 return mesh->data(ID);
807 }
808 }
809 return nullptr;
810}
811
813 const std::string &accessor) const
814{
815 PRECICE_TRACE(accessor);
816 m2n::PtrM2N m2n = _m2nConfig->getM2N(
817 _config.participants[0], _config.participants[1]);
818 SerialCouplingScheme *scheme = new SerialCouplingScheme(_config.maxTime, _config.maxTimeWindows, _config.timeWindowSize, _config.participants[0], _config.participants[1], accessor, m2n, _config.dtMethod, BaseCouplingScheme::Explicit);
819
820 for (const auto &exchange : _config.exchanges) {
821 if ((exchange.from == _config.participants[1]) && exchange.exchangeSubsteps) {
823 "Exchange of substeps is activated in the serial-explicit coupling between the second participant \"{}\" and first participant \"{}\". This is inefficient as these substeps will never be used. You can turn this off in your preCICE configuration setting substeps=\"false\" in <exchange data=\"{}\" mesh=\"{}\" from=\"{}\" to=\"{}\" substeps=\"false\" />", exchange.from, exchange.to, exchange.data->getName(), exchange.mesh->getName(), exchange.from, exchange.to);
824 }
825 }
826
827 addDataToBeExchanged(*scheme, accessor);
828
829 return PtrCouplingScheme(scheme);
830}
831
833 const std::string &accessor) const
834{
835 PRECICE_TRACE(accessor);
837 m2n::PtrM2N m2n = _m2nConfig->getM2N(
838 _config.participants[0], _config.participants[1]);
839 ParallelCouplingScheme *scheme = new ParallelCouplingScheme(_config.maxTime, _config.maxTimeWindows, _config.timeWindowSize, _config.participants[0], _config.participants[1], accessor, m2n, BaseCouplingScheme::Explicit);
840
841 for (const auto &exchange : _config.exchanges) {
842 if (exchange.exchangeSubsteps) {
844 "Exchange of substeps is activated in the parallel-explicit coupling between \"{}\" and \"{}\". This is inefficient as these substeps will never be used. You can turn this off in your preCICE configuration setting substeps=\"false\" in <exchange data=\"{}\" mesh=\"{}\" from=\"{}\" to=\"{}\" substeps=\"false\" />", exchange.from, exchange.to, exchange.data->getName(), exchange.mesh->getName(), exchange.from, exchange.to);
845 }
846 }
847
848 addDataToBeExchanged(*scheme, accessor);
849
850 return PtrCouplingScheme(scheme);
851}
852
854 const std::string &accessor) const
855{
856 PRECICE_TRACE(accessor);
857
858 const auto first = _config.participants[0];
859 const auto second = _config.participants[1];
860
861 m2n::PtrM2N m2n = _m2nConfig->getM2N(
862 first, second);
863 SerialCouplingScheme *scheme = new SerialCouplingScheme(_config.maxTime, _config.maxTimeWindows, _config.timeWindowSize, first, second, accessor, m2n, _config.dtMethod, BaseCouplingScheme::Implicit, _config.minIterations, _config.maxIterations);
864
865 addDataToBeExchanged(*scheme, accessor);
867 "No send data configured. "
868 "Use explicit scheme for one-way coupling. "
869 "Please check your <coupling-scheme ... /> and make sure that you provide at least one <exchange .../> subtag, "
870 "where from=\"{}\".",
871 accessor);
872
873 // Add convergence measures
875 addConvergenceMeasures(scheme, second, _config.convergenceMeasureDefinitions);
876
877 // Set acceleration
878 setSerialAcceleration(scheme, first, second);
879
880 if (scheme->doesFirstStep() && _accelerationConfig->getAcceleration() && not _accelerationConfig->getAcceleration()->getPrimaryDataIDs().empty()) {
881 DataID dataID = *(_accelerationConfig->getAcceleration()->getPrimaryDataIDs().begin());
882 PRECICE_CHECK(not scheme->hasSendData(dataID),
883 "In case of serial coupling, acceleration can be defined for data of second participant only!");
884 }
885
886 return PtrCouplingScheme(scheme);
887}
888
890 const std::string &accessor) const
891{
892 PRECICE_TRACE(accessor);
894 m2n::PtrM2N m2n = _m2nConfig->getM2N(
895 _config.participants[0], _config.participants[1]);
896 ParallelCouplingScheme *scheme = new ParallelCouplingScheme(_config.maxTime, _config.maxTimeWindows, _config.timeWindowSize, _config.participants[0], _config.participants[1], accessor, m2n, BaseCouplingScheme::Implicit, _config.minIterations, _config.maxIterations);
897
898 addDataToBeExchanged(*scheme, accessor);
900 "No send data configured. Use explicit scheme for one-way coupling. "
901 "Please check your <coupling-scheme ... /> and make sure that you provide at least one <exchange .../> subtag, "
902 "where from=\"{}\".",
903 accessor);
904
905 // Add convergence measures
907 addConvergenceMeasures(scheme, _config.participants[1], _config.convergenceMeasureDefinitions);
908
909 // Set acceleration
910 setParallelAcceleration(scheme, _config.participants[1]);
911
912 return PtrCouplingScheme(scheme);
913}
914
916 const std::string &accessor) const
917{
918 PRECICE_TRACE(accessor);
920
921 BaseCouplingScheme *scheme;
922
923 std::map<std::string, m2n::PtrM2N> m2ns;
924 for (const std::string &participant : _config.participants) {
925 if (_m2nConfig->isM2NConfigured(accessor, participant)) {
926 m2ns[participant] = _m2nConfig->getM2N(accessor, participant);
927 }
928 }
929
930 scheme = new MultiCouplingScheme(
931 _config.maxTime, _config.maxTimeWindows, _config.timeWindowSize, accessor, m2ns, _config.controller, _config.minIterations, _config.maxIterations);
932
933 MultiCouplingScheme *castedScheme = dynamic_cast<MultiCouplingScheme *>(scheme);
934 PRECICE_ASSERT(castedScheme, "The dynamic cast of CouplingScheme failed.");
935 addMultiDataToBeExchanged(*castedScheme, accessor);
936
938 "No send data configured. Use explicit scheme for one-way coupling. "
939 "Please check your <coupling-scheme ... /> and make sure that you provide at least one "
940 "<exchange .../> subtag, where from=\"{}\".",
941 accessor);
942
943 // Add convergence measures
945 if (accessor == _config.controller) {
946 addConvergenceMeasures(scheme, _config.controller, _config.convergenceMeasureDefinitions);
947 }
948
949 // Set acceleration
950 setParallelAcceleration(scheme, _config.controller);
951
953 not scheme->doesFirstStep() && _accelerationConfig->getAcceleration() && _accelerationConfig->getAcceleration()->getPrimaryDataIDs().size() < 3,
954 "Due to numerical reasons, for multi coupling, the number of coupling data vectors should be at least 3, not: {}. "
955 "Please check the <data .../> subtags in your <acceleration:.../> and make sure that you have at least 3.",
956 _accelerationConfig->getAcceleration()->getPrimaryDataIDs().size());
957 return PtrCouplingScheme(scheme);
958}
959
962 const std::string &method) const
963{
964 PRECICE_TRACE(method);
965 if (method == VALUE_FIXED) {
967 } else if (method == VALUE_FIRST_PARTICIPANT) {
969 } else {
970 // We should never reach this point.
971 PRECICE_UNREACHABLE("Unknown timestepping method '{}'.", method);
972 }
973}
974
981
983{
984 if (_config.convergenceMeasureDefinitions.empty()) {
985 PRECICE_CHECK(_config.maxIterations != -1,
986 "Not defining convergence measures without providing a maximum iteration limit is forbidden. "
987 "Please define a convergence measure or set a maximum iteration limit using <max-iterations value=\"...\" />.");
988
989 PRECICE_INFO("No convergence measures were defined for an implicit coupling scheme. "
990 "It will always iterate the maximum amount iterations, which is {}. "
991 "You may want to add a convergence measure in your <coupling-scheme:.../> in your configuration.",
992 _config.maxIterations);
993 }
994}
995
997{
998 const auto &participant = _participantConfig->getParticipant(exchange.to);
999
1000 const auto &meshPtr = participant->findMesh(exchange.data->getName()); // related to https://github.com/precice/precice/issues/1694
1001
1002 if (meshPtr == nullptr) {
1003 // Only warn, because might be valid configuration, if summation action is used. See Integration/Serial/SummationActionTwoSources.
1004 PRECICE_WARN("You defined <exchange data=\"{}\" ... to=\"{}\" /> in the <coupling-scheme:... />, but <participant name=\"{}\"> has no corresponding <read-data name=\"{}\" ... />. Usually this means that there is an error in your configuration.",
1005 exchange.data->getName(), exchange.to, exchange.to, exchange.data->getName());
1006 return; // skip checks below
1007 }
1008
1009 const auto &readDataContext = participant->readDataContext(meshPtr->getName(), exchange.data->getName());
1010 if (readDataContext.getWaveformDegree() == 0) {
1012 "You configured <data:scalar/vector name=\"{}\" waveform-degree=\"{}\" />. Please deactivate exchange of substeps by setting substeps=\"false\" in the following exchange tag of your coupling scheme: <exchange data=\"{}\" mesh=\"{}\" from=\"{}\" to=\"{}\" />. Reason: For constant interpolation no exchange of data for substeps is needed. Please consider using waveform-degree=\"1\" or higher, if you want to use subcycling.",
1013 readDataContext.getDataName(), readDataContext.getWaveformDegree(), exchange.data->getName(), exchange.mesh->getName(), exchange.from, exchange.to);
1014 } else if (readDataContext.getWaveformDegree() >= 2) {
1016 "You configured <data:scalar/vector name=\"{}\" waveform-degree=\"{}\" />. Please activate exchange of substeps by setting substeps=\"true\" in the following exchange tag of your coupling scheme: <exchange data=\"{}\" mesh=\"{}\" from=\"{}\" to=\"{}\" />. Reason: For higher-order interpolation exchange of data for substeps is required. If you don't want to activate exchange of additional data, please consider using waveform-degree=\"1\". Note that deactivating exchange of substep data might lead to worse results, if you use subcycling.",
1017 readDataContext.getDataName(), readDataContext.getWaveformDegree(), exchange.data->getName(), exchange.mesh->getName(), exchange.from, exchange.to);
1018 } else { // For first degree there is no restriction for exchange of substeps
1019 PRECICE_ASSERT(readDataContext.getWaveformDegree() == 1);
1020 }
1021}
1022
1024 BiCouplingScheme &scheme,
1025 const std::string &accessor) const
1026{
1027 PRECICE_TRACE();
1028 for (const Config::Exchange &exchange : _config.exchanges) {
1029 const std::string &from = exchange.from;
1030 const std::string &to = exchange.to;
1031 const std::string &dataName = exchange.data->getName();
1032 const std::string &meshName = exchange.mesh->getName();
1033
1034 PRECICE_CHECK(to != from,
1035 "You cannot define an exchange from and to the same participant. "
1036 "Please check the <exchange data=\"{}\" mesh=\"{}\" from=\"{}\" to=\"{}\" /> tag in the <coupling-scheme:... /> of your precice-config.xml.",
1037 dataName, meshName, from, to);
1038
1039 PRECICE_CHECK((utils::contained(from, _config.participants) || from == _config.controller),
1040 "Participant \"{}\" is not configured for coupling scheme. "
1041 "Please check the <exchange data=\"{}\" mesh=\"{}\" from=\"{}\" to=\"{}\" /> tag in the <coupling-scheme:... /> of your precice-config.xml.",
1042 from, dataName, meshName, from, to);
1043
1044 PRECICE_CHECK((utils::contained(to, _config.participants) || to == _config.controller),
1045 "Participant \"{}\" is not configured for coupling scheme. "
1046 "Please check the <exchange data=\"{}\" mesh=\"{}\" from=\"{}\" to=\"{}\" /> tag in the <coupling-scheme:... /> of your precice-config.xml.",
1047 to, dataName, meshName, from, to);
1048
1049 const bool requiresInitialization = exchange.requiresInitialization;
1050
1052 !(requiresInitialization && _participantConfig->getParticipant(from)->isDirectAccessAllowed(exchange.mesh->getName())),
1053 "Participant \"{}\" cannot initialize data of the directly-accessed mesh \"{}\" from the participant\"{}\". "
1054 "Either disable the initialization in the <exchange /> tag or use a locally provided mesh instead.",
1055 from, meshName, to);
1056
1057 const bool exchangeSubsteps = exchange.exchangeSubsteps;
1058
1059 if (from == accessor) {
1060 scheme.addDataToSend(exchange.data, exchange.mesh, requiresInitialization, exchangeSubsteps);
1061 } else if (to == accessor) {
1063 scheme.addDataToReceive(exchange.data, exchange.mesh, requiresInitialization, exchangeSubsteps);
1064 } else {
1066 }
1067 }
1069}
1070
1072 MultiCouplingScheme &scheme,
1073 const std::string &accessor) const
1074{
1075 PRECICE_TRACE();
1076 for (const Config::Exchange &exchange : _config.exchanges) {
1077 const std::string &from = exchange.from;
1078 const std::string &to = exchange.to;
1079 const std::string &dataName = exchange.data->getName();
1080 const std::string &meshName = exchange.mesh->getName();
1081
1082 PRECICE_CHECK(to != from,
1083 "You cannot define an exchange from and to the same participant. "
1084 "Please check the <exchange data=\"{}\" mesh=\"{}\" from=\"{}\" to=\"{}\" /> tag in the <coupling-scheme:... /> of your precice-config.xml.",
1085 dataName, meshName, from, to);
1086
1087 PRECICE_CHECK((utils::contained(from, _config.participants) || from == _config.controller),
1088 "Participant \"{}\" is not configured for coupling scheme",
1089 from);
1090
1091 PRECICE_CHECK((utils::contained(to, _config.participants) || to == _config.controller),
1092 "Participant \"{}\" is not configured for coupling scheme", to);
1093
1094 const bool initialize = exchange.requiresInitialization;
1095 const bool exchangeSubsteps = exchange.exchangeSubsteps;
1096
1097 if (from == accessor) {
1098 scheme.addDataToSend(exchange.data, exchange.mesh, initialize, exchangeSubsteps, to);
1099 } else if (to == accessor) {
1100 scheme.addDataToReceive(exchange.data, exchange.mesh, initialize, exchangeSubsteps, from);
1101 }
1102 }
1104}
1105
1107 DataID dataID, std::string_view participant) const
1108{
1109 const auto match = std::find_if(_config.exchanges.begin(),
1110 _config.exchanges.end(),
1111 [dataID, participant](const Config::Exchange &exchange) {
1112 // handle multi coupling
1113 if (exchange.from != participant && exchange.to != participant) {
1114 return false;
1115 } else {
1116 return exchange.data->getID() == dataID;
1117 }
1118 });
1119 if (match != _config.exchanges.end()) {
1120 return;
1121 }
1122
1123 // Data is not being exchanged
1124 std::string dataName = "";
1125 auto dataptr = findDataByID(dataID);
1126 if (dataptr) {
1127 dataName = dataptr->getName();
1128 }
1129
1130 PRECICE_ERROR("You need to exchange every data that you use for convergence measures and/or the iteration acceleration. "
1131 "Data \"{}\" is currently not exchanged over the respective mesh of participant \"{}\" on which it is used for convergence measures and/or iteration acceleration. "
1132 "Please check the <exchange ... /> and <...-convergence-measure ... /> tags in the <coupling-scheme:... /> of your precice-config.xml.",
1133 dataName, participant);
1134}
1135
1137 int dataID,
1138 const std::string &first,
1139 const std::string &second) const
1140{
1141 checkIfDataIsExchanged(dataID, second);
1142 const auto match = std::find_if(_config.exchanges.begin(),
1143 _config.exchanges.end(),
1144 [dataID](const Config::Exchange &exchange) { return exchange.data->getID() == dataID; });
1145 PRECICE_ASSERT(match != _config.exchanges.end());
1146 const auto &exchange = *match;
1147
1148 // In serial implicit cplschemes, data is only accelerated on the second participant.
1149 if (second == exchange.from) {
1150 return;
1151 }
1152
1153 std::string dataName = "";
1154 auto dataptr = findDataByID(dataID);
1155 if (dataptr) {
1156 dataName = dataptr->getName();
1157 }
1158
1160 "You configured acceleration data \"{}\" in the serial implicit coupling scheme between participants \"{}\" and \"{}\". "
1161 "For serial implicit coupling schemes, only data exchanged from the second to the first participant can be used for acceleration. "
1162 "Here, from \"{}\" to \"{}\". "
1163 "However, you configured data \"{}\" for acceleration, which is exchanged from \"{}\" to \"{}\". "
1164 "Please remove this acceleration data tag or switch to a parallel implicit coupling scheme.",
1165 dataName, first, second, second, first, dataName, first, second);
1166}
1167
1169 BaseCouplingScheme *scheme,
1170 const std::string &participant,
1171 const std::vector<ConvergenceMeasureDefintion> &convergenceMeasureDefinitions) const
1172{
1173 for (auto &elem : convergenceMeasureDefinitions) {
1174 _meshConfig->addNeededMesh(participant, elem.meshName);
1175 checkIfDataIsExchanged(elem.data->getID(), participant);
1176 scheme->addConvergenceMeasure(elem.data->getID(), elem.suffices, elem.strict, elem.measure);
1177 }
1178}
1179
1181 BaseCouplingScheme *scheme,
1182 const std::string &first,
1183 const std::string &second) const
1184{
1185 if (_accelerationConfig->getAcceleration().get() != nullptr) {
1186 for (std::string &neededMesh : _accelerationConfig->getNeededMeshes()) {
1187 _meshConfig->addNeededMesh(second, neededMesh);
1188 }
1189 for (const DataID dataID : _accelerationConfig->getAcceleration()->getPrimaryDataIDs()) {
1190 checkSerialImplicitAccelerationData(dataID, first, second);
1191 }
1192 scheme->setAcceleration(_accelerationConfig->getAcceleration());
1193 }
1194}
1195
1197 BaseCouplingScheme *scheme,
1198 const std::string &participant) const
1199{
1200 if (_accelerationConfig->getAcceleration().get() != nullptr) {
1201 for (std::string &neededMesh : _accelerationConfig->getNeededMeshes()) {
1202 _meshConfig->addNeededMesh(participant, neededMesh);
1203 }
1204 for (const DataID dataID : _accelerationConfig->getAcceleration()->getPrimaryDataIDs()) {
1205 checkIfDataIsExchanged(dataID, participant);
1206 }
1207 scheme->setAcceleration(_accelerationConfig->getAcceleration());
1208
1210 dynamic_cast<acceleration::AitkenAcceleration *>(_accelerationConfig->getAcceleration().get()) != nullptr,
1211 "You configured participant \"{}\" in a parallel-implicit coupling scheme with \"Aitken\" "
1212 "acceleration, which is known to perform bad in parallel coupling schemes. "
1213 "See https://precice.org/configuration-acceleration.html#dynamic-aitken-under-relaxation for details. "
1214 "Consider switching to a serial-implicit coupling scheme or changing the acceleration method.",
1215 participant);
1216 }
1217}
1218
1220 bool allowed)
1221{
1222 _allowRemeshing = allowed;
1223}
1224
1225} // namespace precice::cplscheme
#define PRECICE_ERROR(...)
Definition LogMacros.hpp:16
#define PRECICE_WARN_IF(condition,...)
Definition LogMacros.hpp:18
#define PRECICE_WARN(...)
Definition LogMacros.hpp:12
#define PRECICE_DEBUG(...)
Definition LogMacros.hpp:61
#define PRECICE_TRACE(...)
Definition LogMacros.hpp:92
#define PRECICE_INFO_IF(condition,...)
Definition LogMacros.hpp:25
#define PRECICE_INFO(...)
Definition LogMacros.hpp:14
#define PRECICE_CHECK(check,...)
Definition LogMacros.hpp:32
#define PRECICE_ASSERT(...)
Definition assertion.hpp:85
#define PRECICE_UNREACHABLE(...)
Definition assertion.hpp:93
const std::string & getName() const
Returns the name of the mesh, as set in the config file.
Definition Mesh.cpp:242
const DataContainer & data() const
Allows access to all data.
Definition Mesh.cpp:194
Abstract base class for standard coupling schemes.
void setAcceleration(const acceleration::PtrAcceleration &acceleration)
Set an acceleration technique.
void addConvergenceMeasure(int dataID, bool suffices, bool strict, impl::PtrConvergenceMeasure measure)
Adds a measure to determine the convergence of coupling iterations.
bool doesFirstStep() const
Getter for _doesFirstStep.
Abstract base class for coupling schemes with two participants.
void addDataToReceive(const mesh::PtrData &data, mesh::PtrMesh mesh, bool requiresInitialization, bool exchangeSubsteps)
Adds data to be received on data exchange.
void addDataToSend(const mesh::PtrData &data, mesh::PtrMesh mesh, bool requiresInitialization, bool exchangeSubsteps)
Adds data to be sent on data exchange and possibly be modified during coupling iterations.
void determineInitialDataExchange() override
Determines which data is initialized and therefore has to be exchanged during initialize.
PtrCouplingScheme createSerialExplicitCouplingScheme(const std::string &accessor) const
void checkIterationLimits() const
Helper function to check iteration limits in conjunction with convergence measures.
const PtrCouplingScheme & getCouplingScheme(const std::string &participantName) const
Returns the configured coupling scheme.
precice::config::PtrParticipantConfiguration _participantConfig
void addMultiDataToBeExchanged(MultiCouplingScheme &scheme, const std::string &accessor) const
Adds configured exchange data to be sent or received to scheme. Only used specifically for MultiCoupl...
PtrCouplingScheme createSerialImplicitCouplingScheme(const std::string &accessor) const
void xmlEndTagCallback(const xml::ConfigurationContext &context, xml::XMLTag &callingTag) override
Callback method required when using xml::XMLTag.
void xmlTagCallback(const xml::ConfigurationContext &context, xml::XMLTag &callingTag) override
Callback method required when using xml::XMLTag.
void setSerialAcceleration(BaseCouplingScheme *scheme, const std::string &first, const std::string &second) const
void addResidualRelativeConvergenceMeasure(const std::string &dataName, const std::string &meshName, double limit, bool suffices, bool strict)
mesh::PtrData getData(const std::string &dataName, const std::string &meshName) const
void addAbsoluteConvergenceMeasure(const std::string &dataName, const std::string &meshName, double limit, bool suffices, bool strict)
void addDataToBeExchanged(BiCouplingScheme &scheme, const std::string &accessor) const
Adds configured exchange data to be sent or received to scheme.
struct precice::cplscheme::CouplingSchemeConfiguration::Config _config
void checkSubstepExchangeWaveformDegree(const Config::Exchange &exchange) const
Helper function to check that waveform-degree and substep exchange are compatible.
constants::TimesteppingMethod getTimesteppingMethod(const std::string &method) const
void checkSerialImplicitAccelerationData(DataID dataID, const std::string &first, const std::string &second) const
acceleration::PtrAccelerationConfiguration _accelerationConfig
std::map< std::string, PtrCouplingScheme > _couplingSchemes
Map from participant name to coupling scheme (composition).
void checkIfDataIsExchanged(DataID dataID, std::string_view participant) const
CouplingSchemeConfiguration(xml::XMLTag &parent, mesh::PtrMeshConfiguration meshConfig, m2n::M2NConfiguration::SharedPointer m2nConfig, config::PtrParticipantConfiguration participantConfig)
Constructor.
void addTagExchange(xml::XMLTag &tag, bool substepsDefault)
void addTypespecifcSubtags(const std::string &type, xml::XMLTag &tag)
PtrCouplingScheme createMultiCouplingScheme(const std::string &accessor) const
void addCouplingScheme(const PtrCouplingScheme &cplScheme, const std::string &participantName)
Adds a manually configured coupling scheme for a participant.
bool hasCouplingScheme(const std::string &participantName) const
Check, if a coupling scheme is configured for a participant.
void updateConfigForImplicitCoupling()
Helper to update some configs which may have a different meaning in implicit coupling.
void addAbsoluteOrRelativeConvergenceMeasure(const std::string &dataName, const std::string &meshName, double absLimit, double relLimit, bool suffices, bool strict)
PtrCouplingScheme createParallelImplicitCouplingScheme(const std::string &accessor) const
PtrCouplingScheme createParallelExplicitCouplingScheme(const std::string &accessor) const
void addTransientLimitTags(const std::string &type, xml::XMLTag &tag)
void addRelativeConvergenceMeasure(const std::string &dataName, const std::string &meshName, double limit, bool suffices, bool strict)
std::map< std::string, CompositionalCouplingScheme * > _couplingSchemeCompositions
If a participant has more than one coupling scheme, a composition is created.
void addConvergenceMeasures(BaseCouplingScheme *scheme, const std::string &participant, const std::vector< ConvergenceMeasureDefintion > &convergenceMeasureDefinitions) const
void setParallelAcceleration(BaseCouplingScheme *scheme, const std::string &participant) const
static const int INFINITE_MAX_ITERATIONS
To be used, when the number of max iterations is infinite (for implicit coupling).
static const double UNDEFINED_MAX_TIME
Does not define a time limit for the coupled simulation.
static const int UNDEFINED_MAX_ITERATIONS
To be used, when the number of max iterations is not defined (for explicit coupling).
static const double UNDEFINED_TIME_WINDOW_SIZE
To be used, when the time window size is determined dynamically during the coupling.
static const int UNDEFINED_TIME_WINDOWS
Does not define limit on time windows for the coupled simulation.
A coupling scheme with multiple participants.
void addDataToSend(const mesh::PtrData &data, mesh::PtrMesh mesh, bool requiresInitialization, bool exchangeSubsteps, const std::string &to)
Adds data to be sent on data exchange and possibly be modified during coupling iterations.
void determineInitialDataExchange() override
Determines which data is initialized and therefore has to be exchanged during initialize.
void addDataToReceive(const mesh::PtrData &data, mesh::PtrMesh mesh, bool requiresInitialization, bool exchangeSubsteps, const std::string &from)
Adds data to be received on data exchange.
Coupling scheme for parallel coupling, i.e. simultaneous execution of two coupled participants.
Coupling scheme for serial coupling, i.e. staggered execution of two coupled participants.
std::shared_ptr< M2NConfiguration > SharedPointer
Represents an XML tag to be configured automatically.
Definition XMLTag.hpp:28
const std::string & getNamespace() const
Returns xml namespace.
Definition XMLTag.hpp:159
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
XMLTag & setDocumentation(std::string_view documentation)
Adds a description of the purpose of this XML tag.
Definition XMLTag.cpp:29
const std::string & getName() const
Returns name (without namespace).
Definition XMLTag.hpp:153
const std::string & getFullName() const
Returns full name consisting of xml namespace + ":" + name.
Definition XMLTag.hpp:170
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
XMLTag & addAttribute(const XMLAttribute< double > &attribute)
Adds a XML attribute by making a copy of the given attribute.
Definition XMLTag.cpp:53
XMLTag & addSubtag(const XMLTag &tag)
Adds an XML tag as subtag by making a copy of the given tag.
Definition XMLTag.cpp:41
vector< double > getData()
Definition mainA.cpp:19
std::shared_ptr< ParticipantConfiguration > PtrParticipantConfiguration
contains implementations of coupling schemes for coupled simulations.
std::shared_ptr< CouplingScheme > PtrCouplingScheme
contains the logic of the parallel communication between participants.
Definition BoundM2N.cpp:12
std::shared_ptr< M2N > PtrM2N
constexpr double NUMERICAL_ZERO_DIFFERENCE
std::enable_if< std::is_arithmetic< Scalar >::value, bool >::type greaterEquals(Scalar A, Scalar B, Scalar tolerance=NUMERICAL_ZERO_DIFFERENCE)
std::enable_if< std::is_arithmetic< Scalar >::value, bool >::type greater(Scalar A, Scalar B, Scalar tolerance=NUMERICAL_ZERO_DIFFERENCE)
provides Mesh, Data and primitives.
std::shared_ptr< Data > PtrData
std::shared_ptr< Mesh > PtrMesh
std::shared_ptr< MeshConfiguration > PtrMeshConfiguration
bool contained(const ELEMENT_T &element, const std::vector< ELEMENT_T > &vec)
Returns true, if given element is in vector, otherwise false.
Definition Helpers.hpp:38
contains the XML configuration parser.
int DataID
Definition Types.hpp:25
STL namespace.
Tightly coupled to the parameters of Participant()
Definition XMLTag.hpp:21