MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
rigidbodies.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#include "rigidbodies.h"
8#include "COMM/mpiexchange.h"
9#include "COMM/mpioverride.h"
11#include "IO/parallelio.h"
12#include "UTIL/maiamath.h"
13#include "typetraits.h"
14
15
16#include <algorithm>
17#include <functional>
18#include <iomanip>
19
31template <MInt nDim>
32RigidBodies<nDim>::RigidBodies(const MInt solverId_, GridProxy& gridProxy_, Geom& geometry_, MPI_Comm comm_)
33 : maia::CartesianSolver<nDim, RigidBodies<nDim>>(solverId_, gridProxy_, comm_), m_geometry(&geometry_) {
34 TRACE();
35
36 initTimers();
38
39#ifdef RB_DEBUG
40 m_debugFileStream.open("d" + std::to_string(domainId()) + ".txt");
41#endif
42
44
45 if(!domainId() && !m_restart) {
47 }
48
49 // create body communication mappings
54// for indirect neighbors (large bodies, to be improved)
55// exchangeNeighborConnectionInfo();
56#ifdef RB_DEBUG
58#endif
59 RECORD_TIMER_STOP(m_timers[Timers::Constructor]);
60}
61
67template <MInt nDim>
69 TRACE();
70 // Close stream
71 if(!domainId()) {
72 m_anglog.close();
73 }
74
75#ifdef RB_DEBUG
76 m_debugFileStream.close();
77#endif
78 // Deallocate memory
79
80 // stop timer
81 RECORD_TIMER_STOP(m_timers[Timers::Class]);
82
83 averageTimer();
84 printScalingVariables();
85}
86
87template <MInt nDim>
89 TRACE();
90
91 // Create timer group and coupler timer, and start the timer
92 NEW_TIMER_GROUP_NOCREATE(m_timers[Timers::TimerGroup], "RigidBodies");
93 NEW_TIMER_NOCREATE(m_timers[Timers::Class], "Total object lifetime", m_timers[Timers::TimerGroup]);
94 RECORD_TIMER_START(m_timers[Timers::Class]);
95
96 // Create and start constructor timer
97 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Constructor], "Constructor", m_timers[Timers::Class]);
98 RECORD_TIMER_START(m_timers[Timers::Constructor]);
99
100 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SolutionStep], "Solution Step", m_timers[Timers::Class]);
101
102 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Predict], "Predict", m_timers[Timers::SolutionStep]);
103 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Correct], "Correct", m_timers[Timers::SolutionStep]);
104
105 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Communication], "Communication", m_timers[Timers::SolutionStep]);
106 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::UpdateCommunication], "Update Communication", m_timers[Timers::SolutionStep]);
107}
108
109template <MInt nDim>
111 TRACE();
112 if(!grid().isActive()) return;
113
114 m_timerType = "max";
115 m_timerType = Context::getSolverProperty<MString>("timerType", m_solverId, AT_, &m_timerType);
116
117 // 0) map timer ids for safety
118
119 const MInt noTimers = m_timers.size();
120
121 // 1) fill buffer with local timer values
122 std::vector<MFloat> timerValues_;
123 timerValues_.reserve(noTimers);
124 for(MInt i = 0; i < noTimers; i++) {
125 timerValues_.emplace_back(RETURN_TIMER_TIME(m_timers[i]));
126 }
127
128 // 2) collect values from all ranks
129 if(m_timerType == "average") {
130 MPI_Allreduce(MPI_IN_PLACE, timerValues_.data(), noTimers, maia::type_traits<MFloat>::mpiType(), MPI_SUM, mpiComm(),
131 AT_, "MPI_IN_PLACE", "timerValues_");
132 } else {
133 MPI_Allreduce(MPI_IN_PLACE, timerValues_.data(), noTimers, maia::type_traits<MFloat>::mpiType(), MPI_MAX, mpiComm(),
134 AT_, "MPI_IN_PLACE", "timerValues_");
135 }
136
137 // 3) perform averaging on timer and4) set new timer values
138 if(m_timerType == "average") {
139 const MInt noDomains_ = noDomains();
140 for(MInt i = 0; i < noTimers; i++) {
141 const MFloat meanValue = timerValues_[i] / noDomains_;
142 SET_RECORD(m_timers[i], meanValue);
143 }
144 } else {
145 for(MInt i = 0; i < noTimers; i++) {
146 SET_RECORD(m_timers[i], timerValues_[i]);
147 }
148 }
149}
150
157template <MInt nDim>
159 TRACE();
160
161 m_outputDir = "./";
162 m_outputDir = Context::getSolverProperty<MString>("outputDir", m_solverId, AT_, &m_outputDir);
163
164 m_printKineticEnergy = false;
165 Context::getSolverProperty<MBool>("printKineticEnergy", m_solverId, AT_, &m_printKineticEnergy);
166
167 m_intervalBodyLog = 1;
168 m_intervalBodyLog = Context::getSolverProperty<MInt>("intervalBodyLog", m_solverId, AT_, &m_intervalBodyLog);
169
170 // restart related Properties
171 m_restart = false;
172 m_restart = Context::getSolverProperty<MBool>("restartFile", m_solverId, AT_, &m_restart);
173
174 m_restartTimeStep = 0;
175 m_restartTimeStep = Context::getSolverProperty<MInt>("restartTimeStep", m_solverId, AT_, &m_restartTimeStep);
176
177 m_restartDir = Context::getSolverProperty<MString>("restartDir", m_solverId, AT_, &m_outputDir);
178
179 m_bodyCenterInitMethod = "POINT";
180 m_bodyCenterInitMethod =
181 Context::getSolverProperty<MString>("bodyCenterInitMethod", m_solverId, AT_, &m_bodyCenterInitMethod);
182
183 if(!m_restart) {
184 if(m_bodyCenterInitMethod == "BOX_SEED") {
185 boxSeedInitialize();
186 } else if(m_bodyCenterInitMethod == "POINT") {
187 m_noEmbeddedBodies = Context::getSolverProperty<MInt>("noEmbeddedBodies", m_solverId, AT_, &m_noEmbeddedBodies);
188
189 const MInt num_initialBodyCenters = Context::propertyLength("initialBodyCenters", m_solverId);
190 for(MInt i = 0; i < num_initialBodyCenters; i++) {
191 m_initialBodyCenters.emplace_back(Context::getSolverProperty<MFloat>("initialBodyCenters", m_solverId, AT_, i));
192 }
193 }
194 }
195
196 m_maxNoBodies = m_noEmbeddedBodies;
197 m_maxNoBodies = Context::getSolverProperty<MInt>("maxNoBodies", m_solverId, AT_, &m_maxNoBodies);
198
199 m_forcedMotion = Context::getSolverProperty<MBool>("forcedMotion", m_solverId, AT_, &m_forcedMotion);
200
201 m_bodyType = 1;
202 m_bodyType = Context::getSolverProperty<MInt>("bodyTypeMb", m_solverId, AT_, &m_bodyType);
203
204 const MInt num_initBodyRadius = Context::propertyLength("bodyRadius", m_solverId);
205 for(MInt i = 0; i < num_initBodyRadius; i++) {
206 m_initBodyRadius.emplace_back(Context::getSolverProperty<MFloat>("bodyRadius", m_solverId, AT_, i));
207 }
208
209 const MInt num_initBodyRadii = Context::propertyLength("bodyRadii", m_solverId);
210 for(MInt i = 0; i < num_initBodyRadii; i++) {
211 m_initBodyRadii.emplace_back(Context::getSolverProperty<MFloat>("bodyRadii", m_solverId, AT_, i));
212 }
213
214 m_bodyHeight = 1.0;
215 m_bodyHeight = Context::getSolverProperty<MFloat>("bodyHeight", m_solverId, AT_, &m_bodyHeight);
216
217 m_uRef = 1.0;
218 m_uRef = Context::getSolverProperty<MFloat>("uRef", m_solverId, AT_, &m_uRef);
219
220 m_logBodyData = false;
221 m_logBodyData = Context::getSolverProperty<MBool>("logBodyData", m_solverId, AT_, &m_logBodyData);
222
223 // Array-like properties
224 const MInt num_initBodyDensityRatios = Context::propertyLength("bodyDensityRatio", m_solverId);
225 for(MInt i = 0; i < num_initBodyDensityRatios; i++) {
226 m_initBodyDensityRatios.emplace_back(Context::getSolverProperty<MFloat>("bodyDensityRatio", m_solverId, AT_, i));
227 }
228
229 if(Context::propertyExists("gravity", m_solverId)) {
230 for(MInt n = 0; n < nDim; n++) {
231 gravity[n] = Context::getSolverProperty<MFloat>("gravity", m_solverId, AT_, n);
232 gravity[n] /= POW2(m_uRef);
233 }
234 }
235
236 // TODO labels:DOC,toenhance Change to per-body value
237 m_uniformBodyTemperature = F1;
238 m_uniformBodyTemperature =
239 Context::getSolverProperty<MFloat>("uniformBodyTemperature", m_solverId, AT_, &m_uniformBodyTemperature);
240
241 // allow translation
242 m_translation = true;
243 m_translation = Context::getSolverProperty<MBool>("translation", m_solverId, AT_, &m_translation);
244
245 // allow rotation
246 m_rotation = true;
247 m_rotation = Context::getSolverProperty<MBool>("integrateRotation", m_solverId, AT_, &m_rotation);
248
249 // allow rotation only around z-axis
250 m_rotXYaxis = true;
251 m_rotXYaxis = Context::getSolverProperty<MBool>("rotXYaxis", m_solverId, AT_, &m_rotXYaxis);
252}
253
260template <MInt nDim>
262 TRACE();
263
264 if(m_restart) {
265 loadBodiesSizeAndPosition();
266 }
267
268 findLocalBodies();
269
270 m_bodies.reset(m_maxNoBodies);
271
272 // Create Mapping
273 for(MInt i = 0; i < noNeighborDomains(); i++) {
274 MInt globDomain = neighborDomain(i);
275 m_remoteDomainLocalBodies[globDomain] = std::vector<MInt>();
276 m_homeDomainRemoteBodies[globDomain] = std::vector<MInt>();
277 }
278
279 m_bodies.append(m_noLocalBodies);
280
281 if(m_noLocalBodies == 0 && !m_restart) return;
282
283 // Init bodyRadius and bodyRadii via bodyRadius
284 if(!m_initBodyRadius.empty()) {
285 // If only one radius is given, use for all bodies
286 if(m_initBodyRadius.size() == 1) {
287 const MFloat defaultRadius = m_initBodyRadius[0];
288 std::fill_n(&a_bodyRadius(0), m_noLocalBodies, defaultRadius);
289 std::fill_n(&a_bodyRadii(0, 0), m_noLocalBodies * nDim, defaultRadius);
290 } else {
291 for(MUint bodyId = 0; bodyId < m_initBodyRadius.size(); bodyId++) {
292 a_bodyRadius(bodyId) = m_initBodyRadius[getGlobalBodyId(bodyId)];
293 std::fill_n(&a_bodyRadii(bodyId, 0), nDim, m_initBodyRadius[getGlobalBodyId(bodyId)]);
294 }
295 }
296 }
297
298 // Init bodyRadii via bodyRadii
299 if(!m_initBodyRadii.empty()) {
300 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
301 // If only one set of radii is given, use for all bodies
302 if(m_initBodyRadii.size() == nDim) {
303 for(MInt n = 0; n < nDim; n++) {
304 a_bodyRadii(bodyId, n) = m_initBodyRadii[n];
305 }
306 } else {
307 for(MInt n = 0; n < nDim; n++) {
308 a_bodyRadii(bodyId, n) = m_initBodyRadii[getGlobalBodyId(bodyId) * nDim + n];
309 }
310 }
311 }
312 }
313
314 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
315 for(MInt n = 0; n < nRot; n++) {
316 a_angularVelocityT1(bodyId, n) = 0.0;
317 a_angularAccelerationT1(bodyId, n) = 0.0;
318 }
319 }
320
321 if(!m_forcedMotion) {
322 if(m_initBodyDensityRatios.size() > 1) {
323 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
324 a_bodyDensityRatio(bodyId) = m_initBodyDensityRatios[getGlobalBodyId(bodyId)];
325 }
326 } else if(m_initBodyDensityRatios.size() == 1) {
327 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
328 a_bodyDensityRatio(bodyId) = m_initBodyDensityRatios[0];
329 }
330 } else {
331 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
332 a_bodyDensityRatio(bodyId) = 1.0;
333 }
334 }
335
336 // Init rotational data
337 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
338 for(MInt n = 0; n < nRot; n++) {
339 a_bodyInertia(bodyId, n) = 1.0;
340 a_angularVelocityT1B2(bodyId, n) = 0.0;
341 a_angularVelocityBodyT1(bodyId, n) = 0.0;
342 a_angularVelocityBodyT1B2(bodyId, n) = 0.0;
343 a_angularAccelerationBody(bodyId, n) = 0.0;
344 a_torqueT1(bodyId, n) = 0.0;
345 }
346 }
347
348 // Init bodyQuaternion and moment of inertia
349 IF_CONSTEXPR(nDim == 3) {
350 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
351 for(MInt n = 0; n < nQuat - 1; n++) {
352 a_bodyQuaternionT1B2(bodyId, n) = 0;
353 a_bodyQuaternionT1(bodyId, n) = 0;
354 }
355 a_bodyQuaternionT1B2(bodyId, nQuat - 1) = 1.0;
356 a_bodyQuaternionT1(bodyId, nQuat - 1) = 1.0;
357 a_bodyInertia(bodyId, 0) =
358 (POW2(a_bodyRadii(bodyId, 1)) + POW2(a_bodyRadii(bodyId, 2))) / 5.0 * a_bodyMass(bodyId);
359 a_bodyInertia(bodyId, 1) =
360 (POW2(a_bodyRadii(bodyId, 0)) + POW2(a_bodyRadii(bodyId, 2))) / 5.0 * a_bodyMass(bodyId);
361 a_bodyInertia(bodyId, 2) =
362 (POW2(a_bodyRadii(bodyId, 0)) + POW2(a_bodyRadii(bodyId, 1))) / 5.0 * a_bodyMass(bodyId);
363 }
364 }
365 }
366
367 if(m_restart) {
368 loadBodyRestartFile();
369 // Init remaining values
370 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
371 a_bodyHeatFlux(bodyId) = 0.0;
372 const MInt tmpGlobalId = getGlobalBodyId(bodyId);
373
374 a_bodyTemperature(bodyId) = m_bResFile.bodyTemperature(tmpGlobalId);
375 for(MInt n = 0; n < nDim; n++) {
376 a_bodyCenter(bodyId, n) = m_bResFile.bodyCenter(tmpGlobalId, n);
377 a_bodyVelocity(bodyId, n) = m_bResFile.bodyVelocity(tmpGlobalId, n);
378 a_bodyAcceleration(bodyId, n) = m_bResFile.bodyAcceleration(tmpGlobalId, n);
379 }
380 for(MInt r = 0; r < nRot; r++) {
381 a_angularVelocityBodyT1B2(bodyId, r) = m_bResFile.angularVelocityBodyT1B2(tmpGlobalId, r);
382 a_angularAccelerationBody(bodyId, r) = m_bResFile.angularAccelerationBody(tmpGlobalId, r);
383 }
384 for(MInt q = 0; q < nQuat; q++) {
385 a_bodyQuaternionT1B2(bodyId, q) = m_bResFile.bodyQuaternionT1B2(tmpGlobalId, q);
386 a_bodyQuaternionT1(bodyId, q) = m_bResFile.bodyQuaternionT1(tmpGlobalId, q);
387 }
388 }
389 } else {
390 // Set init body values
391 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
392 for(MInt n = 0; n < nDim; n++) {
393 a_bodyCenter(bodyId, n) = m_initialBodyCenters[getGlobalBodyId(bodyId) * nDim + n];
394 a_bodyVelocity(bodyId, n) = 0.0;
395 a_bodyAcceleration(bodyId, n) = 0.0;
396 a_bodyForce(bodyId, n) = 0.0;
397 }
398 a_bodyTemperature(bodyId) = 1.0;
399 a_bodyHeatFlux(bodyId) = 0.0;
400 }
401 }
402
403 // Transfer initialValues to *Dt1 fields.
404 if(!m_forcedMotion) {
405 advanceBodies();
406 }
407}
408
415template <MInt nDim>
417 TRACE();
418
419 // delete output file if it already exists
420 MBool body_exists = fileExists("bodies.log");
421 MBool angBody_exists = fileExists("angvel.log");
422
423 if(body_exists) {
424 std::remove("bodies.log");
425 m_log << "replaced body log";
426 }
427
428 if(angBody_exists) {
429 std::remove("angvel.log");
430 m_log << "replaced angular body log";
431 }
432
433 m_log.open("bodies.log", std::ios::app);
434 m_anglog.open("angvel.log", std::ios::app);
435
436 if(!m_logBodyData) {
437 if(!domainId()) {
438 std::stringstream logEntry;
439 std::stringstream logEntryAng;
440
441 logEntry << ">>> enable body log by using: 'logBodyData = true' "
442 << "\n";
443 logEntryAng << ">>> enable body log by using: 'logBodyData = true' "
444 << "\n";
445
446 m_log << logEntry.str();
447 m_log.close();
448
449 m_anglog << logEntryAng.str();
450 m_anglog.close();
451 }
452 return;
453 }
454
455 MString delimiter = " ";
456 m_logVars.insert(m_logVars.end(), {"t", "body", "x", "y", "z", "u", "v", "w", "c_x", "c_y", "c_z"});
457
458 m_logAngVars.insert(m_logAngVars.end(),
459 {"t", "body", "ang_vel_x", "ang_vel_y", "ang_vel_z", "tourque_x", "tourque_y", "tourque_z"});
460
461 IF_CONSTEXPR(nDim == 2) {
462 std::vector<MString> removeList{"z", "w", "c_z"};
463 std::vector<MString> removeListAng{"ang_vel_z", "tourque_z"};
464 for(const MString& r : removeList) {
465 m_logVars.erase(std::remove(m_logVars.begin(), m_logVars.end(), r), m_logVars.end());
466 }
467
468 for(const MString& r : removeListAng) {
469 m_logAngVars.erase(std::remove(m_logAngVars.begin(), m_logAngVars.end(), r), m_logAngVars.end());
470 }
471 }
472
473 for(const MString& var : m_logVars) {
474 m_log << var << delimiter;
475 }
476
477 for(const MString& var : m_logAngVars) {
478 m_anglog << var << delimiter;
479 }
480
481 m_log << "\n";
482 m_anglog << "\n";
483
484 m_log.close();
485 m_anglog.close();
486}
487
488template <MInt nDim>
490 TRACE();
491
492 std::map<MString, MInt> scalingVars;
493 scalingVars["localBodies"] = m_noLocalBodies;
494 scalingVars["connectedBodies"] = noConnectingBodies();
495 scalingVars["neighborDomains"] = noNeighborDomains();
496
497 std::vector<MInt> recvBuffer;
498 recvBuffer.resize(noDomains());
499 for(const auto& [name, value] : scalingVars) {
501 0, mpiComm(), AT_, "send", "recv");
502
503 if(!domainId()) {
504 // average
505 MFloat avgValue = 0;
506 avgValue = std::accumulate(recvBuffer.begin(), recvBuffer.end(), avgValue);
507 avgValue /= noDomains();
508 std::cout << "Average " + name + " per Domain are: " << avgValue << std::endl;
509
510 // maximum
511 const MInt maxValue = *std::max_element(recvBuffer.begin(), recvBuffer.end());
512 std::cout << "Max " + name + " per Domain are: " << maxValue << std::endl;
513
514 // minimum
515 const MInt minValue = *std::min_element(recvBuffer.begin(), recvBuffer.end());
516 std::cout << "Min " + name + " per Domain are: " << minValue << std::endl;
517 }
518 }
519}
520
521
522template <MInt nDim>
524 TRACE();
525
526 if(!(globalTimeStep % m_solutionInterval == 0) || !m_printKineticEnergy) return;
527 std::vector<MFloat> recvBuffer;
528 recvBuffer.resize(noDomains());
529
530 MFloat summedKineticEnergy = 0.0;
531 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
532 summedKineticEnergy += F1B2 * a_bodyDensityRatio(bodyId) * a_volume(bodyId) * POW2(a_bodyVelocityMag(bodyId));
533 }
534
535 MPI_Gather(&summedKineticEnergy, 1, maia::type_traits<MFloat>::mpiType(), recvBuffer.data(), 1,
536 maia::type_traits<MFloat>::mpiType(), 0, mpiComm(), AT_, "send", "recv");
537
538 MFloat totalKineticEnergy = 0.0;
539 if(!domainId()) {
540 totalKineticEnergy = std::accumulate(recvBuffer.begin(), recvBuffer.end(), totalKineticEnergy);
541 std::cout << "Total Kinetic Energy of Bodies is: " << totalKineticEnergy << std::endl;
542 }
543}
544
545
546template <MInt nDim>
548 TRACE();
549
550 std::array<MFloat, nDim> bMin{};
551 std::array<MFloat, nDim> bMax{};
552
553 for(MInt n = 0; n < nDim; n++) {
554 bMin[n] = Context::getSolverProperty<MFloat>("seedBoxMin", m_solverId, AT_, n);
555 bMax[n] = Context::getSolverProperty<MFloat>("seedBoxMax", m_solverId, AT_, n);
556 }
557
558 MInt bodiesPerEdge = Context::getSolverProperty<MInt>("bodiesPerEdge", m_solverId, AT_, &bodiesPerEdge);
559 m_noEmbeddedBodies = pow(bodiesPerEdge, nDim);
560
561 std::array<std::vector<MFloat>, nDim> bodyGrid;
562 for(MInt n = 0; n < nDim; n++) {
563 bodyGrid[n] = maia::math::linSpace(bMin[n], bMax[n], bodiesPerEdge);
564 }
565
566 m_initialBodyCenters.resize(MLong(m_noEmbeddedBodies * nDim), F0);
567 for(MInt i = 0; i < bodiesPerEdge; i++) {
568 MFloat x = bodyGrid[0][i];
569 for(MInt j = 0; j < bodiesPerEdge; j++) {
570 MFloat y = bodyGrid[1][j];
571 for(MInt k = 0; k < bodiesPerEdge; k++) {
572 MFloat z = bodyGrid[2][k];
573 m_initialBodyCenters[i * nDim * pow(bodiesPerEdge, 2) + j * nDim * bodiesPerEdge + k * nDim] = x;
574 m_initialBodyCenters[i * nDim * pow(bodiesPerEdge, 2) + j * nDim * bodiesPerEdge + k * nDim + 1] = y;
575 m_initialBodyCenters[i * nDim * pow(bodiesPerEdge, 2) + j * nDim * bodiesPerEdge + k * nDim + 2] = z;
576 }
577 }
578 }
579}
580
586template <MInt nDim>
588 m_newTimeStep = true;
589}
590
598template <MInt nDim>
600 if(m_newTimeStep) {
601#ifdef RB_DEBUG
602 m_debugFileStream
603 << "------------TIMESTEP: " << globalTimeStep
604 << " -----------------------------------------------------------------------------------------------"
605 << std::endl;
606#endif
607
608 RECORD_TIMER_START(m_timers[Timers::SolutionStep]);
609
610 RECORD_TIMER_START(m_timers[Timers::Predict]);
611 computeBodies();
612 RECORD_TIMER_STOP(m_timers[Timers::Predict]);
613
614 RECORD_TIMER_START(m_timers[Timers::Communication]);
615 exchangeKinematicData();
616 RECORD_TIMER_STOP(m_timers[Timers::Communication]);
617
618 m_newTimeStep = false;
619
620 RECORD_TIMER_STOP(m_timers[Timers::SolutionStep]);
621
622 return false;
623 } else {
624 RECORD_TIMER_START(m_timers[Timers::SolutionStep]);
625
626 RECORD_TIMER_START(m_timers[Timers::Communication]);
627 exchangeFsiData();
628 RECORD_TIMER_STOP(m_timers[Timers::Communication]);
629
630 RECORD_TIMER_START(m_timers[Timers::Correct]);
631 correctBodies();
632 RECORD_TIMER_STOP(m_timers[Timers::Correct]);
633
634 RECORD_TIMER_START(m_timers[Timers::Communication]);
635 exchangeKinematicData();
636 RECORD_TIMER_STOP(m_timers[Timers::Communication]);
637
638 RECORD_TIMER_START(m_timers[Timers::UpdateCommunication]);
639 updateConnections();
640 RECORD_TIMER_STOP(m_timers[Timers::UpdateCommunication]);
641
642 advanceBodies();
643 RECORD_TIMER_STOP(m_timers[Timers::SolutionStep]);
644
645 return true;
646 }
647}
648
656template <MInt nDim>
658 TRACE();
659
660 // dimensionless RB time
661 const MFloat time = globalTimeStep * m_timestep;
662
663 if(m_forcedMotion) {
664 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
665 computeBodyPropertiesForced(1, &m_bodies.bodyCenter(bodyId, 0), bodyId, time);
666 computeBodyPropertiesForced(2, &m_bodies.bodyVelocity(bodyId, 0), bodyId, time);
667 computeBodyPropertiesForced(3, &m_bodies.bodyAcceleration(bodyId, 0), bodyId, time);
668 }
669 } else {
670 predictorStep();
671 }
672}
673
683template <MInt nDim>
685 TRACE();
686
687 MInt noRemoteDomains = m_remoteDomainLocalBodies.size();
688 MInt noHomeDomains = m_homeDomainRemoteBodies.size();
689
690 std::vector<MPI_Request> mpi_send_req(noRemoteDomains, MPI_REQUEST_NULL);
691 std::vector<MPI_Request> mpi_recv_req(noHomeDomains, MPI_REQUEST_NULL);
692
693 MInt bufSizePerBody = nDim * 3 + nRot * 2 + nQuat;
694 // allocate receive buffer per homeDomain
695 std::vector<std::vector<MFloat>> rcvBufferAll(noHomeDomains);
696 MInt idx = 0;
697 for(const auto& [homeDomain, bodies] : m_homeDomainRemoteBodies) {
698 rcvBufferAll[idx].resize(bodies.size() * bufSizePerBody);
699 idx++;
700 }
701
702 // receive predicted body state
703 idx = 0;
704 for(const auto& [homeDomain, bodies] : m_homeDomainRemoteBodies) {
705 MPI_Irecv(rcvBufferAll[idx].data(), rcvBufferAll[idx].size(), maia::type_traits<MFloat>::mpiType(), homeDomain, 2,
706 mpiComm(), &mpi_recv_req[idx], AT_, "recv predict");
707 idx++;
708 }
709
710 idx = 0;
711 MInt paraCount = 0;
712 MInt bodyCount = 0;
713 std::vector<std::vector<MFloat>> sendBufferAll(noRemoteDomains);
714 // pack send buffer and send predicted body states to all remote domains
715 for(const auto& [remoteDomain, bodies] : m_remoteDomainLocalBodies) {
716 // pack
717 auto& sendBuffer = sendBufferAll[idx];
718 sendBuffer.resize(bufSizePerBody * bodies.size());
719 bodyCount = 0;
720 for(const auto& body : bodies) {
721 paraCount = 0;
722 for(MInt n = 0; n < nDim; n++) {
723 sendBuffer[bodyCount + n] = a_bodyCenter(body, n);
724 // apply shift if periodic BCs are active
725 if(m_periodicBC) {
726 sendBuffer[bodyCount + n] += m_periodicShift[remoteDomain][body][n];
727 }
728 sendBuffer[bodyCount + nDim + n] = a_bodyVelocity(body, n);
729 sendBuffer[bodyCount + 2 * nDim + n] = a_bodyAcceleration(body, n);
730 }
731 paraCount += 3 * nDim;
732 for(MInt r = 0; r < nRot; r++) {
733 sendBuffer[bodyCount + paraCount + r] = a_angularVelocity(body, r);
734 sendBuffer[bodyCount + paraCount + nRot + r] = a_angularVelocityBody(body, r);
735 }
736 paraCount += 2 * nRot;
737 for(MInt q = 0; q < nQuat; q++) {
738 sendBuffer[bodyCount + paraCount + q] = a_bodyQuaternionT1(body, q);
739 }
740 bodyCount += bufSizePerBody;
741 }
742 // send
743 MPI_Isend(sendBuffer.data(), sendBuffer.size(), maia::type_traits<MFloat>::mpiType(), remoteDomain, 2, mpiComm(),
744 &mpi_send_req[idx], AT_, "send predict");
745 idx++;
746 }
747
748 // Wait for MPI exchange to complete
749 for(MInt i = 0; i < noRemoteDomains; i++) {
750 MPI_Wait(&mpi_send_req[i], MPI_STATUS_IGNORE, AT_);
751 }
752
753 for(MInt i = 0; i < noHomeDomains; i++) {
754 MPI_Wait(&mpi_recv_req[i], MPI_STATUS_IGNORE, AT_);
755 }
756
757 // unpack buffer -> same as packing
758 idx = 0;
759 for(const auto& [homeDomain, bodies] : m_homeDomainRemoteBodies) {
760 bodyCount = 0;
761 for(const auto& body : bodies) {
762 paraCount = 0;
763 for(MInt n = 0; n < nDim; n++) {
764 a_bodyCenter(body, n) = rcvBufferAll[idx][bodyCount + n];
765 a_bodyVelocity(body, n) = rcvBufferAll[idx][bodyCount + nDim + n];
766 a_bodyAcceleration(body, n) = rcvBufferAll[idx][bodyCount + nDim * 2 + n];
767 }
768 paraCount += 3 * nDim;
769 for(MInt r = 0; r < nRot; r++) {
770 a_angularVelocity(body, r) = rcvBufferAll[idx][bodyCount + paraCount + r];
771 a_angularVelocityBody(body, r) = rcvBufferAll[idx][bodyCount + paraCount + nRot + r];
772 }
773 paraCount += 2 * nRot;
774 for(MInt q = 0; q < nQuat; q++) {
775 a_bodyQuaternionT1(body, q) = rcvBufferAll[idx][bodyCount + paraCount + q];
776 }
777 bodyCount += bufSizePerBody;
778 }
779 idx++;
780 }
781
782 // Exchange kinematic Data for self-mapped Bodies
783 auto aDBCopy = m_associatedDummyBodies;
784 for(const auto& [body, dummyId] : aDBCopy) {
785 // if a remote body has a associated dummy body, but is not intersecting with a halo cell anymore -> delete dummy
786 // body
787 const MInt intersectingCellId =
788 grid().raw().intersectingWithHaloCells(&a_bodyCenter(body, 0), m_infoDiameter / 2.0, 0, true);
789 if(intersectingCellId == -1) {
790 deleteDummyBody(body);
791 continue;
792 }
793 for(MInt n = 0; n < nDim; n++) {
794 // periodic shift has to be updated?
795 m_periodicShift[domainId()][body][n] = calculatePeriodicShift(intersectingCellId, n);
796 a_bodyCenter(dummyId, n) = a_bodyCenter(body, n) + m_periodicShift[domainId()][body][n];
797 a_bodyVelocity(dummyId, n) = a_bodyVelocity(body, n);
798 a_bodyAcceleration(dummyId, n) = a_bodyAcceleration(body, n);
799 }
800 for(MInt r = 0; r < nRot; r++) {
801 a_angularVelocity(dummyId, r) = a_angularVelocity(body, r);
802 a_angularVelocityBody(dummyId, r) = a_angularVelocityBody(body, r);
803 }
804 for(MInt q = 0; q < nQuat; q++) {
805 a_bodyQuaternionT1(dummyId, q) = a_bodyQuaternionT1(body, q);
806 }
807 }
808}
809
810
820template <MInt nDim>
822 TRACE();
823
824 // exchange local partial sum of the remote body force to the bodies home domain and add it
825 std::vector<MPI_Request> mpi_send_req(noHomeDomains(), MPI_REQUEST_NULL);
826 std::vector<MPI_Request> mpi_recv_req(noRemoteDomains(), MPI_REQUEST_NULL);
827
828 MInt noRemoteDomains = m_remoteDomainLocalBodies.size();
829 MInt noHomeDomains = m_homeDomainRemoteBodies.size();
830
831 MInt bufSizePerBody = nDim * 2;
832 // allocate receive buffer per remote domain and create tmp sum buffer for each body
833 std::vector<std::vector<MFloat>> rcvBufferAll(noRemoteDomains);
834 MInt idx = 0;
835 for(const auto& [remoteDomain, bodies] : m_remoteDomainLocalBodies) {
836 rcvBufferAll[idx].resize(bodies.size() * bufSizePerBody);
837 idx++;
838 }
839
840 // receive predicted body state
841 idx = 0;
842 for(const auto& [remoteDomain, bodies] : m_remoteDomainLocalBodies) {
843 MPI_Irecv(rcvBufferAll[idx].data(), rcvBufferAll[idx].size(), maia::type_traits<MFloat>::mpiType(), remoteDomain, 2,
844 mpiComm(), &mpi_recv_req[idx], AT_, "recv predict");
845 idx++;
846 }
847
848 idx = 0;
849 MInt bodyCount = 0;
850 std::vector<std::vector<MFloat>> sendBufferAll(noHomeDomains);
851 // pack send buffer and send predicted body states to home domains
852 for(const auto& [homeDomain, bodies] : m_homeDomainRemoteBodies) {
853 // pack
854 auto& sendBuffer = sendBufferAll[idx];
855 sendBuffer.resize(bufSizePerBody * bodies.size());
856 bodyCount = 0;
857 for(const auto& body : bodies) {
858 for(MInt n = 0; n < nDim; n++) {
859 // when sending the FSI-Data to the homeDomain, we not only need the forces of the remoteBody, but also the
860 // forces of its associated dummy body, in case the remoteBody is self-mapped
861 if(hasAssociatedDummyBody(body)) {
862 a_bodyForce(body, n) += a_bodyForce(m_associatedDummyBodies[body], n);
863 a_bodyTorque(body, n) += a_bodyTorque(m_associatedDummyBodies[body], n);
864 }
865 sendBuffer[bodyCount + n] = a_bodyForce(body)[n];
866 sendBuffer[bodyCount + nDim + n] = a_bodyTorque(body)[n];
867 }
868 bodyCount += bufSizePerBody;
869 }
870 // send
871 MPI_Isend(sendBuffer.data(), sendBuffer.size(), maia::type_traits<MFloat>::mpiType(), homeDomain, 2, mpiComm(),
872 &mpi_send_req[idx], AT_, "send predict");
873 idx++;
874 }
875
876 // Wait for MPI exchange to complete
877 for(MInt i = 0; i < noHomeDomains; i++) {
878 MPI_Wait(&mpi_send_req[i], MPI_STATUS_IGNORE, AT_);
879 }
880
881 for(MInt i = 0; i < noRemoteDomains; i++) {
882 MPI_Wait(&mpi_recv_req[i], MPI_STATUS_IGNORE, AT_);
883 }
884
885 // add up required parts of remotely calculated surface force + torque
886 idx = 0;
887 for(const auto& [remoteDomain, bodies] : m_remoteDomainLocalBodies) {
888 bodyCount = 0;
889 for(const auto& body : bodies) {
890 for(MInt n = 0; n < nDim; n++) {
891 a_bodyForce(body)[n] += rcvBufferAll[idx][bodyCount + n];
892 a_bodyTorque(body)[n] += rcvBufferAll[idx][bodyCount + nDim + n];
893 }
894 bodyCount += bufSizePerBody;
895 }
896 idx++;
897 }
898
899 // Exchange FSI data for self-mapped Bodies
900 for(const auto& [body, dummyId] : m_associatedDummyBodies) {
901 for(MInt n = 0; n < nDim; n++) {
902 a_bodyForce(body, n) += a_bodyForce(dummyId, n);
903 a_bodyTorque(body, n) += a_bodyTorque(dummyId, n);
904 }
905 }
906}
907
908template <MInt nDim>
910 TRACE();
911 findTransferBodies();
912 exchangeTransferBodies();
913 checkDummyBodiesForSwap();
914 updateInfoDiameter();
915 updateBodyDomainConnections(false);
916 exchangeEdgeBodyData();
917// exchangeNeighborConnectionInfo();
918#ifdef RB_DEBUG
919 printBodyDomainConnections();
920#endif
921 totalKineticEnergy();
922}
923
929template <MInt nDim>
931 TRACE();
932
933 if(!m_forcedMotion) {
934 collideBodies();
935 correctorStep();
936 }
937
938 logBodyData();
939}
940
946template <MInt nDim>
948 TRACE();
949 if(!m_logBodyData || !(globalTimeStep % m_intervalBodyLog == 0)) return;
950 // mpi_gatherv body data to write file with domain 0
951 // bodyId + pos + vel + acc + ang_vel + torque
952 const MInt bufSizePerBody = 1 + nDim * 5;
953 std::vector<MFloat> sendBuffer(MLong(bufSizePerBody * m_noLocalBodies));
954 for(MInt i = 0; i < m_noLocalBodies; i++) {
955 MInt bodyId = i;
956 sendBuffer[MLong(i * bufSizePerBody)] = (MFloat)bodyId;
957 for(MInt n = 0; n < nDim; n++) {
958 sendBuffer[i * bufSizePerBody + 1 + n] = a_bodyCenter(bodyId, n);
959 sendBuffer[i * bufSizePerBody + 1 + 1 * nDim + n] = a_bodyVelocity(bodyId, n);
960 sendBuffer[i * bufSizePerBody + 1 + 2 * nDim + n] = a_bodyAcceleration(bodyId, n);
961 sendBuffer[i * bufSizePerBody + 1 + 3 * nDim + n] = a_angularVelocity(bodyId, n);
962 sendBuffer[i * bufSizePerBody + 1 + 4 * nDim + n] = a_bodyTorque(bodyId, n);
963 }
964 }
965
966 std::vector<MInt> noToRecv(noDomains());
967 const MUint noToSend = sendBuffer.size();
968 exchangeBufferLengthsAllToRoot(noToRecv, noToSend);
969
970 MInt count = 0;
971 std::vector<MInt> displacements(noDomains());
972 for(MInt n = 0; n < noDomains(); n++) {
973 // noToRecv[n] *= bufSizePerBody;
974 displacements[n] = count;
975 count += noToRecv[n];
976 }
977
978 // create receive buffer
979 std::vector<MFloat> rcvBuffer(MLong(m_noEmbeddedBodies * bufSizePerBody));
980 MPI_Gatherv(sendBuffer.data(), sendBuffer.size(), maia::type_traits<MFloat>::mpiType(), rcvBuffer.data(),
981 noToRecv.data(), displacements.data(), maia::type_traits<MFloat>::mpiType(), 0, mpiComm(), AT_, "send",
982 "recv");
983
984 if(domainId() != 0) return;
985
986 MString delimiter = " ";
987 std::stringstream logEntry;
988 std::stringstream logEntryAng;
989
990 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
991 MInt bodyId = (MInt)rcvBuffer[MLong(b * bufSizePerBody)];
992
993 logEntry << globalTimeStep << delimiter;
994 logEntry << bodyId << delimiter;
995
996 logEntryAng << globalTimeStep << delimiter;
997 logEntryAng << bodyId << delimiter;
998
999 std::array<MFloat, nDim> center{};
1000 std::array<MFloat, nDim> velocity{};
1001 std::array<MFloat, nDim> acceleration{};
1002 std::array<MFloat, nDim> ang_vel{};
1003 std::array<MFloat, nDim> torque{};
1004
1005 for(MInt n = 0; n < nDim; n++) {
1006 center[n] = rcvBuffer[b * bufSizePerBody + 1 + n];
1007 velocity[n] = rcvBuffer[b * bufSizePerBody + 1 + nDim + n];
1008 acceleration[n] = rcvBuffer[b * bufSizePerBody + 1 + 2 * nDim + n];
1009 ang_vel[n] = rcvBuffer[b * bufSizePerBody + 1 + 3 * nDim + n];
1010 torque[n] = rcvBuffer[b * bufSizePerBody + 1 + 4 * nDim + n];
1011 }
1012
1013 // bodies log
1014 for(MInt n = 0; n < nDim; n++) {
1015 logEntry << std::scientific << center[n] << delimiter;
1016 }
1017
1018 for(MInt n = 0; n < nDim; n++) {
1019 logEntry << std::scientific << velocity[n] << delimiter;
1020 }
1021
1022 for(MInt n = 0; n < nDim; n++) {
1023 logEntry << std::scientific << acceleration[n] << delimiter;
1024 }
1025
1026 // angvel log
1027 for(MInt n = 0; n < nDim; n++) {
1028 logEntryAng << std::scientific << ang_vel[n] << delimiter;
1029 }
1030
1031 for(MInt n = 0; n < nDim; n++) {
1032 logEntryAng << std::scientific << torque[n] << delimiter;
1033 }
1034
1035 logEntry << "\n";
1036 logEntryAng << "\n";
1037 }
1038
1039 m_log.open("bodies.log", std::ios::app);
1040 m_log << logEntry.str();
1041 m_log.close();
1042
1043 m_anglog.open("angvel.log", std::ios::app);
1044 m_anglog << logEntryAng.str();
1045 m_anglog.close();
1046}
1047
1053template <MInt nDim>
1055 TRACE();
1056
1057 m_bodies.advanceBodies();
1058}
1059
1065template <MInt nDim>
1067 TRACE();
1068
1069 const MFloat dt = m_timestep;
1070
1071 if(m_translation) {
1072 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
1073 // Translational values
1074 for(MInt n = 0; n < nDim; n++) {
1075 // Determine acceleration
1076 a_bodyAcceleration(bodyId, n) = a_bodyAccelerationOld(bodyId, n);
1077
1078 // Determine velocities
1079 a_bodyVelocity(bodyId, n) = a_bodyVelocityOld(bodyId, n)
1080 + 0.5 * dt * (a_bodyAcceleration(bodyId, n) + a_bodyAccelerationOld(bodyId, n));
1081
1082 // Determine position
1083 a_bodyCenter(bodyId, n) =
1084 a_bodyCenterOld(bodyId, n) + dt * a_bodyVelocityOld(bodyId, n)
1085 + 0.25 * POW2(dt) * (a_bodyAcceleration(bodyId, n) + a_bodyAccelerationOld(bodyId, n));
1086 }
1087
1088 if(m_rotation) {
1089 predictRotation(bodyId);
1090 }
1091
1092 // Scalar values
1093 // Determine temperature
1094 a_bodyTemperature(bodyId) =
1095 a_bodyTemperatureOld(bodyId) + dt * a_bodyHeatFlux(bodyId) / (m_bodyHeatCapacity * a_bodyMass(bodyId));
1096 }
1097 } else {
1098 if(m_rotation) {
1099 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
1100 predictRotation(bodyId);
1101 }
1102 }
1103 }
1104}
1105
1106template <MInt nDim>
1107void RigidBodies<nDim>::exchangeBufferLengthsRemoteToHome(std::vector<MInt>& noToRecv, std::vector<MInt>& noToSend) {
1108 TRACE();
1109
1110 std::vector<MPI_Request> mpi_send_req(noHomeDomains(), MPI_REQUEST_NULL);
1111 std::vector<MPI_Request> mpi_recv_req(noRemoteDomains(), MPI_REQUEST_NULL);
1112
1113 // recv from every neighbor
1114 MInt count = 0;
1115 for(const auto& [remoteDomain, bodies] : m_remoteDomainLocalBodies) {
1116 MPI_Irecv(&noToRecv[count], 1, MPI_INT, remoteDomain, 2, mpiComm(), &mpi_recv_req[count], AT_, "recv from remote");
1117 count++;
1118 }
1119
1120 // send
1121 count = 0;
1122 for(const auto& [homeDomain, bodies] : m_homeDomainRemoteBodies) {
1123 MPI_Isend(&noToSend[count], 1, MPI_INT, homeDomain, 2, mpiComm(), &mpi_send_req[count], AT_, "send to home");
1124 count++;
1125 }
1126
1127 // wait for communication to finish
1128 for(MInt n = 0; n < noHomeDomains(); n++) {
1129 MPI_Wait(&mpi_send_req[n], MPI_STATUS_IGNORE, AT_);
1130 }
1131
1132 for(MInt n = 0; n < noRemoteDomains(); n++) {
1133 MPI_Wait(&mpi_recv_req[n], MPI_STATUS_IGNORE, AT_);
1134 }
1135}
1136
1144template <MInt nDim>
1146 std::vector<std::vector<MInt>>& bodyList) {
1147 TRACE();
1148
1149 // exchange no of edge bodies to neighboring domains
1150 std::vector<MPI_Request> mpi_send_req(noNeighborDomains(), MPI_REQUEST_NULL);
1151 std::vector<MPI_Request> mpi_recv_req(noNeighborDomains(), MPI_REQUEST_NULL);
1152
1153 // recv from every neighbor
1154 for(MInt n = 0; n < noNeighborDomains(); n++) {
1155 MPI_Irecv(&noToRecv[n], 1, MPI_INT, neighborDomain(n), 2, mpiComm(), &mpi_recv_req[n], AT_, "recv predict");
1156 }
1157
1158 // create send buffer
1159 std::vector<MUint> sendBuffer(noNeighborDomains(), 0);
1160 for(MInt d = 0; d < noNeighborDomains(); d++) {
1161 sendBuffer[d] = bodyList[d].size();
1162 }
1163
1164 // send to every neighbor
1165 for(MInt i = 0; i < noNeighborDomains(); i++) {
1166 MPI_Isend(&sendBuffer[i], 1, MPI_INT, neighborDomain(i), 2, mpiComm(), &mpi_send_req[i], AT_, "send predict");
1167 }
1168
1169 // Wait for MPI exchange to complete
1170 for(MInt i = 0; i < noNeighborDomains(); i++) {
1171 MPI_Wait(&mpi_send_req[i], MPI_STATUS_IGNORE, AT_);
1172 MPI_Wait(&mpi_recv_req[i], MPI_STATUS_IGNORE, AT_);
1173 }
1174}
1175
1187template <MInt nDim>
1189 std::map<MInt, std::vector<MInt>>& bodyList) {
1190 TRACE();
1191
1192 // exchange no of edge bodies to neighboring domains
1193 std::vector<MPI_Request> mpi_send_req(noNeighborDomains(), MPI_REQUEST_NULL);
1194 std::vector<MPI_Request> mpi_recv_req(noNeighborDomains(), MPI_REQUEST_NULL);
1195
1196 // recv from every neighbor
1197 for(MInt n = 0; n < noNeighborDomains(); n++) {
1198 MPI_Irecv(&noToRecv[n], 1, MPI_INT, neighborDomain(n), 2, mpiComm(), &mpi_recv_req[n], AT_, "recv predict");
1199 }
1200
1201 // create send buffer
1202 std::vector<MUint> sendBuffer(noNeighborDomains(), 0);
1203 for(MInt d = 0; d < noNeighborDomains(); d++) {
1204 MInt globDomain = neighborDomain(d);
1205 sendBuffer[d] = bodyList[globDomain].size();
1206 }
1207
1208 // send to every neighbor
1209 for(MInt i = 0; i < noNeighborDomains(); i++) {
1210 MPI_Isend(&sendBuffer[i], 1, MPI_INT, neighborDomain(i), 2, mpiComm(), &mpi_send_req[i], AT_, "send predict");
1211 }
1212
1213 // Wait for MPI exchange to complete
1214 for(MInt i = 0; i < noNeighborDomains(); i++) {
1215 MPI_Wait(&mpi_send_req[i], MPI_STATUS_IGNORE, AT_);
1216 MPI_Wait(&mpi_recv_req[i], MPI_STATUS_IGNORE, AT_);
1217 }
1218}
1219
1227template <MInt nDim>
1228void RigidBodies<nDim>::exchangeBufferLengthsAllToRoot(std::vector<MInt>& noToRecv, const MInt noToSend) {
1229 TRACE();
1230
1231 MPI_Request mpi_send_req = MPI_REQUEST_NULL;
1232 std::vector<MPI_Request> mpi_recv_req(noDomains(), MPI_REQUEST_NULL);
1233
1234 // recv from every domain and wait
1235 if(!domainId()) {
1236 for(MInt n = 0; n < noDomains(); n++) {
1237 MPI_Irecv(&noToRecv[n], 1, MPI_INT, n, 2, mpiComm(), &mpi_recv_req[n], AT_, "recv buffer length");
1238 }
1239 }
1240
1241 // send to root
1242 MPI_Isend(&noToSend, 1, MPI_INT, 0, 2, mpiComm(), &mpi_send_req, AT_, "send buffer length");
1243
1244 // Wait for MPI exchange to complete
1245 MPI_Waitall(noDomains(), mpi_recv_req.data(), MPI_STATUS_IGNORE, AT_);
1246
1247 // Wait for MPI exchange to complete
1248 MPI_Wait(&mpi_send_req, MPI_STATUS_IGNORE, AT_);
1249}
1250
1258template <MInt nDim>
1259void RigidBodies<nDim>::exchangeBufferLengthsAllToAll(std::vector<MInt>& noToRecv, const MInt noToSend) {
1260 TRACE();
1261 // exchange no of edge bodies to neighboring domains
1262 std::vector<MPI_Request> mpi_send_req(noDomains(), MPI_REQUEST_NULL);
1263 std::vector<MPI_Request> mpi_recv_req(noDomains(), MPI_REQUEST_NULL);
1264
1265 // recv from every domain and wait
1266 for(MInt n = 0; n < noDomains(); n++) {
1267 MPI_Irecv(&noToRecv[n], 1, MPI_INT, n, 2, mpiComm(), &mpi_recv_req[n], AT_, "recv buffer length");
1268 }
1269
1270 // send to root
1271 for(MInt n = 0; n < noDomains(); n++) {
1272 MPI_Isend(&noToSend, 1, MPI_INT, n, 2, mpiComm(), &mpi_send_req[n], AT_, "send buffer length");
1273 }
1274 // Wait for MPI exchange to complete
1275 MPI_Waitall(noDomains(), mpi_send_req.data(), MPI_STATUSES_IGNORE, AT_);
1276 MPI_Waitall(noDomains(), mpi_recv_req.data(), MPI_STATUSES_IGNORE, AT_);
1277}
1278
1282template <MInt nDim>
1283void RigidBodies<nDim>::exchangeBufferLengthsNeighbors(std::vector<MInt>& noToRecv, const MInt noToSend) {
1284 TRACE();
1285 // exchange no of edge bodies to neighboring domains
1286 std::vector<MPI_Request> mpi_send_req(noNeighborDomains(), MPI_REQUEST_NULL);
1287 std::vector<MPI_Request> mpi_recv_req(noNeighborDomains(), MPI_REQUEST_NULL);
1288
1289 // recv from every domain and wait
1290 for(MInt n = 0; n < noNeighborDomains(); n++) {
1291 MPI_Irecv(&noToRecv[n], 1, MPI_INT, neighborDomain(n), 2, mpiComm(), &mpi_recv_req[n], AT_, "recv buffer length");
1292 }
1293
1294 // send to root
1295 for(MInt n = 0; n < noNeighborDomains(); n++) {
1296 MPI_Isend(&noToSend, 1, MPI_INT, neighborDomain(n), 2, mpiComm(), &mpi_send_req[n], AT_, "send buffer length");
1297 }
1298 // Wait for MPI exchange to complete
1299 MPI_Waitall(noNeighborDomains(), mpi_send_req.data(), MPI_STATUSES_IGNORE, AT_);
1300 MPI_Waitall(noNeighborDomains(), mpi_recv_req.data(), MPI_STATUSES_IGNORE, AT_);
1301}
1302
1303
1310template <MInt nDim>
1312 TRACE();
1313
1314 std::vector<MInt> noLocalBodiesPerPartition(noDomains());
1315 exchangeBufferLengthsAllToAll(noLocalBodiesPerPartition, m_noLocalBodies);
1316
1317 MLong offset{};
1318 for(MInt i = 0; i < domainId(); i++) {
1319 offset += noLocalBodiesPerPartition[i];
1320 }
1321
1322 return offset;
1323}
1324
1325
1333template <MInt nDim>
1335 TRACE();
1336
1337 m_bResFile.reset(noEmbeddedBodies());
1338 m_bResFile.append(noEmbeddedBodies());
1339
1340 // variables
1341 std::vector<MFloat*> transVarsRcv{&m_bResFile.bodyCenter(0, 0), &m_bResFile.bodyVelocity(0, 0),
1342 &m_bResFile.bodyAcceleration(0, 0)};
1343
1344 std::vector<MFloat*> rotVarsRcv{&m_bResFile.angularVelocityBodyT1B2(0, 0), &m_bResFile.angularAccelerationBody(0, 0)};
1345
1346 std::vector<MFloat*> quatVarsRcv{&m_bResFile.bodyQuaternionT1B2(0, 0), &m_bResFile.bodyQuaternionT1(0, 0)};
1347
1348 // bodyId + temperature + trans + rot + quat
1349 const MInt noTransVars = 3;
1350 const MInt noRotVars = 2;
1351 const MInt noQuatVars = 2;
1352 const MInt bufSizePerBody = 1 + 1 + noTransVars * nDim + noRotVars * nRot + noQuatVars * nQuat;
1353 MInt varSizeCount = 0;
1354 MInt bodySizeCount = 0;
1355 // create send buffer
1356 std::vector<MFloat> sendBuffer(MLong(m_noLocalBodies * bufSizePerBody));
1357 const MUint noToSend = sendBuffer.size();
1358
1359 // fill send buffer, if bodies are in collector
1360 if(m_bodies.size() > 0) {
1361 // send variables
1362 std::vector<MFloat*> transVars{&a_bodyCenter(0, 0), &a_bodyVelocity(0, 0), &a_bodyAcceleration(0, 0)};
1363 // MInt noTransVars = transVars.size();
1364
1365 std::vector<MFloat*> rotVars{&a_angularVelocityBodyT1B2(0, 0), &a_angularAccelerationBody(0, 0)};
1366 // MInt noRotVars = rotVars.size();
1367
1368 std::vector<MFloat*> quatVars{&a_bodyQuaternionT1B2(0, 0), &a_bodyQuaternionT1(0, 0)};
1369 // MInt noQuatVars = quatVars.size();
1370
1371 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
1372 sendBuffer[bodySizeCount] = (MFloat)getGlobalBodyId(bodyId);
1373 varSizeCount += 1;
1374
1375 // temperature
1376 sendBuffer[bodySizeCount + varSizeCount] = a_bodyTemperature(bodyId);
1377 varSizeCount += 1;
1378
1379 // trans vars
1380 for(MInt v = 0; v < noTransVars; v++) {
1381 for(MInt n = 0; n < nDim; n++) {
1382 sendBuffer[bodySizeCount + varSizeCount + n] = transVars[v][nDim * bodyId + n];
1383 }
1384 varSizeCount += nDim;
1385 }
1386 // rot vars
1387 for(MInt v = 0; v < noRotVars; v++) {
1388 for(MInt r = 0; r < nRot; r++) {
1389 sendBuffer[bodySizeCount + varSizeCount + r] = rotVars[v][nRot * bodyId + r];
1390 }
1391 varSizeCount += nRot;
1392 }
1393
1394 // quat vars
1395 for(MInt v = 0; v < noQuatVars; v++) {
1396 for(MInt q = 0; q < nQuat; q++) {
1397 sendBuffer[bodySizeCount + varSizeCount + q] = quatVars[v][nQuat * bodyId + q];
1398 }
1399 varSizeCount += nQuat;
1400 }
1401 bodySizeCount += bufSizePerBody;
1402 varSizeCount = 0;
1403 }
1404 }
1405
1406 // allocate receive buffer
1407 std::vector<MInt> noToRecv(noDomains());
1408 exchangeBufferLengthsAllToAll(noToRecv, noToSend);
1409 std::vector<MFloat> rcvBuffer(noEmbeddedBodies() * bufSizePerBody);
1410
1411 // displacements
1412 MInt count = 0;
1413 std::vector<MInt> displacements(noDomains());
1414 for(MInt n = 0; n < noDomains(); n++) {
1415 displacements[n] = count;
1416 count += noToRecv[n];
1417 }
1418
1419 // exchange data
1420 MPI_Allgatherv(sendBuffer.data(), sendBuffer.size(), maia::type_traits<MFloat>::mpiType(), rcvBuffer.data(),
1421 noToRecv.data(), displacements.data(), maia::type_traits<MFloat>::mpiType(), mpiComm(), AT_, "send",
1422 "recv");
1423
1424 // unpack receive buffer
1425 varSizeCount = 0;
1426 bodySizeCount = 0;
1427 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
1428 const MInt bodyId = (MInt)rcvBuffer[bodySizeCount];
1429 varSizeCount += 1;
1430
1431 // temperature
1432 m_bResFile.bodyTemperature(bodyId) = rcvBuffer[bodySizeCount + varSizeCount];
1433 varSizeCount += 1;
1434
1435 // trans vars
1436 for(MInt v = 0; v < noTransVars; v++) {
1437 for(MInt n = 0; n < nDim; n++) {
1438 transVarsRcv[v][nDim * bodyId + n] = rcvBuffer[bodySizeCount + varSizeCount + n];
1439 }
1440 varSizeCount += nDim;
1441 }
1442 // rot vars
1443 for(MInt v = 0; v < noRotVars; v++) {
1444 for(MInt r = 0; r < nRot; r++) {
1445 rotVarsRcv[v][nRot * bodyId + r] = rcvBuffer[bodySizeCount + varSizeCount + r];
1446 }
1447 varSizeCount += nRot;
1448 }
1449
1450 // quat vars
1451 for(MInt v = 0; v < noQuatVars; v++) {
1452 for(MInt q = 0; q < nQuat; q++) {
1453 quatVarsRcv[v][nQuat * bodyId + q] = rcvBuffer[bodySizeCount + varSizeCount + q];
1454 }
1455 varSizeCount += nQuat;
1456 }
1457 bodySizeCount += bufSizePerBody;
1458 varSizeCount = 0;
1459 }
1460}
1461
1468template <MInt nDim>
1470 TRACE();
1471
1472 // loop over all bodies initial bodies
1473 for(MInt globalBodyId = 0; globalBodyId < noEmbeddedBodies(); globalBodyId++) {
1474 std::array<MFloat, nDim> tmpCenter{};
1475 for(MInt n = 0; n < nDim; n++) {
1476 if(m_restart) {
1477 tmpCenter[n] = m_bResFile.bodyCenter(globalBodyId, n);
1478 } else {
1479 tmpCenter[n] = m_initialBodyCenters[globalBodyId * nDim + n];
1480 }
1481 }
1482 MBool insideLocalBbox = grid().raw().pointInLocalBoundingBox(tmpCenter.data());
1483 if(insideLocalBbox) {
1484 MInt localPCellId = grid().raw().findContainingPartitionCell(tmpCenter.data(), -1, nullptr);
1485 if(localPCellId != -1) {
1486 m_globalBodyIds.emplace_back(globalBodyId);
1487 m_noLocalBodies++;
1488 }
1489 }
1490 }
1491}
1492
1493template <MInt nDim>
1495 TRACE();
1496 // Counting periodic directions
1497 MInt periodic = 0;
1498 for(MInt n = 0; n < nDim; n++) {
1499 m_globDomainLength[n] = globBBox(nDim + n) - globBBox(n);
1500 periodic += grid().raw().periodicCartesianDir(n);
1501 }
1502
1503 if(periodic) {
1504 m_periodicBC = true;
1505
1506 constexpr MFloat eps = 1e-9;
1507 MBool domainIsCube = true;
1508 for(MInt n = 0; n < nDim; n++) {
1509 domainIsCube = domainIsCube && (m_globDomainLength[0] - m_globDomainLength[n]) < eps;
1510 }
1511
1512 if(!domainIsCube) {
1513 std::cerr << "\033[0;31m Warning:\033[0m Domain is not a cube - periodic BCs only work on cube domains"
1514 << std::endl;
1515 }
1516 }
1517
1518 updateMaxLevel(maxLevel());
1519}
1520
1521template <MInt nDim>
1523 TRACE();
1524 std::vector<MInt> l_Bodies;
1525 MFloat maxBodyExtension = F0;
1526
1527 if(initCall) {
1528 for(MInt i = 0; i < m_noLocalBodies; i++) {
1529 l_Bodies.push_back(i);
1530 }
1531 } else {
1532 for(MInt bodyId = 0; bodyId < noCollectorBodies(); bodyId++) {
1533 l_Bodies.push_back(bodyId);
1534 }
1535 }
1536
1537 if(m_initBodyRadii.empty()) {
1538 for(const MInt& bodyId : l_Bodies) {
1539 maxBodyExtension = std::max(maxBodyExtension, 2 * a_bodyRadius(bodyId));
1540 }
1541 } else {
1542 for(const MInt& bodyId : l_Bodies) {
1543 for(MInt n = 0; n < nDim; n++) {
1544 maxBodyExtension = std::max(maxBodyExtension, 2 * a_bodyRadii(bodyId, n));
1545 }
1546 }
1547 }
1548 // Body extension + buffer
1549 constexpr const MInt noCellsClearance = 4.0;
1550 m_infoDiameter = maxBodyExtension + noCellsClearance * c_cellLengthAtMaxLevel();
1551}
1552
1561template <MInt nDim>
1563 TRACE();
1564 m_transferBodies.clear();
1565 m_transferBodies.resize(noNeighborDomains());
1566
1567 for(MInt i = 0; i < noNeighborDomains(); i++) {
1568 /* 1) if local bodies center is contained in a neighbor domains halo cell
1569 ** move local body -> transfer body
1570 */
1571 for(const MInt& bodyId : m_remoteDomainLocalBodies[neighborDomain(i)]) {
1572 MBool outside = -1 != grid().raw().findContainingHaloCell(&a_bodyCenter(bodyId, 0), -1, i, true, nullptr);
1573 if(outside) {
1574 // Already get new index of body to be transfered in collector in transferBodies
1575 m_transferBodies[i].push_back(bodyId);
1576#ifdef RB_DEBUG
1577 m_debugFileStream << "Found transfer body with globalId " << getGlobalBodyId(bodyId)
1578 << " will be sent to domain " << i << std::endl;
1579#endif
1580 }
1581 }
1582 }
1583}
1584
1596// TODO, just loop over old remote Domains of body for sending
1597template <MInt nDim>
1599 TRACE();
1600 // transfer to new home domain
1601 // exchange no of transfer bodies to neighboring domains
1602 std::vector<MInt> noToRecv(noNeighborDomains());
1603 MInt totalBufferLength = 0;
1604 for(MInt i = 0; i < noNeighborDomains(); i++) {
1605 totalBufferLength += m_transferBodies[i].size();
1606 }
1607
1608 exchangeBufferLengthsNeighbors(noToRecv, totalBufferLength);
1609
1610 // send new home domain Id to every other home domain
1611 std::vector<MPI_Request> mpi_send_req(noNeighborDomains(), MPI_REQUEST_NULL);
1612 std::vector<MPI_Request> mpi_recv_req(noNeighborDomains(), MPI_REQUEST_NULL);
1613
1614 // create receive buffer
1615 std::vector<std::vector<MFloat>> rcvBufferAll(noNeighborDomains());
1616 MInt bufSizePerBody = 2;
1617
1618 for(MInt n = 0; n < noNeighborDomains(); n++) {
1619 rcvBufferAll[n].resize(MLong(noToRecv[n] * bufSizePerBody));
1620 }
1621
1622 // non-blocking receive
1623 for(MInt i = 0; i < noNeighborDomains(); i++) {
1624 if(!noToRecv[i]) {
1625 continue;
1626 }
1627
1628 MPI_Irecv(rcvBufferAll[i].data(), rcvBufferAll[i].size(), maia::type_traits<MFloat>::mpiType(), neighborDomain(i),
1629 2, mpiComm(), &mpi_recv_req[i], AT_, "recv predict");
1630 }
1631
1632 // create sendBuffer that is send to every domain
1633 MInt idx = 0;
1634 std::vector<MFloat> sendBufferAll(MLong(totalBufferLength * bufSizePerBody));
1635 std::list<std::pair<MInt, MInt>> localBodyRemoveList;
1636 for(MUint i = 0; i < m_transferBodies.size(); i++) {
1637 MUint domain = i;
1638 MUint newHomeDomain = neighborDomain(domain);
1639 for(const auto& body : m_transferBodies[i]) {
1640 sendBufferAll[MLong(idx * bufSizePerBody)] = (MFloat)getGlobalBodyId(body);
1641 sendBufferAll[idx * bufSizePerBody + 1] = (MFloat)newHomeDomain; // <- send new globalDomainId
1642 idx++;
1643
1644 auto it = std::find_if(localBodyRemoveList.cbegin(), localBodyRemoveList.cend(),
1645 [&body](const std::pair<MInt, MInt>& localB) { return localB.second == body; });
1646 if(it == localBodyRemoveList.cend()) {
1647 localBodyRemoveList.push_front(std::make_pair(newHomeDomain, body));
1648 }
1649 }
1650 }
1651
1652 // non-blocking send
1653 for(MInt i = 0; i < noNeighborDomains(); i++) {
1654 if(sendBufferAll.empty()) {
1655 continue;
1656 }
1657
1658 MPI_Isend(sendBufferAll.data(), sendBufferAll.size(), maia::type_traits<MFloat>::mpiType(), neighborDomain(i), 2,
1659 mpiComm(), &mpi_send_req[i], AT_, "send predict");
1660 }
1661
1662 // wait for communication to finish
1663 for(MInt i = 0; i < noNeighborDomains(); i++) {
1664 MPI_Wait(&mpi_send_req[i], MPI_STATUS_IGNORE, AT_);
1665 }
1666
1667 for(MInt i = 0; i < noNeighborDomains(); i++) {
1668 MPI_Wait(&mpi_recv_req[i], MPI_STATUS_IGNORE, AT_);
1669 }
1670
1671 // transferBodies change from local to remote status -> swap position in collector
1672 // only executed on sending domain
1673 // update mappings and collector accordingly
1674
1675 // Due to swapping, localIds in localBodyRemoveList might lose validity
1676 // This mapping starts as unity and is filled if a localBody becomes a swap target
1677 std::map<MInt, MInt> tmpMapping;
1678 for(const auto& [newDomainId, body] : localBodyRemoveList) {
1679 tmpMapping[body] = body;
1680 }
1681 for(const auto& [newDomainId, body] : localBodyRemoveList) {
1682 const MInt tmpCollectorId = tmpMapping[body];
1683 const MInt remoteBodyId = localToRemoteBody(tmpCollectorId, body, newDomainId);
1684
1685 // Fill mapping if one of the remaining localBodies was swapped
1686 for(auto& [newDomainId_, body_] : localBodyRemoveList) {
1687 if(body_ == remoteBodyId) {
1688 tmpMapping[body_] = tmpCollectorId;
1689 }
1690 }
1691 }
1692
1693 // unpack buffer
1694 // 1) Find all bodies, that are transfered to the current domain (remoteBodiesToLocal)
1695 // 2) Find all bodies, that changed there homeDomain in the same timestep, and update mapping accordingly, if relevant
1696 std::vector<std::pair<MInt, MInt>> remoteBodiesToLocal;
1697 std::vector<std::array<MInt, 2>> remoteBodiesNeighDomain;
1698 for(MInt n = 0; n < noNeighborDomains(); n++) {
1699 for(MInt b = 0; b < noToRecv[n]; b++) {
1700 MInt globalBodyId = MInt(rcvBufferAll[n][MLong(b * bufSizePerBody)]);
1701 MInt newHomeDomain = MInt(rcvBufferAll[n][MLong(b * bufSizePerBody + 1)]);
1702 const MInt localId = getLocalBodyId(globalBodyId);
1703
1704#ifdef RB_DEBUG
1705 m_debugFileStream << "received: " << globalBodyId << " with localId " << localId << " and new homeDomain "
1706 << newHomeDomain << "from " << neighborDomain(n) << std::endl;
1707#endif
1708
1709 if(newHomeDomain == domainId()) {
1710 if(localId == -1) {
1711 mTerm(1, AT_,
1712 "ERROR: Body " + std::to_string(globalBodyId) + " has not been on domain " + std::to_string(domainId())
1713 + " before !");
1714 }
1715 MInt oldHomeDomainId = neighborDomain(n);
1716 remoteBodiesToLocal.emplace_back(oldHomeDomainId, globalBodyId);
1717 } else if(localId != -1) {
1718 remoteBodiesNeighDomain.push_back({newHomeDomain, globalBodyId});
1719 }
1720 }
1721 }
1722
1723 // 3) make received bodies local
1724 // If body was previously remote on domain, it gets now local -> change position of body in collector of
1725 // receiving domain (append to local bodies)
1726 for(MUint i = 0; i < remoteBodiesToLocal.size(); i++) {
1727 if(m_noRemoteBodies <= 0) {
1728 mTerm(1, AT_, "Domain: " + std::to_string(domainId()) + " has no remote bodies that can change to local status!");
1729 }
1730 MInt oldHomeDomainId = remoteBodiesToLocal[i].first;
1731 MInt globalId = remoteBodiesToLocal[i].second;
1732 MInt localId = getLocalBodyId(globalId);
1733
1734 const MInt newIdx = m_noLocalBodies;
1735
1736#ifdef RB_DEBUG
1737 m_debugFileStream << "B localId: " << localId << " globalId " << globalId << " newIdx " << newIdx
1738 << " globalIdNewIdx: " << getGlobalBodyId(newIdx) << " oldHomeDomain " << oldHomeDomainId
1739 << std::endl;
1740#endif
1741
1742 if(noConnectingBodies() > 1) {
1743 m_bodies.swap(localId, newIdx);
1744 iter_swap(m_globalBodyIds.begin() + localId, m_globalBodyIds.begin() + newIdx);
1745 }
1746 m_noLocalBodies++;
1747 m_noRemoteBodies--;
1748
1749 // we just append to local bodies and therefore do not need to update this mapping
1750 m_remoteDomainLocalBodies[oldHomeDomainId].push_back(newIdx);
1751
1752 // update localIds in mapping
1753 std::map<MInt, std::vector<MInt>> oldMapping(m_homeDomainRemoteBodies);
1754 for(auto& [domain, bodies] : oldMapping) {
1755 // first delete the new local Body from Remote Body mapping -> body is now on current domain
1756 for(const MInt& body : bodies) {
1757 if(body == localId) {
1758#ifdef RB_DEBUG
1759 m_debugFileStream << "delete body " << body << " domain " << domain << std::endl;
1760#endif
1761 std::vector<MInt>* c = &m_homeDomainRemoteBodies[domain];
1762 c->erase(std::remove(c->begin(), c->end(), localId), c->end());
1763 }
1764 }
1765 // when making a local body remote, all the ids of the remote bodies, that have a lower id than the new local body
1766 // have to be modified. This is done in a second loop to prevent accidental deletion of a body
1767 // if you want to remove local id 1, local id 0 is raised to local id 1
1768 for(MInt& body : m_homeDomainRemoteBodies[domain]) {
1769 if(body < localId) {
1770 body++;
1771 }
1772 }
1773 }
1774 }
1775
1776#ifdef RB_DEBUG
1777 printBodyDomainConnections();
1778#endif
1779
1780 // 4) now after all localBodies and the corresponding remoteDomains are updated
1781 // we potentielly need to update the homeDomain of our remote Bodies
1782 // search in mapping to find body and update new HomeDomain
1783 MBool found = false;
1784 for(const auto& arr : remoteBodiesNeighDomain) {
1785 const MInt newHomeDomain = arr[0];
1786 const MInt globalId = arr[1];
1787
1788 const MInt NewLocalId = getLocalBodyId(globalId);
1789
1790 for(const auto& [domain, bodies] : m_homeDomainRemoteBodies) {
1791 if(domain == domainId()) continue;
1792 for(const auto& bodyId : bodies) {
1793 if(getGlobalBodyId(bodyId) == globalId) {
1794 found = true;
1795 // a remote Body was transfered to a new homedomain, update:
1796 if(domain != newHomeDomain) {
1797 std::vector<MInt>* c = &m_homeDomainRemoteBodies[domain];
1798 c->erase(std::remove(c->begin(), c->end(), NewLocalId), c->end());
1799
1800 m_homeDomainRemoteBodies[newHomeDomain].push_back(NewLocalId);
1801 break;
1802 }
1803#ifdef RB_DEBUG
1804 m_debugFileStream
1805 << "something went wrong, domain should be diff from newHomeDomain in remoteBodiesNeighDomain! "
1806 << "Domain is " << domain << " newHomeDomain is " << newHomeDomain << std::endl;
1807#endif
1808 }
1809 }
1810 if(found) break;
1811 }
1812 }
1813#ifdef RB_DEBUG
1814 m_debugFileStream << "end of exchange: " << std::endl;
1815 printBodyDomainConnections();
1816#endif
1817}
1818
1819
1820/***
1821 * \brief checks if body center leaves domain and the corresponding dummybody center enters therefore the domain
1822 *
1823 * \author Johannes Grafen <johannes.grafen@rwth-aachen.de>
1824 *
1825 */
1826template <MInt nDim>
1828 TRACE();
1829
1830 if(m_associatedDummyBodies.empty()) return;
1831
1832 for(const auto& [bodyId, dummyId] : m_associatedDummyBodies) {
1833 MBool outside = -1 != grid().raw().findContainingHaloCell(&a_bodyCenter(bodyId, 0), -1, domainId(), true, nullptr);
1834 if(outside) {
1835 // swap body and its associated dummybody
1836 m_bodies.swap(bodyId, dummyId);
1837#ifdef RB_DEBUG
1838 m_debugFileStream << "body " << bodyId << " and associated dummyBody " << dummyId << " were swapped!"
1839 << std::endl;
1840#endif
1841 }
1842 }
1843}
1844
1845
1855template <MInt nDim>
1857 TRACE();
1858
1859#ifdef RB_DEBUG
1860 m_debugFileStream << "entering updateBodyDomainConnections on domain " << domainId() << std::endl;
1861 printBodyDomainConnections();
1862#endif
1863
1864 for(MInt i = 0; i < noNeighborDomains(); i++) {
1865 /* 1) if local body are intersecting with Halo Partition Cells
1866 ** copy local body -> edge body
1867 */
1868 MInt globDomain = neighborDomain(i);
1869 for(MInt bodyId = 0; bodyId < noConnectingBodies(); bodyId++) {
1870 MBool alreadyInside = std::binary_search(m_remoteDomainLocalBodies[globDomain].begin(),
1871 m_remoteDomainLocalBodies[globDomain].end(), bodyId);
1872
1873 MBool alreadySelfMapped = m_periodicBC && hasAssociatedDummyBody(bodyId);
1874
1875#ifdef RB_DEBUG
1876 m_debugFileStream << "D" << globDomain << " lBody " << bodyId << " already in mapping " << alreadyInside
1877 << " selfmapped " << alreadySelfMapped << std::endl;
1878 for(auto&& b : m_remoteDomainLocalBodies[globDomain]) {
1879 m_debugFileStream << "[" << globDomain << "," << b << "]" << std::endl;
1880 }
1881 m_debugFileStream << std::endl;
1882#endif
1883 if(alreadyInside || alreadySelfMapped) {
1884 continue;
1885 }
1886
1887 MInt intersectingCellId =
1888 grid().raw().intersectingWithHaloCells(&a_bodyCenter(bodyId, 0), m_infoDiameter / 2.0, i, true);
1889 if(intersectingCellId != -1) {
1890 if(domainId() == globDomain && m_periodicBC
1891 && grid().raw().a_hasProperty(intersectingCellId, Cell::IsPeriodic)) {
1892 // Hande Self-Mapping Case: A domain does not have to send something to itself, so the dummyBody does not
1893 // appear in the domain - body mappings, but a dummy has still to be added to collector, as the body has now
1894 // to different positions of the bodycenter, in the periodic case
1895 createDummyBody(bodyId);
1896 } else if(isLocalBody(bodyId)) {
1897 // Regular handling of edgeBodies, that have a remoteDomain
1898 std::vector<MInt>* bodyIds = &(m_remoteDomainLocalBodies[globDomain]);
1899 if(!std::binary_search(bodyIds->begin(), bodyIds->end(), bodyId)) {
1900 // Insert at the right position to keep this mapping sorted by the local body id
1901 bodyIds->insert(std::upper_bound(bodyIds->begin(), bodyIds->end(), bodyId), bodyId);
1902 }
1903 }
1904 }
1905 }
1906
1907
1908 /* 2) if edge body is no longer intersecting halo partition cells
1909 ** remove edge body -> []
1910 */
1911 std::vector<MInt> removeList;
1912 for(const MInt& bodyId : m_remoteDomainLocalBodies[globDomain]) {
1913 // checking only partition halo cells
1914 MInt intersectingCellId =
1915 grid().raw().intersectingWithHaloCells(&a_bodyCenter(bodyId, 0), m_infoDiameter / 2.0, i, true);
1916 if(intersectingCellId == -1) {
1917 // body is no longer intersecting haloPartitionCell (body has left domain ->
1918 // body that was previously marked as transferBody and now needs to be removed from edgeBodies of homeDomain)
1919 removeList.push_back(bodyId);
1920 }
1921 }
1922
1923#ifdef RB_DEBUG
1924 if(!removeList.empty()) {
1925 MString removeListS = "[";
1926 for(const MInt& body : removeList) {
1927 removeListS += std::to_string(body) + ", ";
1928 }
1929 removeListS += "] ";
1930 m_debugFileStream << "RemoveList for domain " << domainId() << " " << removeListS
1931 << " neighborDomain: " << neighborDomain(i) << std::endl;
1932 }
1933#endif
1934
1935 for(const auto& body : removeList) {
1936 // body is not remote on other domain, remove it from mapping and edgeBodies
1937 std::vector<MInt>* bodies = &m_remoteDomainLocalBodies[neighborDomain(i)];
1938 bodies->erase(std::remove(bodies->begin(), bodies->end(), body), bodies->end());
1939 }
1940 }
1941
1942 /* 3) if edge body intersects a periodic halo partition cell
1943 ** calculate periodic shift
1944 */
1945 if(m_periodicBC) {
1946 m_periodicShift.clear();
1947 // determine periodicShift for bodies that are remote on Neighbors
1948 for(MInt i = 0; i < noNeighborDomains(); i++) {
1949 MInt globDomain = neighborDomain(i);
1950
1951 if(globDomain == domainId()) continue;
1952
1953 for(const auto& bodyId : m_remoteDomainLocalBodies[globDomain]) {
1954 std::array<MFloat, nDim> center{};
1955 for(MInt n = 0; n < nDim; n++) {
1956 center[n] = a_bodyCenter(bodyId, n);
1957 }
1958 const MInt intersectingCellId =
1959 grid().raw().intersectingWithHaloCells(center.data(), m_infoDiameter / 2.0, i, true);
1960 std::array<MFloat, nDim> tmpShift{};
1961 for(MInt n = 0; n < nDim; n++) {
1962 tmpShift[n] = calculatePeriodicShift(intersectingCellId, n);
1963 }
1964 const MInt globalDomain = neighborDomain(i);
1965 m_periodicShift[globalDomain][bodyId] = tmpShift;
1966 }
1967 }
1968
1969 // Now handle Self-Mapped Bodies
1970 for(const auto& [localBodyId, dummyBodyId] : m_associatedDummyBodies) {
1971 std::array<MFloat, nDim> center{};
1972 for(MInt n = 0; n < nDim; n++) {
1973 center[n] = a_bodyCenter(localBodyId, n);
1974 }
1975 const MInt intersectingCellId =
1976 grid().raw().intersectingWithHaloCells(center.data(), m_infoDiameter / 2.0, 0, true);
1977 std::array<MFloat, nDim> tmpShift{};
1978 for(MInt n = 0; n < nDim; n++) {
1979 tmpShift[n] = calculatePeriodicShift(intersectingCellId, n);
1980 }
1981 m_periodicShift[domainId()][localBodyId] = tmpShift;
1982 }
1983
1984#ifdef RB_DEBUG
1985 MString periodicShiftS{};
1986 for(const auto& [domain, bodies] : m_periodicShift) {
1987 periodicShiftS += "on domain " + std::to_string(domain) + " periodic Shifts are: \n";
1988 for(const auto& [bodyId, shift] : bodies) {
1989 periodicShiftS += " bodyId: " + std::to_string(bodyId) + " [";
1990 for(MInt n = 0; n < nDim; n++) {
1991 periodicShiftS += std::to_string(shift[n]) + " ";
1992 }
1993 periodicShiftS += "] \n";
1994 }
1995 }
1996 m_debugFileStream << periodicShiftS;
1997#endif
1998 }
1999}
2000
2006template <MInt nDim>
2008 TRACE();
2009
2010 MInt newBodyId = noCollectorBodies();
2011 m_noDummyBodies++;
2012 m_associatedDummyBodies[bodyId] = newBodyId;
2013 m_globalBodyIds.push_back(getGlobalBodyId(bodyId));
2014 m_bodies.append();
2015#ifdef RB_DEBUG
2016 m_debugFileStream << "Self-mapping case, adding dummy body to collector at " << newBodyId
2017 << " associated with bodyId " << bodyId << std::endl;
2018#endif
2019 // Initialize the dummyBuddy in collector
2020 a_bodyRadius(newBodyId) = a_bodyRadius(bodyId);
2021 a_bodyDensityRatio(newBodyId) = a_bodyDensityRatio(bodyId);
2022 a_bodyTemperature(newBodyId) = a_bodyTemperature(bodyId);
2023 a_bodyHeatFlux(newBodyId) = a_bodyHeatFlux(bodyId);
2024 for(MInt n = 0; n < nDim; n++) {
2025 a_bodyRadii(newBodyId, n) = a_bodyRadii(bodyId, n);
2026 a_bodyInertia(newBodyId, n) = a_bodyInertia(bodyId, n);
2027 }
2028}
2029
2042template <MInt nDim>
2044 TRACE();
2045 MFloat shift = F0;
2046 const MInt n = direction;
2047 const MBool periodicDir = grid().raw().periodicCartesianDir(n);
2048 const MBool periodicCell = grid().raw().a_hasProperty(intersectingCellId, Cell::IsPeriodic);
2049 if(m_periodicBC && periodicDir && periodicCell) {
2050 if(grid().raw().periodicCartesianDir(n)) {
2051 const MFloat cellCoordinate = grid().raw().a_coordinate(intersectingCellId, n);
2052 const MInt sign1 = maia::math::sgn(globBBox(n) - cellCoordinate);
2053 const MInt sign2 = maia::math::sgn(globBBox(n + nDim) - cellCoordinate);
2054 MFloat sign = F0;
2055 if(sign1 == 1 && sign2 == 1) {
2056 sign = 1.0;
2057 } else if(sign1 == -1 && sign2 == -1) {
2058 sign = -1.0;
2059 }
2060 shift = m_globDomainLength[n] * sign;
2061 }
2062 }
2063 return shift;
2064}
2065
2074template <MInt nDim>
2076 TRACE();
2077 // exchange no of edge bodies to neighboring domains
2078 std::vector<MInt> noToRecv(noNeighborDomains());
2079 exchangeBufferLengthsNeighbor(noToRecv, m_remoteDomainLocalBodies);
2080
2081 std::vector<MPI_Request> mpi_send_req(noNeighborDomains(), MPI_REQUEST_NULL);
2082 std::vector<MPI_Request> mpi_recv_req(noNeighborDomains(), MPI_REQUEST_NULL);
2083
2084 // create receive buffer
2085 std::vector<std::vector<MFloat>> rcvBufferAll(noNeighborDomains());
2086 MInt bufSizePerBody = 1 + nDim * 1 + nRot * 2 + nQuat * 2 + 3;
2087
2088 // if not shape, different body Radii have to be send
2089 if(a_bodyType() != Shapes::Sphere) {
2090 bufSizePerBody += nDim;
2091 }
2092
2093 for(MInt n = 0; n < noNeighborDomains(); n++) {
2094 rcvBufferAll[n].resize(noToRecv[n] * bufSizePerBody);
2095 }
2096
2097 // non-blocking receive
2098 for(MInt i = 0; i < noNeighborDomains(); i++) {
2099 if(!noToRecv[i]) {
2100 continue;
2101 }
2102
2103 MPI_Irecv(rcvBufferAll[i].data(), rcvBufferAll[i].size(), maia::type_traits<MFloat>::mpiType(), neighborDomain(i),
2104 2, mpiComm(), &mpi_recv_req[i], AT_, "recv predict");
2105 }
2106
2107 // create send buffer
2108 MInt idx = 0;
2109 MInt paraCount = 0;
2110 std::vector<std::vector<MFloat>> sendBufferAll(noNeighborDomains());
2111 for(MInt i = 0; i < noNeighborDomains(); i++) {
2112 MInt globDomain = neighborDomain(i);
2113 if(domainId() == globDomain) continue;
2114
2115 auto& tmpSendBuffer = sendBufferAll[i];
2116 tmpSendBuffer.resize(bufSizePerBody * m_remoteDomainLocalBodies[globDomain].size());
2117 idx = 0;
2118 for(const auto& body : m_remoteDomainLocalBodies[globDomain]) {
2119 paraCount = 0;
2120 // send corresponding globalId of body
2121 tmpSendBuffer[idx * bufSizePerBody] = (MFloat)getGlobalBodyId(body);
2122 paraCount++;
2123
2124 for(MInt n = 0; n < nDim; n++) {
2125 tmpSendBuffer[idx * bufSizePerBody + paraCount + n] = a_bodyCenter(body, n);
2126 }
2127 paraCount += nDim;
2128
2129 // necessary to exchange quaternions?
2130 for(MInt r = 0; r < nRot; r++) {
2131 tmpSendBuffer[idx * bufSizePerBody + paraCount + r] = a_angularAccelerationBody(body, r);
2132 tmpSendBuffer[idx * bufSizePerBody + paraCount + nRot + r] = a_angularVelocityBodyT1B2(body, r);
2133 }
2134 paraCount += 2 * nRot;
2135
2136 for(MInt q = 0; q < nQuat; q++) {
2137 tmpSendBuffer[idx * bufSizePerBody + paraCount + q] = a_bodyQuaternionT1(body, q);
2138 tmpSendBuffer[idx * bufSizePerBody + paraCount + nQuat + q] = a_bodyQuaternionT1B2(body, q);
2139 }
2140 paraCount += 2 * nQuat;
2141
2142 tmpSendBuffer[idx * bufSizePerBody + paraCount] = a_bodyRadius(body);
2143 paraCount++;
2144 if(a_bodyType() != Shapes::Sphere) {
2145 for(MInt n = 0; n < nDim; n++) {
2146 tmpSendBuffer[idx * bufSizePerBody + paraCount + n] = a_bodyRadii(body, n);
2147 }
2148 paraCount += nDim;
2149 }
2150
2151 tmpSendBuffer[idx * bufSizePerBody + paraCount] = a_bodyDensityRatio(body);
2152 paraCount++;
2153 tmpSendBuffer[idx * bufSizePerBody + paraCount] = a_bodyTemperature(body);
2154 paraCount++;
2155 idx++;
2156 }
2157 }
2158
2159 // non-blocking send
2160 for(MInt i = 0; i < noNeighborDomains(); i++) {
2161 MInt globDomain = neighborDomain(i);
2162 if(m_remoteDomainLocalBodies[globDomain].empty()) {
2163 continue;
2164 }
2165
2166 MPI_Isend(sendBufferAll[i].data(), sendBufferAll[i].size(), maia::type_traits<MFloat>::mpiType(), neighborDomain(i),
2167 2, mpiComm(), &mpi_send_req[i], AT_, "send predict");
2168 }
2169
2170 // wait for communication to finish
2171 for(MInt i = 0; i < noNeighborDomains(); i++) {
2172 MInt globDomain = neighborDomain(i);
2173 if(!m_remoteDomainLocalBodies[globDomain].empty()) {
2174 MPI_Wait(&mpi_send_req[i], MPI_STATUS_IGNORE, AT_);
2175 }
2176
2177 if(noToRecv[i]) {
2178 MPI_Wait(&mpi_recv_req[i], MPI_STATUS_IGNORE, AT_);
2179 }
2180 }
2181
2182 // All bodies, that are marked as remote on domain are added to remove list
2183 // it is checked if data for the body that was already remote is received
2184 // if not it is not relevant anymore and can be deleted from the mapping
2185 std::list<std::pair<MInt, MInt>> remoteBodyRemoveList;
2186 for(const auto& [homeDomain, bodies] : m_homeDomainRemoteBodies) {
2187 for(const MInt rBody : bodies) {
2188 remoteBodyRemoveList.push_back(std::make_pair(homeDomain, rBody));
2189 }
2190 }
2191
2192#ifdef RB_DEBUG
2193 MString removeListS = "[";
2194 for(const auto& body : remoteBodyRemoveList) {
2195 removeListS += "[" + std::to_string(body.first) + "," + std::to_string(body.second) + "]";
2196 }
2197 removeListS += "] ";
2198 m_debugFileStream << "Before: RemoveList for domain " << domainId() << " " << removeListS << std::endl;
2199 printBodyDomainConnections();
2200#endif
2201
2202 // unpack buffer
2203 for(MInt n = 0; n < noNeighborDomains(); n++) {
2204 MInt globalDomain = neighborDomain(n);
2205 MInt mapIdx = 0;
2206 for(MInt b = 0; b < noToRecv[n]; b++) {
2207 paraCount = 0;
2208 MInt remoteBodyId = rcvBufferAll[n][b * bufSizePerBody];
2209 paraCount++;
2210
2211#ifdef RB_DEBUG
2212 m_debugFileStream << "domain: " << domainId() << " receives remoteBodyId: " << remoteBodyId << " from "
2213 << globalDomain << " with locId " << getLocalBodyId(remoteBodyId) << std::endl;
2214#endif
2215
2216 MInt localBodyId = getLocalBodyId(remoteBodyId);
2217 if(localBodyId != -1) {
2218 // received data for localBodyId, body is still relevant and therefore has to be eliminated again from list
2219 std::list<std::pair<MInt, MInt>>* a = &remoteBodyRemoveList;
2220 a->erase(std::remove_if(a->begin(), a->end(),
2221 [&localBodyId](std::pair<MInt, MInt> x) { return x.second == localBodyId; }),
2222 a->end());
2223
2224 for(const auto& [domain, bodies] : m_homeDomainRemoteBodies) {
2225 if(bodies.empty()) continue;
2226
2227 for(const auto& bodyId : bodies) {
2228 // check if body was previously in m_transferBodies -> homeDomain has changed and
2229 // mapping needs to be updated accordingly
2230 if(domain != globalDomain && localBodyId == bodyId) {
2231 // Body was transfered and has a new homeDomain
2232 std::vector<MInt>* c = &m_homeDomainRemoteBodies[domain];
2233 c->erase(std::remove(c->begin(), c->end(), localBodyId), c->end());
2234 m_homeDomainRemoteBodies[globalDomain].push_back(localBodyId);
2235 break;
2236 }
2237 }
2238 }
2239
2240 // Ensure the bodies in the mapping are in the received order
2241 // This is important for all communication buffers to be consistent
2242 std::vector<MInt>& remoteBodies = m_homeDomainRemoteBodies[globalDomain];
2243 auto actualPos = std::find(remoteBodies.begin(), remoteBodies.end(), localBodyId);
2244 auto wantedPos = remoteBodies.begin() + mapIdx;
2245 std::iter_swap(actualPos, wantedPos);
2246 mapIdx++;
2247 m_debugFileStream << "SWAP SWAP";
2248 for(auto&& r : remoteBodies) {
2249 m_debugFileStream << r << ",";
2250 }
2251 m_debugFileStream << std::endl;
2252
2253 } else {
2254 // we want to maintain the structure in the collector (localBodies | remoteBodies | dummyBodies)
2255 // therefore all relevant Mappings have to be updated accordingly
2256 // if there are no dummyBodies in collector we can simply append to collector
2257 if(m_associatedDummyBodies.empty()) {
2258 m_bodies.append();
2259 m_globalBodyIds.push_back(remoteBodyId);
2260 m_noRemoteBodies++;
2261 m_homeDomainRemoteBodies[globalDomain].push_back(m_globalBodyIds.size() - 1);
2262 mapIdx++;
2263 } else {
2264 // if there are already dummy Bodies in the collector
2265 // a new Remote Body is inserted in the collector in front of all dummy bodies
2266 MInt newIdx = noConnectingBodies();
2267 m_bodies.insert(newIdx);
2268 m_globalBodyIds.insert(m_globalBodyIds.begin() + newIdx, remoteBodyId);
2269 m_noRemoteBodies++;
2270 m_homeDomainRemoteBodies[globalDomain].push_back(newIdx);
2271 mapIdx++;
2272 for(auto& [bodyId, dummyId] : m_associatedDummyBodies) {
2273 dummyId++;
2274 }
2275 }
2276 }
2277
2278 const MInt newLocalBodyId = getLocalBodyId(remoteBodyId);
2279
2280 for(MInt d = 0; d < nDim; d++) {
2281 a_bodyCenter(newLocalBodyId, d) = rcvBufferAll[n][b * bufSizePerBody + paraCount + d];
2282 }
2283 paraCount += nDim;
2284
2285 for(MInt r = 0; r < nRot; r++) {
2286 a_angularAccelerationBody(newLocalBodyId, r) = rcvBufferAll[n][b * bufSizePerBody + paraCount + r];
2287 a_angularVelocityBodyT1B2(newLocalBodyId, r) = rcvBufferAll[n][b * bufSizePerBody + paraCount + nRot + r];
2288 }
2289 paraCount += 2 * nRot;
2290
2291 for(MInt q = 0; q < nQuat; q++) {
2292 a_bodyQuaternionT1(newLocalBodyId, q) = rcvBufferAll[n][b * bufSizePerBody + paraCount + q];
2293 a_bodyQuaternionT1B2(newLocalBodyId, q) = rcvBufferAll[n][b * bufSizePerBody + paraCount + nQuat + q];
2294 }
2295 paraCount += 2 * nQuat;
2296
2297 a_bodyRadius(newLocalBodyId) = rcvBufferAll[n][b * bufSizePerBody + paraCount];
2298 paraCount++;
2299 if(a_bodyType() != Shapes::Sphere) {
2300 for(MInt d = 0; d < nDim; d++) {
2301 a_bodyRadii(newLocalBodyId, d) = rcvBufferAll[n][b * bufSizePerBody + paraCount + d];
2302 }
2303 paraCount += nDim;
2304 } else {
2305 std::fill_n(&a_bodyRadii(newLocalBodyId, 0), nDim, a_bodyRadius(newLocalBodyId));
2306 }
2307
2308 a_bodyDensityRatio(newLocalBodyId) = rcvBufferAll[n][b * bufSizePerBody + paraCount];
2309 paraCount++;
2310 a_bodyTemperature(newLocalBodyId) = rcvBufferAll[n][b * bufSizePerBody + paraCount];
2311 paraCount++;
2312 a_bodyHeatFlux(newLocalBodyId) = 0.0;
2313
2314 // if domain receives a new remote Body, that has to be self-mapped on remoteDomain, create dummyBody
2315 const MInt remoteBodyIntersectsWithDomainId =
2316 grid().raw().intersectingWithHaloCells(&a_bodyCenter(newLocalBodyId, 0), m_infoDiameter / 2.0, 0, true);
2317 if(m_periodicBC && !hasAssociatedDummyBody(newLocalBodyId) && remoteBodyIntersectsWithDomainId != -1
2318 && grid().raw().a_hasProperty(remoteBodyIntersectsWithDomainId, Cell::IsPeriodic)) {
2319 createDummyBody(newLocalBodyId);
2320
2321 std::array<MFloat, nDim> center{};
2322 for(MInt d = 0; d < nDim; d++) {
2323 center[n] = a_bodyCenter(newLocalBodyId, n);
2324 }
2325
2326 for(MInt d = 0; d < nDim; d++) {
2327 m_periodicShift[domainId()][newLocalBodyId][d] = calculatePeriodicShift(remoteBodyIntersectsWithDomainId, d);
2328 }
2329 // initialize dummyBody kinematic data with the data of the remote Body
2330 initRemoteDummyBodyData(newLocalBodyId);
2331 }
2332 }
2333 }
2334
2335#ifdef RB_DEBUG
2336 if(!remoteBodyRemoveList.empty()) {
2337 removeListS = "[";
2338 for(const auto& body : remoteBodyRemoveList) {
2339 removeListS += "[" + std::to_string(body.first) + "," + std::to_string(body.second) + "]";
2340 }
2341 removeListS += "] ";
2342 m_debugFileStream << "After: RemoveList for domain " << domainId() << " " << removeListS << std::endl;
2343 }
2344#endif
2345
2346 deleteIrrelevantBodies(remoteBodyRemoveList);
2347}
2348
2356template <MInt nDim>
2358 TRACE();
2359
2360 const MInt dummyId = m_associatedDummyBodies[bodyId];
2361 if(isRemoteBody(bodyId)) {
2362 // Exchange kinematic Data for remote self-mapped Bodies
2363 for(MInt n = 0; n < nDim; n++) {
2364 a_bodyCenter(dummyId, n) = a_bodyCenter(bodyId, n) + m_periodicShift[domainId()][bodyId][n];
2365 a_bodyVelocity(dummyId, n) = a_bodyVelocity(bodyId, n);
2366 a_bodyAcceleration(dummyId, n) = a_bodyAcceleration(bodyId, n);
2367 a_bodyForce(dummyId, n) = -a_bodyForce(bodyId, n);
2368 a_bodyTorque(dummyId, n) = a_bodyTorque(bodyId, n);
2369 }
2370 for(MInt r = 0; r < nRot; r++) {
2371 a_angularVelocity(dummyId, r) = a_angularVelocity(bodyId, r);
2372 a_angularVelocityBody(dummyId, r) = a_angularVelocityBody(bodyId, r);
2373 }
2374 for(MInt q = 0; q < nQuat; q++) {
2375 a_bodyQuaternionT1(dummyId, q) = a_bodyQuaternionT1(bodyId, q);
2376 }
2377 } else {
2378#ifdef RB_DEBUG
2379 m_debugFileStream << "Something went wrong, body with localId: " << bodyId
2380 << " is not a remoteBody -> dummyBodyData cannot be initialized!" << std::endl;
2381#endif
2382 return;
2383 }
2384}
2385
2394template <MInt nDim>
2395MInt RigidBodies<nDim>::localToRemoteBody(const MInt collectorId, const MInt oldBodyId, const MInt domain) {
2396 TRACE();
2397
2398 if(m_noLocalBodies <= 0) {
2399 mTerm(1, AT_, "Domain: " + std::to_string(domainId()) + " has no local bodies that can change to remote status!");
2400 }
2401
2402 const MInt newIdx = m_noLocalBodies - 1;
2403
2404 if(hasAssociatedDummyBody(oldBodyId)) {
2405 deleteDummyBody(oldBodyId);
2406 }
2407
2408 // If more than one localBody in collector -> do swap, else not necessary to swap, just mark local body as remote
2409 if(noConnectingBodies() > 0) {
2410 m_bodies.swap(collectorId, newIdx);
2411 iter_swap(m_globalBodyIds.begin() + collectorId, m_globalBodyIds.begin() + newIdx);
2412 }
2413
2414 m_noLocalBodies--;
2415 m_noRemoteBodies++;
2416
2417 /* Delete from local Bodies, now a remote Body
2418 / Not every local Body has a corresponding remoteDomain, therefore, we need to check each body, already
2419 / contained in the mapping. A local body can potentielly be remote to multiple domains
2420 / -> iterate over all domains in mapping
2421 */
2422 for(MInt n = 0; n < noNeighborDomains(); n++) {
2423 MInt globDomain = neighborDomain(n);
2424 std::vector<MInt>* bodies = &m_remoteDomainLocalBodies[globDomain];
2425
2426 // Check if the swapped body is in the mapping
2427 auto swappedIt = std::find(bodies->begin(), bodies->end(), newIdx);
2428 if(swappedIt != bodies->end()) {
2429 // Swapped body is in the mapping, delete its old entry and keep the other for the swapped Body
2430 bodies->erase(std::remove(bodies->begin(), bodies->end(), newIdx), bodies->end());
2431 } else {
2432 // Swapped body is NOT in the mapping, just delete the entry of the old local body
2433 bodies->erase(std::remove(bodies->begin(), bodies->end(), collectorId), bodies->end());
2434 }
2435
2436 if(hasAssociatedDummyBody(newIdx)) {
2437 m_associatedDummyBodies.erase(newIdx);
2438 m_associatedDummyBodies[newIdx] = collectorId;
2439 }
2440 }
2441
2442 m_homeDomainRemoteBodies[domain].push_back(newIdx);
2443
2444 return newIdx;
2445}
2446
2447
2454template <MInt nDim>
2455void RigidBodies<nDim>::deleteIrrelevantBodies(std::list<std::pair<MInt, MInt>>& removeList) {
2456 TRACE();
2457
2458 // Sort in descending order
2459 removeList.sort([](const std::pair<MInt, MInt>& a, const std::pair<MInt, MInt>& b) { return a.second > b.second; });
2460
2461 std::vector<MInt> removeListGlobIds;
2462 for(const auto& [homeDomain, body] : removeList) {
2463 removeListGlobIds.push_back(getGlobalBodyId(body));
2464 }
2465
2466 MInt collectorShiftIdx = 0;
2467 for(const auto& [homeDomain, body] : removeList) {
2468 m_bodyWasDeleted = true;
2469#ifdef RB_DEBUG
2470 m_debugFileStream << "Deleting remotebody " << body << " on domain " << domainId() << std::endl;
2471#endif
2472
2473 m_globalBodyIds.erase(
2474 std::remove(m_globalBodyIds.begin(), m_globalBodyIds.end(), removeListGlobIds[collectorShiftIdx]),
2475 m_globalBodyIds.end());
2476
2477 m_bodies.removeAndShift(body);
2478 m_noRemoteBodies--;
2479
2480 m_homeDomainRemoteBodies[homeDomain].erase(
2481 std::remove(m_homeDomainRemoteBodies[homeDomain].begin(), m_homeDomainRemoteBodies[homeDomain].end(), body),
2482 m_homeDomainRemoteBodies[homeDomain].end());
2483
2484 collectorShiftIdx++;
2485 // In case a remoteBody has also an associated dummy Body
2486 auto aDBCopy = m_associatedDummyBodies;
2487 for(auto& [bodyId, dummyId] : aDBCopy) {
2488 if(bodyId == body) {
2489 deleteDummyBody(bodyId, collectorShiftIdx);
2490 }
2491 }
2492 }
2493
2494#ifdef RB_DEBUG
2495 m_debugFileStream << "after deletion: " << std::endl;
2496 printBodyDomainConnections();
2497#endif
2498
2499 // Adjust localIds in mapping accordingly
2500 for(std::list<std::pair<MInt, MInt>>::const_iterator it = removeList.cbegin(); it != removeList.cend(); it++) {
2501 for(auto& [domain, bodies] : m_homeDomainRemoteBodies) {
2502 // adjust localIds
2503 for(MInt& body : bodies) {
2504#ifdef RB_DEBUG
2505 m_debugFileStream << "body " << body << " it " << it->second << std::endl;
2506#endif
2507 if(body > it->second) {
2508 body--;
2509 }
2510 }
2511 }
2512 for(auto& [bodyId, dummyId] : m_associatedDummyBodies) {
2513#ifdef RB_DEBUG
2514 m_debugFileStream << "body " << bodyId << " with Dummybody " << dummyId << " it " << it->second << std::endl;
2515#endif
2516 if(dummyId > it->second) {
2517 dummyId--;
2518 }
2519 }
2520 }
2521
2522#ifdef RB_DEBUG
2523 m_debugFileStream << "after deletion and update of mappings: " << std::endl;
2524 printBodyDomainConnections();
2525#endif
2526}
2527
2536template <MInt nDim>
2537void RigidBodies<nDim>::deleteDummyBody(const MInt bodyId, const MInt collectorShift) {
2538 TRACE();
2539
2540 const MInt dummyBodyId = m_associatedDummyBodies[bodyId] - collectorShift;
2541
2542#ifdef RB_DEBUG
2543 m_debugFileStream << "Deleting Dummy Body " << m_associatedDummyBodies[bodyId] << " with corresponding bodyId "
2544 << bodyId << std::endl;
2545#endif
2546
2547 m_associatedDummyBodies.erase(bodyId);
2548 m_globalBodyIds.erase(std::remove(m_globalBodyIds.begin(), m_globalBodyIds.end(), dummyBodyId),
2549 m_globalBodyIds.end());
2550
2551 m_bodies.removeAndShift(dummyBodyId);
2552 m_noDummyBodies--;
2553
2554 m_bodyWasDeleted = true;
2555
2556#ifdef RB_DEBUG
2557 printBodyDomainConnections();
2558#endif
2559}
2560
2561template <MInt nDim>
2563 TRACE();
2564 // for every remote body:
2565 // check every neighbordomain halo cells for intersection
2566 // contains globalIds
2567 std::vector<std::vector<MInt>> bodyIdsForRemoteDomain;
2568 std::vector<std::vector<MInt>> homeDomainIdsForRemoteDomain;
2569
2570 // contains localIds
2571 std::vector<std::vector<MInt>> bodyIdsForHomeDomain;
2572 std::vector<std::vector<MInt>> remoteDomainIdsForHomeDomain;
2573 std::vector<std::vector<std::array<MFloat, nDim>>> shiftForHomeDomain;
2574
2575 // body Ids + homeDomain Ids to send to remote domains
2576 bodyIdsForRemoteDomain.clear();
2577 bodyIdsForRemoteDomain.resize(noNeighborDomains());
2578
2579 homeDomainIdsForRemoteDomain.clear();
2580 homeDomainIdsForRemoteDomain.resize(noNeighborDomains());
2581
2582 // body Ids + remoteDomain Ids + shift to send to home domains
2583 bodyIdsForHomeDomain.clear();
2584 bodyIdsForHomeDomain.resize(noHomeDomains());
2585
2586 remoteDomainIdsForHomeDomain.clear();
2587 remoteDomainIdsForHomeDomain.resize(noHomeDomains());
2588
2589 shiftForHomeDomain.clear();
2590 shiftForHomeDomain.resize(noHomeDomains());
2591
2592 MInt count = 0;
2593 for(MInt i = 0; i < noNeighborDomains(); i++) {
2594 count = 0;
2595 for(const auto& [homeDomain, bodies] : m_homeDomainRemoteBodies) {
2596 for(const auto& body : bodies) {
2597 // check neighbor domain halo cells
2598 std::array<MFloat, nDim> center{};
2599 for(MInt n = 0; n < nDim; n++) {
2600 center[n] = a_bodyCenter(body, n);
2601 }
2602 const MInt intersectingCellId =
2603 grid().raw().intersectingWithHaloCells(center.data(), m_infoDiameter / 2.0, i, true);
2604 if(intersectingCellId != -1) {
2605 // data for new remote domain
2606 bodyIdsForRemoteDomain[i].push_back(getGlobalBodyId(body));
2607 homeDomainIdsForRemoteDomain[i].push_back(homeDomain);
2608
2609 // data for home domain
2610 const MInt remoteDomain = neighborDomain(i);
2611 // dont send body to its own home domain
2612 if(homeDomain == remoteDomain) {
2613 continue;
2614 }
2615 bodyIdsForHomeDomain[count].push_back(getGlobalBodyId(body));
2616 remoteDomainIdsForHomeDomain[count].push_back(remoteDomain);
2617 // shift
2618 std::array<MFloat, nDim> shiftVector{};
2619 for(MInt n = 0; n < nDim; n++) {
2620 const MFloat shift = calculatePeriodicShift(intersectingCellId, n);
2621 shiftVector[n] = shift;
2622 }
2623 shiftForHomeDomain[count].push_back(shiftVector);
2624 }
2625 }
2626 count++;
2627 }
2628 }
2629
2630 std::map<MInt, std::vector<MInt>> tmpRemoteMap;
2631
2632 exchangeNeighborNeighborRemote(bodyIdsForRemoteDomain, homeDomainIdsForRemoteDomain, tmpRemoteMap);
2633 exchangeNeighborNeighborHome(bodyIdsForHomeDomain, remoteDomainIdsForHomeDomain, shiftForHomeDomain);
2634
2635 // transfer tmp maps to member mappings
2636 for(auto [homeDomainId, remoteBodyIds] : tmpRemoteMap) {
2637 for(auto remoteBodyId : remoteBodyIds) {
2638 if(homeDomainId == domainId()) continue;
2639 const std::vector<MInt>* bodyIds = &(m_homeDomainRemoteBodies[homeDomainId]);
2640 // check if remote body is not in mapping yet
2641 if(!std::binary_search(bodyIds->begin(), bodyIds->end(), remoteBodyId)) {
2642 std::cout << "In Timestep " << globalTimeStep << "indirect Neighborstuff" << std::endl;
2643 // PseudoLocal, as just remote body for domain, but body is contained in collector
2644 // const MInt newPseudoLocalBodyId = getLocalBodyId(remoteBodyId);
2645 m_homeDomainRemoteBodies[homeDomainId].push_back(remoteBodyId);
2646 }
2647 }
2648 }
2649}
2650
2651template <MInt nDim>
2652void RigidBodies<nDim>::exchangeNeighborNeighborRemote(std::vector<std::vector<MInt>>& bodyIdsForRemoteDomain,
2653 std::vector<std::vector<MInt>>& homeDomainIdsForRemoteDomain,
2654 std::map<MInt, std::vector<MInt>>& tmpRemoteMap) {
2655 TRACE();
2656 std::vector<MPI_Request> mpi_send_req(noNeighborDomains(), MPI_REQUEST_NULL);
2657 std::vector<MPI_Request> mpi_recv_req(noNeighborDomains(), MPI_REQUEST_NULL);
2658
2659 // body Ids, home domain
2660 const MInt bufSizePerBody = 1 + 1;
2661 std::vector<MInt> noToSend(noNeighborDomains());
2662 for(MInt n = 0; n < noNeighborDomains(); n++) {
2663 noToSend[n] = bodyIdsForRemoteDomain[n].size();
2664 }
2665 // pack send buffer
2666 std::vector<std::vector<MInt>> sendBufferAll(noNeighborDomains());
2667 for(MInt n = 0; n < noNeighborDomains(); n++) {
2668 sendBufferAll[n].resize(noToSend[n] * bufSizePerBody);
2669 for(MInt b = 0; b < noToSend[n]; b++) {
2670 sendBufferAll[n][b * bufSizePerBody] = bodyIdsForRemoteDomain[n][b];
2671 sendBufferAll[n][b * bufSizePerBody + 1] = homeDomainIdsForRemoteDomain[n][b];
2672 }
2673 }
2674 // exchange buffer lengths
2675 std::vector<MInt> noToRecv(noNeighborDomains());
2676 exchangeBufferLengthsNeighbor(noToRecv, bodyIdsForRemoteDomain);
2677
2678 // create receive buffer
2679 std::vector<std::vector<MInt>> recvBufferAll(noNeighborDomains());
2680 for(MInt n = 0; n < noNeighborDomains(); n++) {
2681 recvBufferAll[n].resize(noToRecv[n] * bufSizePerBody);
2682 }
2683
2684 // recv
2685 for(MInt n = 0; n < noNeighborDomains(); n++) {
2686 MPI_Irecv(recvBufferAll[n].data(), recvBufferAll[n].size(), maia::type_traits<MInt>::mpiType(), neighborDomain(n),
2687 2, mpiComm(), &mpi_recv_req[n], AT_, "recv neighbor-neighbor exchange");
2688 }
2689
2690 // send
2691 for(MInt n = 0; n < noNeighborDomains(); n++) {
2692 MPI_Isend(sendBufferAll[n].data(), sendBufferAll[n].size(), maia::type_traits<MInt>::mpiType(), neighborDomain(n),
2693 2, mpiComm(), &mpi_send_req[n], AT_, "send neighbor-neighbor exchange");
2694 }
2695
2696 // wait for communication to finish
2697 for(MInt i = 0; i < noNeighborDomains(); i++) {
2698 MPI_Wait(&mpi_send_req[i], MPI_STATUS_IGNORE, AT_);
2699 MPI_Wait(&mpi_recv_req[i], MPI_STATUS_IGNORE, AT_);
2700 }
2701
2702 // unpack recv Buffer and fill remoteBodyHomeDomains
2703 for(MInt n = 0; n < noNeighborDomains(); n++) {
2704 for(MInt b = 0; b < noToRecv[n]; b++) {
2705 const MInt remoteBodyId = getLocalBodyId(recvBufferAll[n][b * bufSizePerBody]);
2706 const MInt homeDomain = recvBufferAll[n][b * bufSizePerBody + 1];
2707 const std::vector<MInt>* bodyIds = &(tmpRemoteMap[homeDomain]);
2708 // check if remote body is not in mappin yet
2709 if(!std::binary_search(bodyIds->begin(), bodyIds->end(), remoteBodyId)) {
2710 tmpRemoteMap[homeDomain].push_back(remoteBodyId);
2711 }
2712 }
2713 }
2714}
2715
2716template <MInt nDim>
2718 std::vector<std::vector<MInt>>& bodyIdsForHomeDomain,
2719 std::vector<std::vector<MInt>>& remoteDomainIdsForHomeDomain,
2720 std::vector<std::vector<std::array<MFloat, nDim>>>& shiftForHomeDomain) {
2721 TRACE();
2722 std::vector<MPI_Request> mpi_send_req(noHomeDomains(), MPI_REQUEST_NULL);
2723 std::vector<MPI_Request> mpi_recv_req(noRemoteDomains(), MPI_REQUEST_NULL);
2724
2725 // exchange buffer lengths to home domains
2726 std::vector<MInt> noToRecv(noRemoteDomains());
2727
2728 // body Id + remote domain id + shift
2729 const MInt bufSizePerBody = 1 + 1 + nDim;
2730 std::vector<MInt> noToSend(noHomeDomains());
2731 for(MInt n = 0; n < noHomeDomains(); n++) {
2732 noToSend[n] = bodyIdsForHomeDomain[n].size();
2733 }
2734
2735 exchangeBufferLengthsRemoteToHome(noToRecv, noToSend);
2736
2737 // create receive buffer
2738 std::vector<std::vector<MFloat>> recvBufferAll(noRemoteDomains());
2739 for(MInt n = 0; n < noRemoteDomains(); n++) {
2740 recvBufferAll[n].resize(noToRecv[n] * bufSizePerBody);
2741 }
2742
2743 // pack send buffer
2744 std::vector<std::vector<MFloat>> sendBufferAll(noHomeDomains());
2745 for(MInt n = 0; n < noHomeDomains(); n++) {
2746 sendBufferAll[n].resize(noToSend[n] * bufSizePerBody);
2747 for(MInt b = 0; b < noToSend[n]; b++) {
2748 sendBufferAll[n][b * bufSizePerBody] = bodyIdsForHomeDomain[n][b];
2749 sendBufferAll[n][b * bufSizePerBody + 1] = remoteDomainIdsForHomeDomain[n][b];
2750 for(MInt i = 0; i < nDim; i++) {
2751 sendBufferAll[n][b * bufSizePerBody + 2 + i] = shiftForHomeDomain[n][b][i];
2752 }
2753 }
2754 }
2755
2756 // recv
2757 MInt count = 0;
2758 for(const auto& [remoteDomain, bodies] : m_remoteDomainLocalBodies) {
2759 if(noToRecv[count]) {
2760 MPI_Irecv(recvBufferAll[count].data(), recvBufferAll[count].size(), maia::type_traits<MFloat>::mpiType(),
2761 remoteDomain, 2, mpiComm(), &mpi_recv_req[count], AT_, "recv neighbor-neighbor exchange");
2762 }
2763 count++;
2764 }
2765
2766 // send
2767 count = 0;
2768 for(const auto& [homeDomain, bodies] : m_homeDomainRemoteBodies) {
2769 if(noToSend[count]) {
2770 MPI_Isend(sendBufferAll[count].data(), sendBufferAll[count].size(), maia::type_traits<MFloat>::mpiType(),
2771 homeDomain, 2, mpiComm(), &mpi_send_req[count], AT_, "send neighbor-neighbor exchange");
2772 }
2773 count++;
2774 }
2775
2776 // wait for communication to finish
2777 for(MInt i = 0; i < noHomeDomains(); i++) {
2778 if(noToSend[i]) {
2779 MPI_Wait(&mpi_send_req[i], MPI_STATUS_IGNORE, AT_);
2780 }
2781 }
2782
2783 for(MInt i = 0; i < noRemoteDomains(); i++) {
2784 if(noToRecv[i]) {
2785 MPI_Wait(&mpi_recv_req[i], MPI_STATUS_IGNORE, AT_);
2786 }
2787 }
2788
2789 // unpack buffer
2790 const MInt currNoRemoteDomains = noRemoteDomains();
2791 for(MInt n = 0; n < currNoRemoteDomains; n++) {
2792 for(MInt b = 0; b < noToRecv[n]; b++) {
2793 const MInt localBodyId = getLocalBodyId((MInt)recvBufferAll[n][b * bufSizePerBody]);
2794 const MInt remoteDomainId = (MInt)recvBufferAll[n][b * bufSizePerBody + 1];
2795
2796 std::array<MFloat, nDim> shift{};
2797 for(MInt i = 0; i < nDim; i++) {
2798 shift[i] = recvBufferAll[n][b * bufSizePerBody + 2 + i];
2799 }
2800
2801 if(m_remoteDomainLocalBodies.find(remoteDomainId) != m_remoteDomainLocalBodies.end()) {
2802 std::vector<MInt>* bodyIds = &(m_remoteDomainLocalBodies[remoteDomainId]);
2803 if(std::binary_search(bodyIds->begin(), bodyIds->end(), localBodyId)) {
2804 continue;
2805 }
2806 }
2807 m_remoteDomainLocalBodies[remoteDomainId].push_back(localBodyId);
2808 m_periodicShift[remoteDomainId][localBodyId] = shift;
2809 }
2810 }
2811}
2812
2819template <MInt nDim>
2821 TRACE();
2822
2823 std::vector<MString> sBodies;
2824 MInt idx = 0;
2825
2826 sBodies.emplace_back("");
2827 if(m_noLocalBodies != 0) {
2828 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
2829 sBodies[idx] += std::to_string(bodyId) + " ";
2830 }
2831 }
2832 idx++;
2833
2834 sBodies.emplace_back("");
2835 if(m_noRemoteBodies > 0) {
2836 for(MInt bodyId = m_noLocalBodies; bodyId < noConnectingBodies(); bodyId++) {
2837 sBodies[idx] += std::to_string(bodyId) + " ";
2838 }
2839 }
2840 idx++;
2841
2842 sBodies.emplace_back("");
2843 if(m_noDummyBodies > 0) {
2844 for(MInt bodyId = noConnectingBodies(); bodyId < noCollectorBodies(); bodyId++) {
2845 sBodies[idx] += std::to_string(bodyId) + " ";
2846 }
2847 }
2848 idx++;
2849
2850 sBodies.emplace_back("");
2851 if(!m_transferBodies.empty()) {
2852 for(MInt i = 0; i < noNeighborDomains(); i++) {
2853 if(!m_transferBodies[i].empty()) {
2854 MString sTmp;
2855 for(MInt body : m_transferBodies[i]) {
2856 sTmp += std::to_string(body) + " ";
2857 }
2858 sBodies[idx] += std::to_string(neighborDomain(i)) + ": [" + sTmp + " ] | ";
2859 }
2860 }
2861 }
2862 idx++;
2863
2864 sBodies.emplace_back("");
2865 if(!m_globalBodyIds.empty()) {
2866 for(MUint localBodyId = 0; localBodyId < m_globalBodyIds.size(); localBodyId++) {
2867 sBodies[idx] +=
2868 "| localId: " + std::to_string(localBodyId) + " globalId: " + std::to_string(m_globalBodyIds[localBodyId]);
2869 }
2870 }
2871 idx++;
2872
2873 sBodies.emplace_back("");
2874 if(!m_remoteDomainLocalBodies.empty()) {
2875 for(const auto& [domain, bodies] : m_remoteDomainLocalBodies) {
2876 for(const auto& body : bodies) {
2877 sBodies[idx] += std::string(" ") + "[" + std::to_string(domain) + ", " + std::to_string(body) + "]";
2878 }
2879 }
2880 }
2881 idx++;
2882
2883 sBodies.emplace_back("");
2884 if(!m_homeDomainRemoteBodies.empty()) {
2885 for(const auto& [domain, bodies] : m_homeDomainRemoteBodies) {
2886 for(const auto& body : bodies) {
2887 sBodies[idx] += std::string(" ") + "[" + std::to_string(domain) + ", " + std::to_string(body) + "]";
2888 }
2889 }
2890 }
2891 idx++;
2892
2893 sBodies.emplace_back("");
2894 if(!m_associatedDummyBodies.empty()) {
2895 for(const auto& [body, dummy] : m_associatedDummyBodies) {
2896 sBodies[idx] += std::string(" ") + "[" + std::to_string(body) + ", " + std::to_string(dummy) + "]";
2897 }
2898 }
2899 idx++;
2900
2901 m_debugFileStream << "--------------BODY INFO for domain: " << domainId() << "---------------------" << std::endl
2902 << " contains bodyIds [ " << sBodies[0] << " ]" << std::endl
2903 << " contains remoteBodyIds [ " << sBodies[1] << " ]" << std::endl
2904 << " contains dummyBodyIds [ " << sBodies[2] << " ]" << std::endl
2905 << " has transferBodies for neighbourdomain " << sBodies[3] << std::endl
2906 << " has following pairings: " << sBodies[4] << std::endl
2907 << " remote domain - local body pairings: " << sBodies[5] << std::endl
2908 << " home domain - remote body pairings: " << sBodies[6] << std::endl
2909 << " body - associated dummy pairings: " << sBodies[7] << std::endl
2910 << " collector has capacity: " << m_bodies.capacity() << " and size " << m_bodies.size()
2911 << " MaxNoBodies is " << m_maxNoBodies << std::endl;
2912}
2913
2924template <>
2925inline void RigidBodies<3>::predictRotation(const MInt bodyId) {
2926 const MFloat dt = m_timestep;
2927
2928 MFloat angularVelocityBodyT3B4[nRot]{};
2929 // Advance angular velocity from time n+1/2 to time n+3/4
2930 for(MInt n = 0; n < nRot; n++) {
2931 angularVelocityBodyT3B4[n] =
2932 a_angularVelocityBodyT1B2(bodyId, n) + 0.25 * dt * a_angularAccelerationBody(bodyId, n);
2933 }
2934 // Transform angular velocity to world frame
2935 MFloat angularVelocityT3B4[nRot]{};
2936 transformToWorldFrame(&a_bodyQuaternionT1B2(bodyId, 0), angularVelocityBodyT3B4, angularVelocityT3B4);
2937
2938 // Advance bodyQuaternion from time n+1/2 to time n+1
2939 advanceQuaternion(angularVelocityT3B4, dt / 2, &a_bodyQuaternionT1B2(bodyId, 0), &a_bodyQuaternionT1(bodyId, 0));
2940
2941 // Advance angular velocity from time n+1/2 to time n+3/4
2942 for(MInt n = 0; n < nRot; n++) {
2943 a_angularVelocityBodyT1(bodyId, n) =
2944 a_angularVelocityBodyT1B2(bodyId, n) + 0.5 * dt * a_angularAccelerationBody(bodyId, n);
2945 }
2946 transformToWorldFrame(&a_bodyQuaternionT1(bodyId, 0), &a_angularVelocityBodyT1(bodyId, 0),
2947 &a_angularVelocityT1(bodyId, 0));
2948}
2949
2957template <>
2958inline void RigidBodies<2>::predictRotation(const MInt /*bodyId*/) {
2959 std::cerr << "predictRotation: No implementation for 2D!" << std::endl;
2960}
2961
2967template <MInt nDim>
2969 TRACE();
2970
2971 const MFloat dt = m_timestep;
2972 if(m_translation) {
2973 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
2974 // Translational values
2975 for(MInt n = 0; n < nDim; n++) {
2976 // Correct acceleration
2977 a_bodyAcceleration(bodyId, n) =
2978 a_bodyForce(bodyId, n) / a_bodyMass(bodyId)
2979 + gravity[n] * (1.0 - 1.0 / a_bodyDensityRatio(bodyId)); // Subtract bouyancy force
2980
2981 // Correct velocities
2982 a_bodyVelocity(bodyId, n) = a_bodyVelocityOld(bodyId, n)
2983 + 0.5 * dt * (a_bodyAcceleration(bodyId, n) + a_bodyAccelerationOld(bodyId, n));
2984
2985 // Correct position
2986 a_bodyCenter(bodyId, n) =
2987 a_bodyCenterOld(bodyId, n) + dt * a_bodyVelocityOld(bodyId, n)
2988 + 0.25 * POW2(dt) * (a_bodyAcceleration(bodyId, n) + a_bodyAccelerationOld(bodyId, n));
2989 }
2990
2991 if(m_rotation) {
2992 correctRotation(bodyId);
2993 }
2994
2995 // Scalar values
2996 // Correct temperature
2997 a_bodyTemperature(bodyId) = F1B2
2998 * (a_bodyTemperature(bodyId) + a_bodyTemperatureOld(bodyId)
2999 + dt * a_bodyHeatFlux(bodyId) / (m_bodyHeatCapacity * a_bodyMass(bodyId)));
3000 }
3001
3002 } else {
3003 if(m_rotation) {
3004 for(MInt bodyId = 0; bodyId < m_noLocalBodies; bodyId++) {
3005 correctRotation(bodyId);
3006 }
3007 }
3008 }
3009}
3010
3021template <>
3022inline void RigidBodies<3>::correctRotation(const MInt bodyId) {
3023 const MFloat dt = m_timestep;
3024
3025 MFloat torqueBodyT1[nRot];
3026 // Transform torque to the body frame
3027 transformToBodyFrame(&a_bodyQuaternionT1(bodyId, 0), &a_torqueT1(bodyId, 0), torqueBodyT1);
3028
3029 // Calculate angular momentum in the body frame
3030 MFloat angularMomentumBody[nRot]{};
3031 for(MInt n = 0; n < nRot; n++) {
3032 angularMomentumBody[n] = a_bodyInertia(bodyId, n) * a_angularVelocityBodyT1(bodyId, n);
3033 }
3034
3035 // Calculate convective part of the angular acceleration
3036 MFloat convectiveTerm[nRot]{};
3037 maia::math::cross(&a_angularVelocityBodyT1(bodyId, 0), &angularMomentumBody[0], &convectiveTerm[0]);
3038
3039 // Calculate angular acceleration
3040 MFloat angularAccelerationBodyT1[nRot]{};
3041 for(MInt n = 0; n < nRot; n++) {
3042 angularAccelerationBodyT1[n] = 1 / a_bodyInertia(bodyId, n) * (torqueBodyT1[n] - convectiveTerm[n]);
3043 }
3044 transformToWorldFrame(&a_bodyQuaternionT1(bodyId, 0), angularAccelerationBodyT1, &a_angularAccelerationT1(bodyId, 0));
3045
3046 // Advance angular velocity from time t+1/2 to time t+3/4
3047 MFloat angularVelocityBodyT3B2[nRot]{};
3048 for(MInt n = 0; n < nRot; n++) {
3049 angularVelocityBodyT3B2[n] = a_angularVelocityBodyT1B2(bodyId, n) + dt * angularAccelerationBodyT1[n];
3050 }
3051
3052 // Advance bodyQuaternion from time t+1/2 to time t+3/2
3053 MFloat bodyQuaternionT3B2[nQuat]{};
3054 advanceQuaternion(&a_angularVelocityT1(bodyId, 0), dt, &a_bodyQuaternionT1B2(bodyId, 0), bodyQuaternionT3B2);
3055
3056 // Transform angular velocity to the world frame
3057 MFloat angularVelocityT3B2[nRot]{};
3058 transformToWorldFrame(bodyQuaternionT3B2, angularVelocityBodyT3B2, angularVelocityT3B2);
3059
3060 // Advance time step
3061 constexpr MLong size_rot = nRot * sizeof(MFloat);
3062 constexpr MLong size_quat = nQuat * sizeof(MFloat);
3063
3064 memcpy(&a_angularAccelerationBody(bodyId, 0), angularAccelerationBodyT1, size_rot);
3065 memcpy(&a_angularVelocityBodyT1B2(bodyId, 0), angularVelocityBodyT3B2, size_rot);
3066 memcpy(&a_angularVelocityT1B2(bodyId, 0), angularVelocityT3B2, size_rot);
3067 memcpy(&a_bodyQuaternionT1B2(bodyId, 0), bodyQuaternionT3B2, size_quat);
3068}
3069
3077template <>
3078inline void RigidBodies<2>::correctRotation(const MInt /*bodyId*/) {
3079 std::cerr << "correctRotation: No implementation for 2D!" << std::endl;
3080}
3081
3094template <MInt nDim>
3095inline void RigidBodies<nDim>::transformToWorldFrame(const MFloat* const bodyQuaternion,
3096 const MFloat* const vectorBody,
3097 MFloat* const vectorWorld) {
3098 const MFloat uv = std::inner_product(bodyQuaternion, &bodyQuaternion[3], vectorBody, 0.0);
3099 const MFloat uu = std::inner_product(bodyQuaternion, &bodyQuaternion[3], bodyQuaternion, 0.0);
3100 const MFloat ss = bodyQuaternion[3] * bodyQuaternion[3];
3101 MFloat ucv[nRot]{};
3102 IF_CONSTEXPR(nDim == 3) { maia::math::cross(bodyQuaternion, vectorBody, &ucv[0]); }
3103 else {
3104 return;
3105 }
3106 for(MInt n = 0; n < nRot; n++) {
3107 vectorWorld[n] = 2.0 * uv * bodyQuaternion[n] + (ss - uu) * vectorBody[n] + 2.0 * bodyQuaternion[3] * -(ucv[n]);
3108 }
3109}
3110
3123template <MInt nDim>
3124inline void RigidBodies<nDim>::transformToBodyFrame(const MFloat* const bodyQuaternion,
3125 const MFloat* const vectorWorld,
3126 MFloat* const vectorBody) {
3127 const MFloat uv = std::inner_product(bodyQuaternion, &bodyQuaternion[3], vectorWorld, 0.0);
3128 const MFloat uu = std::inner_product(bodyQuaternion, &bodyQuaternion[3], bodyQuaternion, 0.0);
3129 const MFloat ss = bodyQuaternion[3] * bodyQuaternion[3];
3130 MFloat ucv[nRot]{};
3131 IF_CONSTEXPR(nDim == 3) { maia::math::cross(bodyQuaternion, vectorWorld, &ucv[0]); }
3132 else {
3133 return;
3134 }
3135 for(MInt n = 0; n < nRot; n++) {
3136 vectorBody[n] = 2.0 * uv * bodyQuaternion[n] + (ss - uu) * vectorWorld[n] + 2.0 * bodyQuaternion[3] * ucv[n];
3137 }
3138}
3139
3153template <MInt nDim>
3154inline void RigidBodies<nDim>::transformToBodyFrame(const MFloat* const bodyQuaternion, MFloat* const vec) {
3155 const MFloat vectorWorld[3]{vec[0], vec[1], vec[2]};
3156 transformToBodyFrame(bodyQuaternion, vectorWorld, vec);
3157}
3158
3169template <MInt nDim>
3170inline void RigidBodies<nDim>::advanceQuaternion(const MFloat* const angularVelocity,
3171 const MFloat dt,
3172 const MFloat* const qIn,
3173 MFloat* const qOut) {
3174 const MFloat angularVelMag = sqrt(std::inner_product(angularVelocity, &angularVelocity[nRot], angularVelocity, 0.0));
3175
3176 MFloat qIncrement[4]{0.0, 0.0, 0.0, 1.0};
3177
3178 if(angularVelMag > 0.0) {
3179 const MFloat angle = 0.5 * angularVelMag * dt;
3180 const MFloat tmp = sin(angle) / angularVelMag;
3181 qIncrement[0] = tmp * angularVelocity[0];
3182 qIncrement[1] = tmp * angularVelocity[1];
3183 qIncrement[2] = tmp * angularVelocity[2];
3184 qIncrement[3] = cos(angle);
3185 }
3186
3187 maia::math::quatMult(qIncrement, qIn, qOut);
3188}
3189
3198template <MInt nDim>
3199void RigidBodies<nDim>::quaternionToEuler(const MFloat* const quaternion, MFloat* const angles) {
3200 TRACE();
3201 const MFloat& x = quaternion[0];
3202 const MFloat& y = quaternion[1];
3203 const MFloat& z = quaternion[2];
3204 const MFloat& w = quaternion[3];
3205
3206 MFloat& roll = angles[0];
3207 MFloat& pitch = angles[1];
3208 MFloat& yaw = angles[2];
3209
3210 // roll (x-axis rotation)
3211 MFloat sinr_cosp = 2 * (w * x + y * z);
3212 MFloat cosr_cosp = 1 - 2 * (x * x + y * y);
3213 roll = std::atan2(sinr_cosp, cosr_cosp);
3214
3215 // pitch (y-axis rotation)
3216 MFloat sinp = 2 * (w * y - z * x);
3217 if(std::abs(sinp) >= 1) {
3218 pitch = std::copysign(M_PI / 2, sinp); // use 90 degrees if out of range
3219 } else {
3220 pitch = std::asin(sinp);
3221 }
3222
3223 // yaw (z-axis rotation)
3224 MFloat siny_cosp = 2 * (w * z + x * y);
3225 MFloat cosy_cosp = 1 - 2 * (y * y + z * z);
3226 yaw = std::atan2(siny_cosp, cosy_cosp);
3227}
3228
3239template <MInt nDim>
3240void RigidBodies<nDim>::computeBodyPropertiesForced(MInt returnMode, MFloat* bodyData, MInt bodyId, MFloat time) {
3241 TRACE();
3242
3243 MFloat elapsedTime = time;
3244 MFloat angle = F0;
3245 MBool& first = m_static_computeBodyProperties_first;
3246 MFloat*& amplitude = m_static_computeBodyProperties_amplitude;
3247 MFloat*& freqFactor = m_static_computeBodyProperties_freqFactor;
3248 MFloat*& initialBodyCenter = m_static_computeBodyProperties_initialBodyCenter;
3249 MFloat*& Strouhal = m_static_computeBodyProperties_Strouhal;
3250 MFloat*& mu2 = m_static_computeBodyProperties_mu2;
3251 MFloat*& liftStartAngle1 = m_static_computeBodyProperties_liftStartAngle1;
3252 MFloat*& liftEndAngle1 = m_static_computeBodyProperties_liftEndAngle1;
3253 MFloat*& liftStartAngle2 = m_static_computeBodyProperties_liftStartAngle2;
3254 MFloat*& liftEndAngle2 = m_static_computeBodyProperties_liftEndAngle2;
3255 MFloat*& circleStartAngle = m_static_computeBodyProperties_circleStartAngle;
3256 MFloat*& normal = m_static_computeBodyProperties_normal;
3257 MInt*& bodyToFunction = m_static_computeBodyProperties_bodyToFunction;
3258 MFloat*& rotAngle = m_static_computeBodyProperties_rotAngle;
3259
3260
3261 // Could be moved to readProperties ... ~jv
3262 if(first) {
3263 // Allocate memory for body movement function data
3264 mAlloc(m_static_computeBodyProperties_amplitude, noEmbeddedBodies(), "m_static_computeBodyProperties_amplitude",
3265 AT_);
3266 m_static_computeBodyProperties_amplitude[0] = F0;
3267 mAlloc(m_static_computeBodyProperties_freqFactor, noEmbeddedBodies(), "m_static_computeBodyProperties_freqFactor",
3268 AT_);
3269 mAlloc(m_static_computeBodyProperties_initialBodyCenter,
3270 noEmbeddedBodies() * nDim,
3271 "m_static_computeBodyProperties_initialBodyCenter",
3272 AT_);
3273 mAlloc(m_static_computeBodyProperties_Strouhal, noEmbeddedBodies(), "m_static_computeBodyProperties_Strouhal", AT_);
3274 mAlloc(m_static_computeBodyProperties_mu2, noEmbeddedBodies(), "m_static_computeBodyProperties_mu2", AT_);
3275 mAlloc(m_static_computeBodyProperties_liftStartAngle1,
3276 noEmbeddedBodies(),
3277 "m_static_computeBodyProperties_liftStartAngle1",
3278 AT_);
3279 mAlloc(m_static_computeBodyProperties_liftEndAngle1, noEmbeddedBodies(),
3280 "m_static_computeBodyProperties_liftEndAngle1", AT_);
3281 mAlloc(m_static_computeBodyProperties_liftStartAngle2,
3282 noEmbeddedBodies(),
3283 "m_static_computeBodyProperties_liftStartAngle2",
3284 AT_);
3285 mAlloc(m_static_computeBodyProperties_liftEndAngle2, noEmbeddedBodies(),
3286 "m_static_computeBodyProperties_liftEndAngle2", AT_);
3287 mAlloc(m_static_computeBodyProperties_circleStartAngle,
3288 noEmbeddedBodies(),
3289 "m_static_computeBodyProperties_circleStartAngle",
3290 AT_);
3291 mAlloc(m_static_computeBodyProperties_normal, noEmbeddedBodies() * nDim, "m_static_computeBodyProperties_normal",
3292 AT_);
3293 mAlloc(m_static_computeBodyProperties_bodyToFunction,
3294 noEmbeddedBodies(),
3295 "m_static_computeBodyProperties_bodyToFunction",
3296 AT_);
3297 mAlloc(m_static_computeBodyProperties_rotAngle, noEmbeddedBodies(), "m_static_computeBodyProperties_rotAngle", AT_);
3298
3299 // 1: set default values:
3300 for(MInt k = 0; k < noEmbeddedBodies(); k++) {
3301 Strouhal[k] = 0.2;
3302 amplitude[k] = 1.0;
3303 freqFactor[k] = 1.0;
3304 bodyToFunction[k] = 0;
3305 for(MInt i = 0; i < nDim; i++) {
3306 initialBodyCenter[k * nDim + i] = F0;
3307 normal[k * nDim + i] = F0;
3308 }
3309 normal[k * nDim + 0] = 1.0;
3310 liftStartAngle1[k] = F0;
3311 liftEndAngle1[k] = PI;
3312 liftStartAngle2[k] = 3.0 * PI;
3313 liftEndAngle2[k] = 4.0 * PI;
3314 circleStartAngle[k] = F0;
3315 }
3316
3317 // 2: read Properties
3318
3331 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3332 amplitude[i] = Context::getSolverProperty<MFloat>("amplitudes", m_solverId, AT_, &amplitude[i], i);
3333 }
3346 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3347 freqFactor[i] = Context::getSolverProperty<MFloat>("freqFactors", m_solverId, AT_, &freqFactor[i], i);
3348 }
3349
3362 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3363 bodyToFunction[i] =
3364 Context::getSolverProperty<MInt>("bodyMovementFunctions", m_solverId, AT_, &bodyToFunction[i], i);
3365 }
3366
3367 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3368 Strouhal[i] = Context::getSolverProperty<MFloat>("Strouhal", m_solverId, AT_, &Strouhal[i], i);
3369 }
3370
3382 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3383 for(MInt j = 0; j < nDim; j++) {
3384 initialBodyCenter[i * nDim + j] = Context::getSolverProperty<MFloat>(
3385 "initialBodyCenters", m_solverId, AT_, &initialBodyCenter[i * nDim + j], i * nDim + j);
3386 }
3387 }
3388
3389 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3390 for(MInt j = 0; j < nDim; j++) {
3391 normal[i * nDim + j] = Context::getSolverProperty<MFloat>("bodyMotionNormals", m_solverId, AT_,
3392 &normal[i * nDim + j], i * nDim + j);
3393 }
3394 }
3395
3409 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3410 liftStartAngle1[i] =
3411 Context::getSolverProperty<MFloat>("liftStartAngles1", m_solverId, AT_, &liftStartAngle1[i], i);
3412 }
3413
3426 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3427 liftStartAngle2[i] =
3428 Context::getSolverProperty<MFloat>("liftStartAngles2", m_solverId, AT_, &liftStartAngle2[i], i);
3429 }
3430
3441 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3442 liftEndAngle1[i] = Context::getSolverProperty<MFloat>("liftEndAngles1", m_solverId, AT_, &liftEndAngle1[i], i);
3443 }
3444
3455 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3456 liftEndAngle2[i] = Context::getSolverProperty<MFloat>("liftEndAngles2", m_solverId, AT_, &liftEndAngle2[i], i);
3457 }
3458
3470 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3471 circleStartAngle[i] =
3472 Context::getSolverProperty<MFloat>("circleStartAngles", m_solverId, AT_, &circleStartAngle[i], i);
3473 }
3474
3485 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3486 rotAngle[i] = Context::getSolverProperty<MFloat>("rotAngle", m_solverId, AT_, &rotAngle[i], i);
3487 rotAngle[i] *= -PI / 180;
3488 }
3489
3490 // 3: compute relevant values:
3491 for(MInt k = 0; k < noEmbeddedBodies(); k++) {
3492 // when using mu : has a dimension!
3493 // when using mu2 : dimensionless!
3494 mu2[k] = freqFactor[k] * Strouhal[k] * F2 * PI;
3495 }
3496
3497 // if bodyMovementFunction is 6 or 7, adjust start and end angles:
3498 for(MInt i = 0; i < noEmbeddedBodies(); i++) {
3499 if(bodyToFunction[i] == 6 || bodyToFunction[i] == 7 || bodyToFunction[i] == 9) {
3500 liftStartAngle1[i] = liftStartAngle1[i] * 2 * PI;
3501 liftEndAngle1[i] = liftEndAngle1[i] * 2 * PI;
3502 }
3503 }
3504
3505 first = false;
3506 }
3507
3508
3509 //--------------------------------
3510
3511 switch(bodyToFunction[bodyId]) {
3512 case 0:
3513 // Dummy movement function
3514 for(MInt n = 0; n < nDim; n++) {
3515 bodyData[n] = F0;
3516 }
3517 break;
3518
3519 case 8:
3520 // translational movement in normal-direction with constant velocity
3521 switch(returnMode) {
3522 case 1: // return body center
3523 for(MInt n = 0; n < nDim; n++) {
3524 bodyData[n] = amplitude[bodyId] * elapsedTime * normal[bodyId * nDim + n];
3525 }
3526 break;
3527 case 2: // return body velocity
3528 for(MInt n = 0; n < nDim; n++) {
3529 bodyData[n] = amplitude[bodyId] * normal[bodyId * nDim + n];
3530 }
3531 break;
3532 case 3: // return body acceleration
3533 for(MInt n = 0; n < nDim; n++) {
3534 bodyData[n] = F0;
3535 }
3536 break;
3537
3538 default:
3539 for(MInt n = 0; n < nDim; n++) {
3540 bodyData[n] = F0;
3541 }
3542 break;
3543 }
3544 break;
3545
3546 case 9: // sine function with normal (=> periodic motion around the initialBodyCenter!)
3547 angle = mu2[bodyId] * elapsedTime; // F1B2;
3548 switch(returnMode) {
3549 case 1: // return body center
3550 if(angle >= liftStartAngle1[bodyId] && angle <= liftEndAngle1[bodyId]) {
3551 for(MInt n = 0; n < nDim; n++) {
3552 bodyData[n] = amplitude[bodyId] / mu2[bodyId] * sin(angle) * normal[bodyId * nDim + n];
3553 }
3554 } else if(angle < liftStartAngle1[bodyId]) {
3555 for(MInt n = 0; n < nDim; n++) {
3556 bodyData[n] = 0;
3557 }
3558 } else if(angle > liftEndAngle1[bodyId]) {
3559 for(MInt n = 0; n < nDim; n++) {
3560 bodyData[n] = amplitude[bodyId] / mu2[bodyId] * sin(liftEndAngle1[bodyId]) * normal[bodyId * nDim + n];
3561 }
3562 }
3563 break;
3564 case 2: // return body velocity
3565 if(angle > liftStartAngle1[bodyId] && angle <= liftEndAngle1[bodyId]) {
3566 for(MInt n = 0; n < nDim; n++) {
3567 bodyData[n] = amplitude[bodyId] * cos(angle) * normal[bodyId * nDim + n];
3568 }
3569 } else {
3570 for(MInt n = 0; n < nDim; n++) {
3571 bodyData[n] = 0;
3572 }
3573 }
3574 break;
3575 case 3: // return body acceleration
3576 if(angle > liftStartAngle1[bodyId] && angle <= liftEndAngle1[bodyId]) {
3577 for(MInt n = 0; n < nDim; n++) {
3578 bodyData[n] = -amplitude[bodyId] * mu2[bodyId] * sin(angle) * normal[bodyId * nDim + n];
3579 }
3580 } else {
3581 for(MInt n = 0; n < nDim; n++) {
3582 bodyData[n] = 0;
3583 }
3584 }
3585 break;
3586 default:
3587 for(MInt n = 0; n < nDim; n++) {
3588 bodyData[n] = F0;
3589 }
3590 break;
3591 }
3592 break;
3593
3594 default:
3595 mTerm(1, AT_, "function type not implemented. Please check bodyMovementFunctions property!");
3596 }
3597
3598 // add the initialBodyCenter to the bodyData for the body position:
3599 if(returnMode == 1) {
3600 for(MInt dir = 0; dir < nDim; dir++) {
3601 bodyData[dir] += initialBodyCenter[bodyId * nDim + dir];
3602 }
3603 }
3604
3605 // rotate the final result around the z-axis
3606 if(rotAngle[bodyId] > 0 || rotAngle[bodyId] < 0) {
3607 MFloat tmp0 = bodyData[0] * cos(rotAngle[bodyId]) + bodyData[1] * sin(rotAngle[bodyId]);
3608 MFloat tmp1 = bodyData[1] * cos(rotAngle[bodyId]) - bodyData[0] * sin(rotAngle[bodyId]);
3609 bodyData[0] = tmp0;
3610 bodyData[1] = tmp1;
3611 bodyData[2] = bodyData[2];
3612 }
3613}
3614
3615
3626template <MInt nDim>
3627MFloat RigidBodies<nDim>::getDistanceSphere(const MFloat* const coordinates, const MInt bodyId) {
3628 TRACE();
3629 MFloat dist = .0;
3630 for(MInt n = 0; n < nDim; n++) {
3631 dist += POW2(coordinates[n] - a_bodyCenter(bodyId, n));
3632 }
3633
3634 dist = sqrt(dist) - a_bodyRadius(bodyId);
3635
3636 return dist;
3637}
3638
3649template <MInt nDim>
3650MFloat RigidBodies<nDim>::getDistancePiston(const MFloat* const coordinates, const MInt bodyId) {
3651 TRACE();
3652 const MFloat x = coordinates[0] - a_bodyCenter(bodyId, 0);
3653 const MFloat y = coordinates[1] - a_bodyCenter(bodyId, 1);
3654 const MFloat z = coordinates[2] - a_bodyCenter(bodyId, 2);
3655
3656 MFloat dist_cylinder = sqrt(POW2(x) + POW2(z)) - a_bodyRadius(bodyId);
3657 MFloat dist_caps = -y - m_bodyHeight / 2;
3658
3659 return std::max(dist_cylinder, dist_caps);
3660}
3661
3672template <MInt nDim>
3673MFloat RigidBodies<nDim>::getDistanceCube(const MFloat* const coordinates, const MInt bodyId) {
3674 TRACE();
3675 const MFloat x = coordinates[0] - a_bodyCenter(bodyId, 0);
3676 const MFloat y = coordinates[1] - a_bodyCenter(bodyId, 1);
3677
3678 const MFloat lim_x = std::max(x, -x);
3679 const MFloat lim_y = std::max(y, -y);
3680
3681 MFloat dist = std::max(lim_x, lim_y);
3682
3683 IF_CONSTEXPR(nDim == 3) {
3684 const MFloat z = coordinates[2] - a_bodyCenter(bodyId, 2);
3685 const MFloat lim_z = std::max(z, -z);
3686 dist = std::max(dist, lim_z);
3687 }
3688
3689 return dist - a_bodyRadius(bodyId);
3690}
3691
3702template <MInt nDim>
3703MFloat RigidBodies<nDim>::getDistanceEllipsoid(const MFloat* const coordinates, const MInt bodyId) {
3704 TRACE();
3705 MFloat relPos[nDim]{};
3706 for(MInt n = 0; n < nDim; n++) {
3707 relPos[n] = coordinates[n] - a_bodyCenter(bodyId, n);
3708 }
3709
3710 const MFloat* const bodyQuaternion = &a_bodyQuaternionT1(bodyId, 0);
3711 transformToBodyFrame(bodyQuaternion, relPos);
3712
3713 MFloat dist = findClosestPointEllipsoid(&relPos[0], bodyId);
3714
3715 return dist;
3716}
3717
3730template <>
3731MFloat RigidBodies<2>::findClosestPointEllipsoid(const MFloat* const /*relPos*/, const MInt /*bodyId*/) {
3732 std::cerr << "Find Ellipse closest point 2D needs to be implemented! " << std::endl;
3733 return 0.0;
3734}
3735
3748template <>
3750 TRACE();
3751 std::ignore = bodyId;
3752 MFloat e[3] = {a_bodyRadii(bodyId, 0), a_bodyRadii(bodyId, 1), a_bodyRadii(bodyId, 2)};
3753 MFloat y[3] = {relPos[0], relPos[1], relPos[2]};
3754 MFloat x[3]{};
3755
3756 // Determine reflections for y to the first octant.
3757 bool reflect[3];
3758 int i;
3759 int j;
3760 for(i = 0; i < 3; ++i) {
3761 reflect[i] = (y[i] < .0);
3762 }
3763
3764 // Determine the axis order for decreasing extents.
3765 int permute[3];
3766 if(e[0] < e[1]) {
3767 if(e[2] < e[0]) {
3768 permute[0] = 1;
3769 permute[1] = 0;
3770 permute[2] = 2;
3771 } else if(e[2] < e[1]) {
3772 permute[0] = 1;
3773 permute[1] = 2;
3774 permute[2] = 0;
3775 } else {
3776 permute[0] = 2;
3777 permute[1] = 1;
3778 permute[2] = 0;
3779 }
3780 } else {
3781 if(e[2] < e[1]) {
3782 permute[0] = 0;
3783 permute[1] = 1;
3784 permute[2] = 2;
3785 } else if(e[2] < e[0]) {
3786 permute[0] = 0;
3787 permute[1] = 2;
3788 permute[2] = 1;
3789 } else {
3790 permute[0] = 2;
3791 permute[1] = 0;
3792 permute[2] = 1;
3793 }
3794 }
3795
3796 std::array<MInt, 3> invpermute{};
3797 for(i = 0; i < 3; ++i) {
3798 invpermute[permute[i]] = i;
3799 }
3800
3801 std::array<MFloat, 3> locE{};
3802 std::array<MFloat, 3> locY{};
3803 for(i = 0; i < 3; ++i) {
3804 j = permute[i];
3805 locE[i] = e[j];
3806 locY[i] = y[j];
3807 if(reflect[j]) {
3808 locY[i] = -locY[i];
3809 }
3810 }
3811
3812 std::array<MFloat, 3> locX{};
3813 for(i = 0; i < 3; ++i) {
3814 ASSERT(!(locY[i] < F0), "");
3815 locY[i] = mMax(MFloatEps, locY[i]); // guarantee non-zero entries
3816 }
3817 MFloat distance = distancePointEllipsoid(locE, locY, locX);
3818
3819 // Restore the axis order and reflections.
3820 for(i = 0; i < 3; ++i) {
3821 j = invpermute[i];
3822 if(reflect[i]) {
3823 locX[j] = -locX[j];
3824 }
3825 x[i] = locX[j];
3826 }
3827
3828 std::ignore = x;
3829
3830 if((POW2(y[0] / e[0]) + POW2(y[1] / e[1]) + POW2(y[2] / e[2])) < F1) {
3831 distance = -distance;
3832 }
3833
3834 return distance;
3835}
3836
3850template <MInt nDim>
3851inline MFloat RigidBodies<nDim>::distancePointEllipsoid(const std::array<MFloat, 3> e, const std::array<MFloat, 3> y,
3852 std::array<MFloat, 3> x) {
3853 constexpr MFloat eps0 = 1e-12;
3854 constexpr MFloat eps1 = 1e-6;
3855 const MFloat dist0 = c_cellLengthAtMaxLevel();
3856 const MFloat dist1 = 10.0 * dist0;
3857 MFloat distance;
3858 // Bisect to compute the root of F(t) for t >= -e2*e2.
3859 MFloat esqr[3] = {e[0] * e[0], e[1] * e[1], e[2] * e[2]};
3860 MFloat ey[3] = {e[0] * y[0], e[1] * y[1], e[2] * y[2]};
3861 MFloat r[3];
3862 MFloat t0 = -esqr[2] + ey[2];
3863 MFloat t1 = -esqr[2] + sqrt(ey[0] * ey[0] + ey[1] * ey[1] + ey[2] * ey[2]);
3864 MFloat t = t0;
3865 const int imax = 2 * std::numeric_limits<MFloat>::max_exponent;
3866 MFloat eps = eps1;
3867 if(fabs(t1 - t0) < eps) t1 = t0 + F2 * eps;
3868 MInt i = 0;
3869 distance = 1.0;
3870 while(fabs(t1 - t0) > eps && i < imax) {
3871 while(fabs(t1 - t0) > eps && i < imax) {
3872 i++;
3873 t = F1B2 * (t0 + t1);
3874 r[0] = ey[0] / (t + esqr[0]);
3875 r[1] = ey[1] / (t + esqr[1]);
3876 r[2] = ey[2] / (t + esqr[2]);
3877 MFloat f = r[0] * r[0] + r[1] * r[1] + r[2] * r[2] - F1;
3878 // f==0 also means convergence, intentionally?
3879 if(f >= F0) {
3880 t0 = t;
3881 }
3882 if(f <= F0) {
3883 t1 = t;
3884 }
3885 }
3886 x[0] = esqr[0] * y[0] / (t + esqr[0]);
3887 x[1] = esqr[1] * y[1] / (t + esqr[1]);
3888 x[2] = esqr[2] * y[2] / (t + esqr[2]);
3889 distance = sqrt(POW2(x[0] - y[0]) + POW2(x[1] - y[1]) + POW2(x[2] - y[2]));
3890 // adjust eps: small close to surface, larger further away from surface
3891 eps = eps0 + mMin(F1, mMax(F0, (distance - dist0) / (dist1 - dist0))) * (eps1 - eps0);
3892 }
3893
3894 if(fabs(t0 - t1) > eps) {
3895 std::cerr << std::setprecision(16) << "ellipsoid dist not converged! " << i << " " << t1 - t0 << std::endl;
3896 }
3897
3898 return distance;
3899}
3900
3913template <MInt nDim>
3914void RigidBodies<nDim>::writeRestartFile(const MBool writeRestart, const MBool writeBackup, const MString ,
3915 MInt* /*recaldIdTree*/) {
3916 TRACE();
3917 if(writeRestart || globalTimeStep % restartInterval() == 0) {
3918 saveBodyRestartFile(writeBackup);
3919 }
3920}
3921
3929template <MInt nDim>
3931 TRACE();
3932
3933 using namespace maia::parallel_io;
3934
3935 const MLong noLocal = m_noLocalBodies;
3936 const MLong noGlobal = noEmbeddedBodies();
3937
3938 // Find order in which the data will be written
3939 // Sorting by containing partition cell ensures consistency between runs with different partitioning
3940 std::vector<MInt> localPartitionCellOfBody(noLocal, -1);
3941 for(MUint i = 0; i < noLocal; i++) {
3942 localPartitionCellOfBody[i] = grid().raw().findContainingPartitionCell(&a_bodyCenter(i, 0), -1, nullptr);
3943 }
3944 std::vector<int> indices(noLocal);
3945 // Init unity index mapping
3946 std::iota(indices.begin(), indices.end(), 0);
3947 // Sort indices based on the local partition cell index
3948 std::sort(indices.begin(), indices.end(),
3949 [&](int a, int b) -> bool { return localPartitionCellOfBody[a] < localPartitionCellOfBody[b]; });
3950
3951 if(domainId() == 0) {
3952 std::cerr << "writing body-restart-data ... (rigid bodies) ";
3953 }
3954
3955 static constexpr MLong DOF_SCALAR = 1;
3956 static constexpr MLong DOF_TRANS = nDim;
3957 static constexpr MLong DOF_ROT = nRot;
3958 static constexpr MLong DOF_QUAT = nDim + 1;
3959
3960 const MLong offset = getDomainOffset();
3961
3962 std::cout << "Domain " << domainId() << " has " << noLocal << " and offset " << offset << std::endl;
3963
3964 std::stringstream fileNameStream;
3965 fileNameStream << outputDir() << "restartBodyData_" << globalTimeStep;
3966 fileNameStream << ParallelIo::fileExt();
3967
3968 const MString fileName = fileNameStream.str();
3969
3970 ParallelIo parallelIo(fileName, PIO_REPLACE, mpiComm());
3971
3972 // Creating file header.
3973 parallelIo.defineScalar(PIO_INT, "noBodies");
3974
3975 // Define scalars
3976 parallelIo.defineArray(PIO_FLOAT, "bodyTemperature", noGlobal * DOF_SCALAR);
3977
3978 // Define vectors
3979 parallelIo.defineArray(PIO_FLOAT, "bodyCenter", noGlobal * DOF_TRANS);
3980 parallelIo.defineArray(PIO_FLOAT, "bodyVelocity", noGlobal * DOF_TRANS);
3981 parallelIo.defineArray(PIO_FLOAT, "bodyAcceleration", noGlobal * DOF_TRANS);
3982
3983 // Define rotational vectors
3984 parallelIo.defineArray(PIO_FLOAT, "angularVelocityBodyT1B2", noGlobal * DOF_ROT);
3985 parallelIo.defineArray(PIO_FLOAT, "angularAccelerationBody", noGlobal * DOF_ROT);
3986
3987 // Define rotational bodyQuaternion
3988 parallelIo.defineArray(PIO_FLOAT, "bodyQuaternionT1B2", noGlobal * DOF_QUAT);
3989 parallelIo.defineArray(PIO_FLOAT, "bodyQuaternionT1", noGlobal * DOF_QUAT);
3990
3991 // Write data
3992 parallelIo.writeScalar(noEmbeddedBodies(), "noBodies");
3993
3994 // Scalar
3995 parallelIo.setOffset(noLocal * DOF_SCALAR, offset * DOF_SCALAR);
3996 {
3997 MFloatScratchSpace bufTemperature(noLocal * DOF_SCALAR, AT_, "writeBuffer");
3998 for(MInt i = 0; i < noLocal; i++) {
3999 bufTemperature[i] = a_bodyTemperature(indices[i]);
4000 }
4001 parallelIo.writeArray(bufTemperature.data(), "bodyTemperature");
4002 }
4003
4004 // Translation
4005 parallelIo.setOffset(noLocal * DOF_TRANS, offset * DOF_TRANS);
4006 {
4007 MFloatScratchSpace writeBuffer(noLocal * DOF_TRANS, AT_, "writeBuffer");
4008 for(MInt i = 0; i < noLocal; i++) {
4009 for(MInt n = 0; n < DOF_TRANS; n++) {
4010 writeBuffer[i * DOF_TRANS + n] = a_bodyCenter(indices[i], n);
4011 }
4012 }
4013 parallelIo.writeArray(writeBuffer.data(), "bodyCenter");
4014 }
4015 {
4016 MFloatScratchSpace writeBuffer(noLocal * DOF_TRANS, AT_, "writeBuffer");
4017 for(MInt i = 0; i < noLocal; i++) {
4018 for(MInt n = 0; n < DOF_TRANS; n++) {
4019 writeBuffer[i * DOF_TRANS + n] = a_bodyVelocity(indices[i], n);
4020 }
4021 }
4022 parallelIo.writeArray(writeBuffer.data(), "bodyVelocity");
4023 }
4024 {
4025 MFloatScratchSpace writeBuffer(noLocal * DOF_TRANS, AT_, "writeBuffer");
4026 for(MInt i = 0; i < noLocal; i++) {
4027 for(MInt n = 0; n < DOF_TRANS; n++) {
4028 writeBuffer[i * DOF_TRANS + n] = a_bodyAcceleration(indices[i], n);
4029 }
4030 }
4031 parallelIo.writeArray(writeBuffer.data(), "bodyAcceleration");
4032 }
4033
4034 // Rotation (vector)
4035 parallelIo.setOffset(noLocal * DOF_ROT, offset * DOF_ROT);
4036 {
4037 MFloatScratchSpace writeBuffer(noLocal * DOF_ROT, AT_, "writeBuffer");
4038 for(MInt i = 0; i < noLocal; i++) {
4039 for(MInt n = 0; n < DOF_ROT; n++) {
4040 writeBuffer[i * DOF_ROT + n] = a_angularVelocityBodyT1B2(indices[i], n);
4041 }
4042 }
4043 parallelIo.writeArray(writeBuffer.data(), "angularVelocityBodyT1B2");
4044 }
4045 {
4046 MFloatScratchSpace writeBuffer(noLocal * DOF_ROT, AT_, "writeBuffer");
4047 for(MInt i = 0; i < noLocal; i++) {
4048 for(MInt n = 0; n < DOF_ROT; n++) {
4049 writeBuffer[i * DOF_ROT + n] = a_angularAccelerationBody(indices[i], n);
4050 }
4051 }
4052 parallelIo.writeArray(writeBuffer.data(), "angularAccelerationBody");
4053 }
4054
4055 // Rotation (quaternions)
4056 parallelIo.setOffset(noLocal * DOF_QUAT, offset * DOF_QUAT);
4057 {
4058 MFloatScratchSpace writeBuffer(noLocal * DOF_QUAT, AT_, "writeBuffer");
4059 for(MInt i = 0; i < noLocal; i++) {
4060 for(MInt n = 0; n < DOF_QUAT; n++) {
4061 writeBuffer[i * DOF_QUAT + n] = a_bodyQuaternionT1B2(indices[i], n);
4062 }
4063 }
4064 parallelIo.writeArray(writeBuffer.data(), "bodyQuaternionT1B2");
4065 }
4066 {
4067 MFloatScratchSpace writeBuffer(noLocal * DOF_QUAT, AT_, "writeBuffer");
4068 for(MInt i = 0; i < noLocal; i++) {
4069 for(MInt n = 0; n < DOF_QUAT; n++) {
4070 writeBuffer[i * DOF_QUAT + n] = a_bodyQuaternionT1(indices[i], n);
4071 }
4072 }
4073 parallelIo.writeArray(writeBuffer.data(), "bodyQuaternionT1");
4074 }
4075
4076 if(domainId() == 0) {
4077 std::cerr << "ok" << std::endl;
4078 }
4079}
4080
4087template <MInt nDim>
4089 TRACE();
4090
4091 using namespace maia::parallel_io;
4092
4093 std::stringstream fileNameStream;
4094 fileNameStream.clear();
4095
4096 fileNameStream << m_restartDir << "restartBodyData_" << m_restartTimeStep;
4097 fileNameStream << ParallelIo::fileExt();
4098
4099 const MString fileName = fileNameStream.str();
4100
4101 if(domainId() == 0) {
4102 std::cerr << "loading noBodies and positions " << fileNameStream.str() << " at " << globalTimeStep << "...";
4103 }
4104
4105 ParallelIo parallelIo(fileName, PIO_READ, mpiComm());
4106
4107 parallelIo.setOffset(1, 0);
4108 parallelIo.readScalar(&m_noEmbeddedBodies, "noBodies");
4109 m_maxNoBodies = m_noEmbeddedBodies;
4110
4111 m_bResFile.reset(noEmbeddedBodies());
4112 m_bResFile.append(noEmbeddedBodies());
4113 parallelIo.setOffset(noEmbeddedBodies() * nDim, 0);
4114 parallelIo.readArray(&m_bResFile.bodyCenter(0, 0), "bodyCenter");
4115
4116 if(domainId() == 0) {
4117 std::cerr << "reading noBodies and initial position from restart-file done" << std::endl;
4118 }
4119}
4120
4126template <MInt nDim>
4128 TRACE();
4129
4130 using namespace maia::parallel_io;
4131
4132 std::stringstream fileNameStream;
4133 fileNameStream.clear();
4134
4135 fileNameStream << m_restartDir << "restartBodyData_" << m_restartTimeStep;
4136 fileNameStream << ParallelIo::fileExt();
4137
4138 const MString fileName = fileNameStream.str();
4139
4140 const MLong DOF = noEmbeddedBodies();
4141 const MLong DOF_TRANS = DOF * nDim;
4142 const MLong DOF_ROT = DOF * nDim;
4143 const MLong DOF_QUAT = DOF * (nDim + 1);
4144
4145 if(domainId() == 0) {
4146 std::cerr << "loading body restart file " << fileNameStream.str() << " at " << globalTimeStep << "...";
4147 }
4148
4149 ParallelIo parallelIo(fileName, PIO_READ, mpiComm());
4150
4151 parallelIo.setOffset(DOF, 0);
4152 parallelIo.readArray(&m_bResFile.bodyTemperature(0), "bodyTemperature");
4153
4154 parallelIo.setOffset(DOF_TRANS, 0);
4155 parallelIo.readArray(&m_bResFile.bodyVelocity(0, 0), "bodyVelocity");
4156 parallelIo.readArray(&m_bResFile.bodyAcceleration(0, 0), "bodyAcceleration");
4157
4158 parallelIo.setOffset(DOF_ROT, 0);
4159 parallelIo.readArray(&m_bResFile.angularVelocityBodyT1B2(0, 0), "angularVelocityBodyT1B2");
4160 parallelIo.readArray(&m_bResFile.angularAccelerationBody(0, 0), "angularAccelerationBody");
4161
4162 parallelIo.setOffset(DOF_QUAT, 0);
4163 parallelIo.readArray(&m_bResFile.bodyQuaternionT1B2(0, 0), "bodyQuaternionT1B2");
4164 parallelIo.readArray(&m_bResFile.bodyQuaternionT1(0, 0), "bodyQuaternionT1");
4165
4166 if(domainId() == 0) {
4167 std::cerr << "reading bodyRestartFile done" << std::endl;
4168 }
4169}
4170
4176template <MInt nDim>
4178 TRACE();
4179 for(MInt bodyA = 0; bodyA < noConnectingBodies(); bodyA++) {
4180 // collide local with local Bodies
4181 for(MInt bodyB = 0; bodyB < noConnectingBodies(); bodyB++) {
4182 if(bodyA == bodyB) {
4183 continue;
4184 }
4185 collideSpheres(bodyA, bodyB);
4186 }
4187 }
4188}
4189
4198template <MInt nDim>
4199void RigidBodies<nDim>::collideSpheres(const MInt bodyA, const MInt bodyB) {
4200 TRACE();
4201 // TODO labels:toenhance support bodies with different radii
4202 const MFloat S = 2.0 * c_cellLengthAtMaxLevel();
4203 const MFloat D = a_bodyRadius(bodyA) + a_bodyRadius(bodyB);
4204 // const MFloat termv = m_uRef;
4205
4206 MFloat delta = 0.0;
4207 for(MInt n = 0; n < nDim; n++) {
4208 delta += POW2(a_bodyCenter(bodyA, n) - a_bodyCenter(bodyB, n));
4209 }
4210 delta = sqrt(delta);
4211
4212 const MFloat dist = delta - D;
4213
4214 if(dist > S) {
4215 return;
4216 }
4217
4218 if(dist < F0) {
4219 std::cerr << "\033[0;31m Warning:\033[0m potential overlap for bodies" << bodyA << " " << bodyB << std::endl;
4220 }
4221
4222 const MFloat M = F1B2 * (a_bodyDensityRatio(bodyA) * a_volume(bodyA) + a_bodyDensityRatio(bodyB) * a_volume(bodyB));
4223 const MFloat C0 = 8.0 * M * POW2(2.0) / c_cellLengthAtMaxLevel();
4224
4225#ifdef RB_DEBUG
4226 std::array<MFloat, nDim> debug{};
4227#endif
4228 for(MInt i = 0; i < nDim; i++) {
4229 const MFloat df = C0 * POW2(mMax(F0, -(dist - S) / S)) * (a_bodyCenter(bodyA, i) - a_bodyCenter(bodyB, i)) / dist;
4230#ifdef RB_DEBUG
4231 debug[i] = df;
4232#endif
4233 a_bodyForce(bodyA, i) += df;
4234 }
4235#ifdef RB_DEBUG
4236 if(dist > F0) {
4237 std::cerr << "Contact force applied " << debug[0] << " " << debug[1] << " " << dist << " " << S << std::endl;
4238 }
4239#endif
4240}
4241
4242// Explicit instatiation
4243template class RigidBodies<2>;
4244template class RigidBodies<3>;
void mAlloc(T *&a, const MLong N, const MString &objectName, MString function)
allocates memory for one-dimensional array 'a' of size N
Definition: alloc.h:173
static MInt propertyLength(const MString &name, MInt solverId=m_noSolvers)
Returns the number of elements of a property.
Definition: context.cpp:538
static MBool propertyExists(const MString &name, MInt solver=m_noSolvers)
This function checks if a property exists in general.
Definition: context.cpp:494
void open(const MString &filename, const MString &projectName, MInt fileType=0, MPI_Comm mpiComm=MPI_COMM_WORLD, MBool rootOnlyHardwired=false)
Opens a file by passing the parameters to InfoOut_<xyz>FileBuffer::open(...).
Definition: infoout.cpp:975
void close(MBool forceClose=false)
Pass the close call to the respective internal buffer.
Definition: infoout.cpp:1011
void transformToBodyFrame(const MFloat *const quaternion, const MFloat *const vectorWorld, MFloat *const vectorBody)
Transform a vector form the world frame to the body frame.
MFloat getDistancePiston(const MFloat *coordinates, const MInt bodyId)
Calculates the closest distance between a given point and a piston.
std::ofstream m_debugFileStream
Definition: rigidbodies.h:322
void initBodyLog()
Initalize log-file.
void exchangeBufferLengthsAllToAll(std::vector< MInt > &noToRecv, const MInt noToSend)
exchange of Buffer lengths all to all
void correctRotation(const MInt bodyId)
void exchangeNeighborConnectionInfo()
void preTimeStep() override
Resetting the 2-Step predictor-corrector cycle.
void correctorStep()
Correct the state of all bodies using external forces/fluxes/torques.
void checkDummyBodiesForSwap()
void loadBodyRestartFile()
Loads restart file for the RigidBodies solver.
MFloat getDistanceEllipsoid(const MFloat *coordinates, const MInt bodyId)
Calculates the closest distance between a given point and a ellipsoid.
RigidBodies(const MInt solverId, GridProxy &gridProxy, Geom &geometry, MPI_Comm comm)
C'tor for the RigidBodies solver.
Definition: rigidbodies.cpp:32
MBool solutionStep() override
void collideSpheres(const MInt bodyA, const MInt bodyB)
Calculate collision force between two spheres.
MFloat findClosestPointEllipsoid(const MFloat *const relPos, const MInt bodyId)
void initGridProperties()
void exchangeNeighborNeighborRemote(std::vector< std::vector< MInt > > &bodyIdsForRemoteDomain, std::vector< std::vector< MInt > > &homeDomainIdsForRemoteDomain, std::map< MInt, std::vector< MInt > > &tmpRemoteMap)
void exchangeBufferLengthsNeighbors(std::vector< MInt > &noToRecv, const MInt noToSend)
exchange of Buffer lengths all to all in direct neighborhood
void initTimers()
Definition: rigidbodies.cpp:88
void transformToWorldFrame(const MFloat *const quaternion, const MFloat *const vectorBody, MFloat *const vectorWorld)
Transform a vector form the body frame to the world frame.
typename maia::CartesianSolver< nDim, RigidBodies > CartesianSolver
Definition: rigidbodies.h:32
void deleteDummyBody(const MInt bodyId, const MInt collectorShift=0)
Delete dummy bodies from collector that are not relevant anymore.
void correctBodies()
Correcting the state of all bodies using all available external forces/fluxes.
void predictorStep()
Peform a prediction for all bodies.
void createDummyBody(MInt bodyId)
appends new DummyBody to collector
void loadBodiesSizeAndPosition()
loadind no of embedded bodies and it's position from restart file
void boxSeedInitialize()
MFloat calculatePeriodicShift(MInt intersectingCellId, MInt direction)
periodic shift for position for further data exchange
void printBodyDomainConnections()
debugging: print all necessary mappings for each partition in specific file
void readProperties()
Reading all necessary properties for the RigidBodies solver.
void deleteIrrelevantBodies(std::list< std::pair< MInt, MInt > > &removeList)
Delete remote bodies from collector that are not relevant anymore.
void collideBodies()
Calculate collisions forces for all bodies.
void saveBodyRestartFile(const MBool backup)
Write restart file for the RigidBody solver.
MFloat getDistanceCube(const MFloat *coordinates, const MInt bodyId)
Calculates the closest distance between a given point and a cube.
void exchangeBufferLengthsRemoteToHome(std::vector< MInt > &noToRecv, std::vector< MInt > &noToSend)
void exchangeFsiData()
exchange of summed forces and torques
void exchangeBufferLengthsNeighbor(std::vector< MInt > &noToRecv, std::vector< std::vector< MInt > > &bodyList)
exchange of Buffer legnths for further exchanges
void findLocalBodies()
searches in all initial Bodies for local bodies
void logBodyData()
Writing a simple log file containing the current state for all bodies.
void advanceBodies()
Copy the body data for time t to t-1 to prepare the next timestep.
void writeRestartFile(const MBool writeRestart, const MBool writeBackup, const MString, MInt *) override
Write restart file for the RigidBody solver.
~RigidBodies()
D'tor for the RigidBodies solver.
Definition: rigidbodies.cpp:68
MFloat getDistanceSphere(const MFloat *coordinates, const MInt bodyId)
Calculates the closest distance between a given point and a sphere.
void findTransferBodies()
creates list with all edge bodies that are no longer contained within local domain
void updateConnections()
MBool m_restart
Definition: rigidbodies.h:176
void initRemoteDummyBodyData(const MInt bodyId)
initalize kinematic data of dummyBody that is associated with a remoteBody
void exchangeNeighborNeighborHome(std::vector< std::vector< MInt > > &bodyIdsForHomeDomain, std::vector< std::vector< MInt > > &remoteDomainIdsForHomeDomain, std::vector< std::vector< std::array< MFloat, nDim > > > &shiftForHomeDomain)
void exchangeBodyVariablesAllToAll()
exchange of Body Variables all to all
void computeBodies()
Calculates the new state for all bodies.
void updateInfoDiameter(const MBool initCall=false)
MInt localToRemoteBody(const MInt collectorId, const MInt oldBodyId, const MInt domain)
this function transforms a localBody to a remoteBody on the current domain, necessary if a body cross...
void exchangeTransferBodies()
exchanges transfer bodies
void updateBodyDomainConnections(MBool initCall)
updates local/ edge body domain connections
MFloat distancePointEllipsoid(const std::array< MFloat, 3 > e, const std::array< MFloat, 3 > y, std::array< MFloat, 3 > x)
Calculates the closest distance between a given point and a ellipsoid in 3D.
MLong getDomainOffset()
for new restartFile format
void quaternionToEuler(const MFloat *const quaternion, MFloat *const angles)
Transform the quaternion to Euler angles.
void computeBodyPropertiesForced(MInt returnMode, MFloat *bodyData, MInt bodyId, MFloat time)
typename CartesianSolver::GridProxy GridProxy
Definition: rigidbodies.h:37
void advanceQuaternion(const MFloat *const angularVelocity, const MFloat dt, const MFloat *const qIn, MFloat *const qOut)
Advance the rotational state by one timestep for a given angular velocity.
void initBodyData()
Allocating and initializing body data necessary for the solver run.
void exchangeKinematicData()
exchange of predictor & corrector step output
void exchangeBufferLengthsAllToRoot(std::vector< MInt > &noToRecv, const MInt noToSend)
exchange of Buffer lengths all to root
void exchangeEdgeBodyData()
exchanges relevant body connections with new neighbor domains
void averageTimer()
void totalKineticEnergy()
std::array< MInt, Timers::_count > m_timers
Definition: rigidbodies.h:256
void predictRotation(const MInt bodyId)
void printScalingVariables()
This class is a ScratchSpace.
Definition: scratch.h:758
pointer data()
Definition: scratch.h:289
virtual MInt domainId() const
Return the domainId (rank)
Definition: solver.h:383
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
MBool fileExists(const MString &fileName)
Returns true if the file fileName exists, false otherwise.
Definition: functions.cpp:73
constexpr Real POW2(const Real x)
Definition: functions.h:119
constexpr T mMin(const T &x, const T &y)
Definition: functions.h:90
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
MInt globalTimeStep
InfoOutFile m_log
int32_t MInt
Definition: maiatypes.h:62
uint32_t MUint
Definition: maiatypes.h:63
std::basic_string< char > MString
Definition: maiatypes.h:55
double MFloat
Definition: maiatypes.h:52
int64_t MLong
Definition: maiatypes.h:64
bool MBool
Definition: maiatypes.h:58
int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Isend
int MPI_Allgatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgatherv
int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Irecv
int MPI_Wait(MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Wait
int MPI_Gatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Gatherv
int MPI_Waitall(int count, MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Waitall
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce
int MPI_Gather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Gather
T cos(const T a, const T b, const T x)
Cosine slope filter.
Definition: filter.h:125
void cross(const T *const u, const T *const v, T *const c)
Definition: maiamath.h:101
MInt sgn(T val)
Definition: maiamath.h:495
std::vector< MFloat > linSpace(const MFloat start, const MFloat end, const MInt num)
Definition: maiamath.h:903
void quatMult(const MFloat *const qA, const MFloat *const qB, MFloat *const qC)
Definition: maiamath.h:482
Namespace for auxiliary functions/classes.
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54
Definition: contexttypes.h:19
define array structures