MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
fcsolver.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 "fcsolver.h"
8
9#include <cstring>
10#include <functional>
11#include <random>
12#include <unordered_map>
13#include <utility>
14#include "COMM/mpioverride.h"
16#include "IO/parallelio.h"
17#include "UTIL/maiamath.h"
18#include "fcgridbndrycell.h"
19#include "globals.h"
20
21using namespace std;
22
23template <MInt nDim>
24FcSolver<nDim>::FcSolver(MInt id, GridProxy& gridProxy_, Geometry<nDim>& geometry_, const MPI_Comm comm)
25 : maia::CartesianSolver<nDim, FcSolver<nDim>>(id, gridProxy_, comm), m_geometry(&geometry_) {
26 TRACE();
27
28 initTimer();
29 RECORD_TIMER_START(m_t.solver);
30
31 m_geometryIntersection = new GeometryIntersection<nDim>(&grid(), m_geometry);
32
40 m_isThermal = false;
41 m_isThermal = Context::getSolverProperty<MBool>("isThermal", m_solverId, AT_, &m_isThermal);
42 m_cells.setThermal(m_isThermal);
43
51 m_polyDeg = 0;
52 m_polyDeg = Context::getSolverProperty<MInt>("polyDeg", m_solverId, AT_, &m_polyDeg);
53 m_cells.setMaxPRfnmnt(m_polyDeg);
54
62 m_testRun = false;
63 m_testRun = Context::getSolverProperty<MBool>("testRun", m_solverId, AT_, &m_testRun);
64
65 if(m_testRun) {
72 m_analyticSolution = F1;
73 m_analyticSolution = Context::getSolverProperty<MFloat>("analyticSolution", m_solverId, AT_, &m_analyticSolution);
74
81 m_printEigenValues = false;
82 m_printEigenValues = Context::getSolverProperty<MBool>("printEigenValues", m_solverId, AT_, &m_printEigenValues);
83 }
84
92 m_E = 100000.0;
93 m_E = Context::getSolverProperty<MFloat>("EModule", m_solverId, AT_, &m_E);
94
102 m_eps = 1e-12;
103 m_eps = Context::getSolverProperty<MFloat>("epsBiCG", m_solverId, AT_, &m_eps);
104
112 m_alpha = 1e-14;
113 m_alpha = Context::getSolverProperty<MFloat>("alpha", m_solverId, AT_, &m_alpha);
114
122 m_maxNoIterations = 10000;
123 m_maxNoIterations = Context::getSolverProperty<MInt>("noIterations", m_solverId, AT_, &m_maxNoIterations);
124
132 m_noLoadSteps = 1;
133 m_noLoadSteps = Context::getSolverProperty<MInt>("noLoadSteps", m_solverId, AT_, &m_noLoadSteps);
134
142 m_solveSoEIteratively = true;
143 m_solveSoEIteratively =
144 Context::getSolverProperty<MBool>("solveSoEIteratively", m_solverId, AT_, &m_solveSoEIteratively);
145
153 m_fcInterpolationMethod = "LAGRANGE_INTERP";
154 m_fcInterpolationMethod =
155 Context::getSolverProperty<MString>("fcInterpolationMethod", m_solverId, AT_, &m_fcInterpolationMethod);
156
157 // Instead of noCells() grid().tree().capacity() was used in m_cells.reset() before;
158 // it was changed because there was no difference at that time and to avoid direct access of the gird()
159 // m_cells.reset(grid().noCells());
160 m_cells.reset(grid().raw().treeb().capacity());
161 m_cells.append(grid().noCells());
162
163 // Update cell collector with information from grid
164 updateCellCollectorFromGrid();
165
166 setIntegrationWeights();
167
168 // TODO: Is this necessary
169 initJacobianMatrix();
170
171 // Find also the diagonal neighbors
172 grid().findEqualLevelNeighborsParDiagonal(false);
173
174 // Instantiation of bndrycnd
175 m_bndryCnd = new FcBndryCnd<nDim>(this);
176
177 deactivateCells();
178
179 // Allocate memory for the displacement vector
180 allocateNodeVectors();
181}
182
189template <MInt nDim>
191 TRACE();
192 mDeallocate(m_nodalDisplacements);
193 mDeallocate(m_totalNodalDisplacements);
194 mDeallocate(m_sysMatCompressed);
195 mDeallocate(m_compressionIndexSys);
196
197 mDeallocate(m_nodalLoadVector);
198 mDeallocate(m_externalLoadVector);
199 mDeallocate(m_internalLoadVector);
200 mDeallocate(m_reactionForceVector);
201
202 RECORD_TIMER_STOP(m_t.solver);
203
204 averageTimer();
205}
206
215template <MInt nDim>
217 TRACE();
218 // Store level information in cell collector for faster access:
219 // halo cells are stored,
220 // the poisson ratio is stored in case it differs from cell to cell,
221 // the p-Refinement per cell is stored,
222 // the number of points per cell is stored,
223 for(MInt i = 0; i < a_noCells(); i++) {
224 a_isHalo(i) = false;
225 a_isWindow(i) = false;
226 a_poissonRatio(i) = m_poissonRatio;
227 a_pRfnmnt(i) = m_polyDeg;
228 a_noNodes(i) = (a_pRfnmnt(i) + 2) * (a_pRfnmnt(i) + 2);
229 a_isActive(i) = true;
230 if(nDim == 3) a_noNodes(i) *= (a_pRfnmnt(i) + 2);
231
232 for(MInt strain = 0; strain < m_noStrains; strain++) {
233 a_elementStrains(i, strain) = F0;
234 }
235
236 for(MInt stress = 0; stress < m_noStrains; stress++) {
237 a_elementStresses(i, stress) = F0;
238 }
239
240 switch(string2enum(m_fcInterpolationMethod)) {
242 for(MInt deg = 0; deg < a_pRfnmnt(i) + 2; deg++) {
243 a_nodePosition(i, deg) = Fd::nodePosLobattoPoints(a_pRfnmnt(i), deg - 1);
244 }
245 break;
246 }
247 case LAGRANGE_INTERP: {
248 for(MInt deg = 0; deg < a_pRfnmnt(i) + 2; deg++) {
249 if(deg == 0) {
250 a_nodePosition(i, deg) = -F1;
251 } else if(deg < a_pRfnmnt(i) + 1) {
252 a_nodePosition(i, deg) = Fd::nodePosLobattoPoints(a_pRfnmnt(i), deg - 1);
253 } else {
254 a_nodePosition(i, deg) = F1;
255 }
256 }
257 break;
258 }
260 for(MInt deg = 0; deg < a_pRfnmnt(i) + 2; deg++) {
261 a_nodePosition(i, deg) = Fd::nodePosLobattoPoints(a_pRfnmnt(i), deg - 1);
262 }
263 break;
264 }
265 case LEGENDRE_INTERP: {
266 for(MInt deg = 0; deg < a_pRfnmnt(i) + 2; deg++) {
267 if(deg == 0) {
268 a_nodePosition(i, deg) = -F1;
269 } else if(deg < a_pRfnmnt(i) + 1) {
270 a_nodePosition(i, deg) = Fd::nodePosLobattoPoints(a_pRfnmnt(i), deg - 1);
271 } else {
272 a_nodePosition(i, deg) = F1;
273 }
274 }
275 break;
276 }
277 default: {
278 mTerm(1, AT_, "ERROR: Interpolation method unknown in FC solver!!!");
279 }
280 }
281 }
282
283 for(MInt i = 0; i < noNeighborDomains(); i++) {
284 for(MInt c = 0; c < noHaloCells(i); c++) {
285 a_isHalo(haloCell(i, c)) = true;
286 }
287 }
288 for(MInt i = 0; i < noNeighborDomains(); i++) {
289 for(MInt c = 0; c < noWindowCells(i); c++) {
290 a_isWindow(windowCell(i, c)) = true;
291 }
292 }
293}
294
302template <MInt nDim>
304 TRACE();
305
306 if(m_gaussPoints != nullptr) {
307 mDeallocate(m_gaussPoints);
308 }
309 if(m_gaussPoints != nullptr) {
310 mDeallocate(m_gaussWeights);
311 }
312 mAlloc(m_gaussPoints, m_polyDeg + 1, m_polyDeg + 2, "m_gaussPoints", F0, AT_);
313 mAlloc(m_gaussWeights, m_polyDeg + 1, m_polyDeg + 2, "m_gaussWeights", F0, AT_);
314
315 for(MInt p = 0; p < m_polyDeg + 1; p++) {
316 Fd::gaussPoint(p + 1, m_gaussPoints[p], m_gaussWeights[p]);
317 MInt halfLen = (m_polyDeg + 2 + 1) / 2;
318 for(MInt n = 0; n < halfLen; n++) {
319 MFloat saveP = m_gaussPoints[p][n];
320 MFloat saveW = m_gaussWeights[p][n];
321 m_gaussPoints[p][n] = m_gaussPoints[p][m_polyDeg + 1 - n];
322 m_gaussPoints[p][m_polyDeg + 1 - n] = saveP;
323 m_gaussWeights[p][n] = m_gaussWeights[p][m_polyDeg + 1 - n];
324 m_gaussWeights[p][m_polyDeg + 1 - n] = saveW;
325 }
326 }
327}
334template <MInt nDim>
336 // Store level information in cell collector for faster access:
337 // halo cells are stored,
338 // the poisson ratio is stored in case it differs from cell to cell,
339 // the p-Refinement per cell is stored,
340 // the number of points per cell is stored,
341 // the lobatto points and weights are stored (are these points necessary??)
342 for(MInt i = 0; i < a_noCells(); i++) {
343 if(!c_isLeafCell(i)) continue;
344 if(a_isBndryCell(i)) continue;
345
346 MFloat point[nDim] = {F0};
347 for(MInt d = 0; d < nDim; d++) {
348 point[d] = c_coordinate(i, d);
349 }
350 MBool outside = m_geometry->pointIsInside2(point);
351 a_isActive(i) = !outside;
352 }
353}
354
365template <MInt nDim>
367 TRACE();
368
369 m_log << "Initializing inverse Jacobian determinant... ";
370
371 for(MInt i = 0; i < a_noCells(); i++) {
372 a_invJacobian(i) = F2 / grid().cellLengthAtCell(i);
373 }
374
375 m_log << "done" << endl;
376}
377
384template <MInt nDim>
386 TRACE();
387
388 createElementToNodeMapping();
389
390 mAlloc(m_globalNodeIdOffsets, noDomains() + 1, "m_globalNodeIdOffsets", 0, AT_);
391
392 // TODO: Should be implemented in a more efficient way.
393 if(noDomains() > 1) {
394 // In case of local p-Refinement, exchange the number of nodes per cell first
395 this->exchangeData(&(a_noNodes(0)), 1);
396
397 for(MInt d = 0; d < noDomains(); d++) {
398 if(domainId() == d) {
399 createElementToNodeMappingGlobal();
400 }
401
402 exchangeNodeIds(d);
403
404 MPI_Allreduce(MPI_IN_PLACE, &m_totalNoNodesGlobal, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
405 "m_totalNoNodesGlobal");
406 m_globalNodeIdOffsets[d + 1] = m_totalNoNodesGlobal;
407 }
408
409 reorderLocalNodeIds();
410 } else {
411 createElementToNodeMappingGlobal();
412
413 m_globalNodeIdOffsets[1] = m_totalNoNodesGlobal;
414 }
415
416 m_noInternalNodes = m_globalNodeIdOffsets[domainId() + 1] - m_globalNodeIdOffsets[domainId()];
417
418 if(m_testRun) {
419 consistencyCheck();
420
421 if(noDomains() > 1) consistencyCheck2();
422 }
423
424 mAlloc(m_nodalDisplacements, m_totalNoNodes * nDim, "m_nodalDisplacements", F0, AT_);
425 mAlloc(m_totalNodalDisplacements, m_totalNoNodes * nDim, "m_totalNodalDisplacements", F0, AT_);
426
427 mAlloc(m_nodalLoadVector, m_totalNoNodes * nDim, "m_nodalLoadVector", F0, AT_);
428 mAlloc(m_externalLoadVector, m_totalNoNodes * nDim, "m_externalLoadVector", F0, AT_);
429 mAlloc(m_internalLoadVector, m_totalNoNodes * nDim, "m_internalLoadVector", F0, AT_);
430 mAlloc(m_reactionForceVector, m_totalNoNodes * nDim, "m_reactionForceVector", F0, AT_);
431 mAlloc(m_localToGlobalId, m_totalNoNodes, "m_localToGlobalId", -1, AT_);
432 mAlloc(m_globalToLocalId, m_totalNoNodesGlobal, "m_globalToLocalId", -1, AT_);
433
434 for(MInt cell = 0; cell < a_noCells(); cell++) {
435 if(!a_isActive(cell)) continue;
436 for(MInt node = 0; node < a_noNodes(cell); node++) {
437 MInt localNodeId = a_nodeIdsLocal(cell, node);
438 MInt globalNodeId = a_nodeIdsGlobal(cell, node);
439 if(m_localToGlobalId[localNodeId] == -1) {
440 m_localToGlobalId[localNodeId] = globalNodeId;
441 } else {
442 if(m_localToGlobalId[localNodeId] != globalNodeId) {
443 mTerm(1, AT_, "ERROR in local to global Mapping");
444 }
445 }
446 if(m_globalToLocalId[globalNodeId] == -1) {
447 m_globalToLocalId[globalNodeId] = localNodeId;
448 } else {
449 if(m_globalToLocalId[globalNodeId] != localNodeId) {
450 mTerm(1, AT_, "ERROR in global to local Mapping");
451 }
452 }
453 }
454 }
455}
456
457template <MInt nDim>
459 TRACE();
460
461 MInt noVertices = IPOW2(nDim);
462 MInt noEdges = (nDim == 2) ? 0 : 12;
463 MInt noSurfaces = 2 * nDim;
464
465 MInt counter = 0;
466 for(MInt cell = 0; cell < a_noCells(); cell++) {
467 if(!c_isLeafCell(cell)) continue;
468 if(!a_isActive(cell)) continue;
469 for(MInt node = 0; node < a_noNodes(cell); node++) {
470 if(a_nodeIdsGlobal(cell, node) >= m_globalNodeIdOffsets[domainId()]
471 && a_nodeIdsGlobal(cell, node) < m_globalNodeIdOffsets[domainId() + 1]) {
472 a_nodeIdsLocal(cell, node) = a_nodeIdsGlobal(cell, node) - m_globalNodeIdOffsets[domainId()];
473 } else {
474 a_nodeIdsLocal(cell, node) = -1;
475 }
476 }
477 }
478
479 for(MInt cell = 0; cell < a_noCells(); cell++) {
480 if(!c_isLeafCell(cell)) continue;
481 if(!a_isActive(cell)) continue;
482 for(MInt node = 0; node < a_noNodes(cell); node++) {
483 if(a_nodeIdsLocal(cell, node) == -1) {
484 a_nodeIdsLocal(cell, node) =
485 (m_globalNodeIdOffsets[domainId() + 1] - m_globalNodeIdOffsets[domainId()]) + counter;
486 counter++;
487 if(node < noVertices) {
488 for(MInt dir = 0; dir < noVertices - 1; dir++) {
489 if(c_neighborId(cell, Fd::nghbrCellOfVertex(node, dir)) < 0) continue;
490 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfVertex(node, dir));
491 if(a_nodeIdsLocal(nghbrId, Fd::vertexIdOfOppCell(node, dir)) > -1) {
492 cerr << a_nodeIdsLocal(nghbrId, Fd::vertexIdOfOppCell(node, dir)) << " OVERWRITTEN in REORDER" << endl;
493 } else {
494 a_nodeIdsLocal(nghbrId, Fd::vertexIdOfOppCell(node, dir)) = a_nodeIdsLocal(cell, node);
495 }
496 }
497 } else if(node < (noVertices + noEdges * a_pRfnmnt(cell))) {
498 MInt pos = node - noVertices;
499 MInt edge = 0;
500 for(MInt e = 0; e < noEdges; e++) {
501 if(e * a_pRfnmnt(cell) < pos) {
502 edge++;
503 } else {
504 edge--;
505 break;
506 }
507 }
508 MInt point = pos - (edge * a_pRfnmnt(cell));
509 pos = noVertices + (edge * a_pRfnmnt(cell));
510 for(MInt dir = 0; dir < 3; dir++) {
511 if(c_neighborId(cell, Fd::nghbrCellOfEdge(edge, dir)) < 0) continue;
512 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfEdge(edge, dir));
513 MInt oppositePos = noVertices + Fd::edgeIdOfOppCell(edge, dir) * a_pRfnmnt(cell);
514 if(a_nodeIdsLocal(nghbrId, oppositePos + point) > -1) {
515 cerr << a_nodeIdsLocal(nghbrId, oppositePos + point) << " OVERWRITTEN in REORDER" << endl;
516 } else {
517 a_nodeIdsLocal(nghbrId, oppositePos + point) = a_nodeIdsLocal(cell, pos + point);
518 }
519 }
520 } else if(node < (noVertices + noEdges * a_pRfnmnt(cell) + noSurfaces * a_pRfnmnt(cell) * a_pRfnmnt(cell))) {
521 MInt pos = node - noVertices + noEdges * a_pRfnmnt(cell);
522 MInt surface = 0;
523 for(MInt s = 0; s < noSurfaces; s++) {
524 if(s * a_pRfnmnt(cell) * a_pRfnmnt(cell) < pos) {
525 surface++;
526 } else {
527 surface--;
528 break;
529 }
530 }
531 MInt point = pos - (surface * a_pRfnmnt(cell) * a_pRfnmnt(cell));
532 pos = noVertices + (noEdges * a_pRfnmnt(cell)) + (surface * a_pRfnmnt(cell) * a_pRfnmnt(cell));
533 if(c_neighborId(cell, Fd::nghbrCellOfSurface(surface)) < 0) continue;
534 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfSurface(surface));
535 MInt oppositePos = noVertices + noEdges * a_pRfnmnt(cell)
536 + Fd::surfaceIdOfOppCell(surface) * a_pRfnmnt(cell) * a_pRfnmnt(cell);
537 if(a_nodeIdsLocal(nghbrId, oppositePos + point) > -1) {
538 cerr << a_nodeIdsLocal(nghbrId, oppositePos + point) << " OVERWRITTEN in REORDER" << endl;
539 } else {
540 a_nodeIdsLocal(nghbrId, oppositePos + point) = a_nodeIdsLocal(cell, pos + point);
541 }
542 }
543 }
544 }
545 }
546}
547
554template <MInt nDim>
555void FcSolver<nDim>::exchangeNodeIds(MInt currentDomain) {
556 TRACE();
557
558 MInt noVertices = IPOW2(nDim);
559 MInt noEdges = (nDim == 2) ? 0 : 12;
560 MInt noSurfaces = 2 * nDim;
561
562 // Create arrays for the data offsets and data count
563 MIntScratchSpace windowDataPerRank(noNeighborDomains(), "windowDataPerRank", AT_);
564 MIntScratchSpace haloDataPerRank(noNeighborDomains(), "haloDataPerRank", AT_);
565 MIntScratchSpace windowDataOffsets(noNeighborDomains() + 1, "windowDataOffsets", AT_);
566 MIntScratchSpace haloDataOffsets(noNeighborDomains() + 1, "haloDataOffsets", AT_);
567 windowDataPerRank.fill(0);
568 haloDataPerRank.fill(0);
569 windowDataOffsets.fill(0);
570 haloDataOffsets.fill(0);
571
572 // Determine the data count and the data offsets
573 MInt totalCounterWindow = 0;
574 MInt totalCounterHalo = 0;
575 for(MInt n = 0; n < noNeighborDomains(); n++) {
576 MInt dataCounterWindow = 0;
577 MInt dataCounterHalo = 0;
578 for(MInt w = 0; w < noWindowCells(n); w++) {
579 dataCounterWindow += a_noNodes(windowCell(n, w));
580 }
581 for(MInt h = 0; h < noHaloCells(n); h++) {
582 dataCounterHalo += a_noNodes(haloCell(n, h));
583 }
584 windowDataPerRank(n) = dataCounterWindow;
585 haloDataPerRank(n) = dataCounterHalo;
586 totalCounterWindow += dataCounterWindow;
587 totalCounterHalo += dataCounterHalo;
588 windowDataOffsets(n + 1) = totalCounterWindow;
589 haloDataOffsets(n + 1) = totalCounterHalo;
590 }
591
592 // Allocate the buffers
593 MInt* sendBuffers{};
594 MInt* receiveBuffers{};
595 MPI_Request* mpi_request{};
596 mAlloc(sendBuffers, totalCounterWindow, "sendBuffers", 0, AT_);
597 mAlloc(receiveBuffers, totalCounterHalo, "receiveBuffers", 0, AT_);
598 mAlloc(mpi_request, noNeighborDomains(), "mpi_request", AT_);
599
600 // Gather data
601 if(domainId() == currentDomain) {
602 for(MInt n = 0; n < noNeighborDomains(); n++) {
603 MInt cnt = 0;
604 for(MInt j = 0; j < noWindowCells(n); j++) {
605 for(MInt node = 0; node < a_noNodes(windowCell(n, j)); node++) {
606 sendBuffers[windowDataOffsets(n) + cnt] = a_nodeIdsGlobal(windowCell(n, j), node);
607 cnt++;
608 }
609 }
610 }
611
612 // Send data
613 for(MInt n = 0; n < noNeighborDomains(); n++) {
614 MPI_Issend(&sendBuffers[windowDataOffsets(n)], windowDataPerRank(n), MPI_INT, neighborDomain(n), 0, mpiComm(),
615 &mpi_request[n], AT_, "sendBuffers[n]");
616 }
617 }
618
619 // Receive data
620 MPI_Status status;
621 for(MInt n = 0; n < noNeighborDomains(); n++) {
622 if(currentDomain != neighborDomain(n)) continue;
623 MPI_Recv(&receiveBuffers[haloDataOffsets(n)], haloDataPerRank(n), MPI_INT, neighborDomain(n), 0, mpiComm(), &status,
624 AT_, "receiveBuffers[n]");
625 }
626 if(domainId() == currentDomain) {
627 for(MInt n = 0; n < noNeighborDomains(); n++) {
628 MPI_Wait(&mpi_request[n], &status, AT_);
629 }
630 }
631
632 // Scatter data
633 for(MInt n = 0; n < noNeighborDomains(); n++) {
634 if(currentDomain != neighborDomain(n)) continue;
635 MInt cnt = 0;
636 for(MInt j = 0; j < noHaloCells(n); j++) {
637 for(MInt node = 0; node < a_noNodes(haloCell(n, j)); node++) {
638 cnt++;
639 if(receiveBuffers[haloDataOffsets(n) + cnt - 1] == -1) continue;
640 if((a_nodeIdsGlobal(haloCell(n, j), node) > -1)) continue;
641 a_nodeIdsGlobal(haloCell(n, j), node) = receiveBuffers[haloDataOffsets(n) + cnt - 1];
642 // If the global nodeId is set in the halo, it should be set also in the neighboring cells sharing the node with
643 // the halo cell
644 if(node < noVertices) {
645 for(MInt dir = 0; dir < noVertices - 1; dir++) {
646 if(c_neighborId(haloCell(n, j), Fd::nghbrCellOfVertex(node, dir)) < 0) continue;
647 MInt nghbrId = c_neighborId(haloCell(n, j), Fd::nghbrCellOfVertex(node, dir));
648 if(a_nodeIdsGlobal(nghbrId, Fd::vertexIdOfOppCell(node, dir)) > -1) {
649 cerr << a_nodeIdsGlobal(nghbrId, Fd::vertexIdOfOppCell(node, dir)) << " OVERWRITTEN in EXCHANGE" << endl;
650 } else {
651 a_nodeIdsGlobal(nghbrId, Fd::vertexIdOfOppCell(node, dir)) = a_nodeIdsGlobal(haloCell(n, j), node);
652 }
653 }
654 } else if(node < (noVertices + noEdges * a_pRfnmnt(haloCell(n, j)))) {
655 MInt pos = node - noVertices;
656 MInt edge = 0;
657 for(MInt e = 0; e < noEdges; e++) {
658 if(e * a_pRfnmnt(haloCell(n, j)) < pos) {
659 edge++;
660 } else {
661 edge--;
662 break;
663 }
664 }
665 MInt point = pos - (edge * a_pRfnmnt(haloCell(n, j)));
666 pos = noVertices + (edge * a_pRfnmnt(haloCell(n, j)));
667 for(MInt dir = 0; dir < 3; dir++) {
668 if(c_neighborId(haloCell(n, j), Fd::nghbrCellOfEdge(edge, dir)) < 0) continue;
669 MInt nghbrId = c_neighborId(haloCell(n, j), Fd::nghbrCellOfEdge(edge, dir));
670 MInt oppositePos = noVertices + Fd::edgeIdOfOppCell(edge, dir) * a_pRfnmnt(haloCell(n, j));
671 if(a_nodeIdsGlobal(nghbrId, oppositePos + point) > -1) {
672 cerr << a_nodeIdsGlobal(nghbrId, oppositePos + point) << " OVERWRITTEN in EXCHANGE" << endl;
673 } else {
674 a_nodeIdsGlobal(nghbrId, oppositePos + point) = a_nodeIdsGlobal(haloCell(n, j), pos + point);
675 }
676 }
677 } else if(node < (noVertices + noEdges * a_pRfnmnt(haloCell(n, j))
678 + noSurfaces * a_pRfnmnt(haloCell(n, j)) * a_pRfnmnt(haloCell(n, j)))) {
679 MInt pos = node - noVertices + noEdges * a_pRfnmnt(haloCell(n, j));
680 MInt surface = 0;
681 for(MInt s = 0; s < noSurfaces; s++) {
682 if(s * a_pRfnmnt(haloCell(n, j)) * a_pRfnmnt(haloCell(n, j)) < pos) {
683 surface++;
684 } else {
685 surface--;
686 break;
687 }
688 }
689 MInt point = pos - (surface * a_pRfnmnt(haloCell(n, j)) * a_pRfnmnt(haloCell(n, j)));
690 pos = noVertices + (noEdges * a_pRfnmnt(haloCell(n, j)))
691 + (surface * a_pRfnmnt(haloCell(n, j)) * a_pRfnmnt(haloCell(n, j)));
692 if(c_neighborId(haloCell(n, j), Fd::nghbrCellOfSurface(surface)) < 0) continue;
693 MInt nghbrId = c_neighborId(haloCell(n, j), Fd::nghbrCellOfSurface(surface));
694 MInt oppositePos = noVertices + noEdges * a_pRfnmnt(haloCell(n, j))
695 + Fd::surfaceIdOfOppCell(surface) * a_pRfnmnt(haloCell(n, j)) * a_pRfnmnt(haloCell(n, j));
696 if(a_nodeIdsGlobal(nghbrId, oppositePos + point) > -1) {
697 cerr << a_nodeIdsGlobal(nghbrId, oppositePos + point) << " OVERWRITTEN in EXCHANGE" << endl;
698 } else {
699 a_nodeIdsGlobal(nghbrId, oppositePos + point) = a_nodeIdsGlobal(haloCell(n, j), pos + point);
700 }
701 }
702 }
703 }
704 }
705
706 mDeallocate(sendBuffers);
707 mDeallocate(receiveBuffers);
708 mDeallocate(mpi_request);
709}
710
719template <MInt nDim>
721 TRACE();
722
723 // Set nodes:
724 // Firstly, set the nodes vertex wise
725 // Secondly, set the nodes edge wise
726 // Thirdly, set the nodes surface wise
727 // Finally, set the inner nodes which have no neighbor
728 MInt noVertices = IPOW2(nDim);
729 MInt noEdges = (nDim == 2) ? 0 : 12;
730 MInt noSurfaces = 2 * nDim;
731
732 for(MInt cell = 0; cell < a_noCells(); cell++) {
733 if(!c_isLeafCell(cell)) continue;
734 if(!a_isActive(cell)) continue;
735 // Check the node ids for the vertex nodes
736 for(MInt vertex = 0; vertex < noVertices; vertex++) {
737 if(a_nodeIdsGlobal(cell, vertex) == -1) {
738 MInt globalId = -1;
739 MInt noDiffCandidates = 0;
740 for(MInt dir = 0; dir < noVertices - 1; dir++) {
741 if(c_neighborId(cell, Fd::nghbrCellOfVertex(vertex, dir)) < 0) continue;
742 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfVertex(vertex, dir));
743 if(a_nodeIdsGlobal(nghbrId, Fd::vertexIdOfOppCell(vertex, dir)) > -1) {
744 if(globalId != a_nodeIdsGlobal(nghbrId, Fd::vertexIdOfOppCell(vertex, dir))) {
745 noDiffCandidates++;
746 }
747 }
748 }
749 if(noDiffCandidates == 1) {
750 a_nodeIdsGlobal(cell, vertex) = globalId;
751 }
752 } else {
753 MInt id = a_nodeIdsGlobal(cell, vertex);
754 for(MInt dir = 0; dir < noVertices - 1; dir++) {
755 if(c_neighborId(cell, Fd::nghbrCellOfVertex(vertex, dir)) < 0) continue;
756 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfVertex(vertex, dir));
757 if(a_nodeIdsGlobal(nghbrId, Fd::vertexIdOfOppCell(vertex, dir)) != id) {
758 stringstream errorMessage;
759 errorMessage << "INCONSISTENCY IN GLOBAL NODE ID FOR GLOBAL CELL ID " << c_globalId(cell) << endl;
760 mTerm(1, AT_, errorMessage.str());
761 }
762 }
763 }
764 }
765 // Check the node ids for the edge nodes
766 for(MInt edge = 0; edge < noEdges; edge++) {
767 MInt pos = noVertices + edge * a_pRfnmnt(cell);
768 for(MInt points = 0; points < a_pRfnmnt(cell); points++) {
769 if(a_nodeIdsGlobal(cell, pos + points) == -1) {
770 MInt globalId = -1;
771 MInt noDiffCandidates = 0;
772 for(MInt dir = 0; dir < 3; dir++) {
773 if(c_neighborId(cell, Fd::nghbrCellOfEdge(edge, dir)) < 0) continue;
774 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfEdge(edge, dir));
775 MInt oppositePos = noVertices + Fd::edgeIdOfOppCell(edge, dir) * a_pRfnmnt(cell);
776 if(a_nodeIdsGlobal(nghbrId, oppositePos + points) > -1) {
777 if(globalId != a_nodeIdsGlobal(nghbrId, oppositePos + points)) {
778 noDiffCandidates++;
779 }
780 }
781 }
782 if(noDiffCandidates == 1) {
783 a_nodeIdsGlobal(cell, pos + points) = globalId;
784 }
785 } else {
786 MInt id = a_nodeIdsGlobal(cell, pos + points);
787 for(MInt dir = 0; dir < 3; dir++) {
788 if(c_neighborId(cell, Fd::nghbrCellOfEdge(edge, dir)) < 0) continue;
789 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfEdge(edge, dir));
790 MInt oppositePos = noVertices + Fd::edgeIdOfOppCell(edge, dir) * a_pRfnmnt(cell);
791 if(a_nodeIdsGlobal(nghbrId, oppositePos + points) != id) {
792 stringstream errorMessage;
793 errorMessage << "INCONSISTENCY IN GLOBAL NODE ID FOR GLOBAL CELL ID " << c_globalId(cell) << endl;
794 mTerm(1, AT_, errorMessage.str());
795 }
796 }
797 }
798 }
799 }
800 // Check the node ids for the surfaces
801 for(MInt surface = 0; surface < noSurfaces; surface++) {
802 MInt pos = noVertices + noEdges * a_pRfnmnt(cell) + surface * a_pRfnmnt(cell) * a_pRfnmnt(cell);
803 for(MInt points = 0; points < a_pRfnmnt(cell) * a_pRfnmnt(cell); points++) {
804 if(a_nodeIdsGlobal(cell, pos + points) == -1) {
805 MInt globalId = -1;
806 if(c_neighborId(cell, Fd::nghbrCellOfSurface(surface)) < 0) continue;
807 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfSurface(surface));
808 MInt oppositePos = noVertices + noEdges * a_pRfnmnt(cell)
809 + Fd::surfaceIdOfOppCell(surface) * a_pRfnmnt(cell) * a_pRfnmnt(cell);
810 if(globalId != a_nodeIdsGlobal(nghbrId, oppositePos + points)) {
811 a_nodeIdsGlobal(cell, pos + points) = globalId;
812 }
813 } else {
814 MInt id = a_nodeIdsGlobal(cell, pos + points);
815 if(c_neighborId(cell, Fd::nghbrCellOfSurface(surface)) < 0) continue;
816 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfSurface(surface));
817 MInt oppositePos = noVertices + noEdges * a_pRfnmnt(cell)
818 + Fd::surfaceIdOfOppCell(surface) * a_pRfnmnt(cell) * a_pRfnmnt(cell);
819 if(a_nodeIdsGlobal(nghbrId, oppositePos + points) != id) {
820 stringstream errorMessage;
821 errorMessage << "INCONSISTENCY IN GLOBAL NODE ID FOR GLOBAL CELL ID " << c_globalId(cell) << endl;
822 mTerm(1, AT_, errorMessage.str());
823 }
824 }
825 }
826 }
827 }
828}
829
838template <MInt nDim>
840 TRACE();
841
842 // Create arrays for the data offsets and data count
843 MIntScratchSpace windowDataPerRank(noNeighborDomains(), "windowDataPerRank", AT_);
844 MIntScratchSpace haloDataPerRank(noNeighborDomains(), "haloDataPerRank", AT_);
845 MIntScratchSpace windowDataOffsets(noNeighborDomains() + 1, "windowDataOffsets", AT_);
846 MIntScratchSpace haloDataOffsets(noNeighborDomains() + 1, "haloDataOffsets", AT_);
847 windowDataPerRank.fill(0);
848 haloDataPerRank.fill(0);
849 windowDataOffsets.fill(0);
850 haloDataOffsets.fill(0);
851
852 // Determine the data count and the data offsets
853 MInt totalCounterWindow = 0;
854 MInt totalCounterHalo = 0;
855 for(MInt n = 0; n < noNeighborDomains(); n++) {
856 MInt dataCounterWindow = 0;
857 MInt dataCounterHalo = 0;
858 for(MInt w = 0; w < noWindowCells(n); w++) {
859 dataCounterWindow += a_noNodes(windowCell(n, w));
860 }
861 for(MInt h = 0; h < noHaloCells(n); h++) {
862 dataCounterHalo += a_noNodes(haloCell(n, h));
863 }
864 windowDataPerRank(n) = dataCounterWindow;
865 haloDataPerRank(n) = dataCounterHalo;
866 totalCounterWindow += dataCounterWindow;
867 totalCounterHalo += dataCounterHalo;
868 windowDataOffsets(n + 1) = totalCounterWindow;
869 haloDataOffsets(n + 1) = totalCounterHalo;
870 }
871
872 // Allocate the buffers
873 MInt* sendBuffers{};
874 MInt* receiveBuffers{};
875 MPI_Request* mpi_request{};
876 mAlloc(sendBuffers, totalCounterWindow, "sendBuffers", 0, AT_);
877 mAlloc(receiveBuffers, totalCounterHalo, "receiveBuffers", 0, AT_);
878 mAlloc(mpi_request, noNeighborDomains(), "mpi_request", AT_);
879
880 // Gather data
881 for(MInt n = 0; n < noNeighborDomains(); n++) {
882 MInt cnt = 0;
883 for(MInt j = 0; j < noWindowCells(n); j++) {
884 for(MInt node = 0; node < a_noNodes(windowCell(n, j)); node++) {
885 sendBuffers[windowDataOffsets(n) + cnt] = a_nodeIdsGlobal(windowCell(n, j), node);
886 cnt++;
887 }
888 }
889 }
890
891 // Send data
892 for(MInt n = 0; n < noNeighborDomains(); n++) {
893 MPI_Issend(&sendBuffers[windowDataOffsets(n)], windowDataPerRank(n), MPI_INT, neighborDomain(n), 0, mpiComm(),
894 &mpi_request[n], AT_, "sendBuffers[n]");
895 }
896
897 // Receive data
898 MPI_Status status;
899 for(MInt n = 0; n < noNeighborDomains(); n++) {
900 MPI_Recv(&receiveBuffers[haloDataOffsets(n)], haloDataPerRank(n), MPI_INT, neighborDomain(n), 0, mpiComm(), &status,
901 AT_, "receiveBuffers[n]");
902 }
903 for(MInt n = 0; n < noNeighborDomains(); n++) {
904 MPI_Wait(&mpi_request[n], &status, AT_);
905 }
906
907 // Scatter data and compare it to the data of the halo cell
908 for(MInt n = 0; n < noNeighborDomains(); n++) {
909 MInt cnt = 0;
910 for(MInt j = 0; j < noHaloCells(n); j++) {
911 for(MInt node = 0; node < a_noNodes(haloCell(n, j)); node++) {
912 cnt++;
913 if(a_nodeIdsGlobal(haloCell(n, j), node) != receiveBuffers[haloDataOffsets(n) + cnt - 1]) {
914 stringstream errorMessage;
915 errorMessage << "INCONSISTENCY IN GLOBAL NODE ID FOR GLOBAL CELL ID " << c_globalId(haloCell(n, j)) << endl;
916 mTerm(1, AT_, errorMessage.str());
917 }
918 }
919 }
920 }
921
922 mDeallocate(sendBuffers);
923 mDeallocate(receiveBuffers);
924 mDeallocate(mpi_request);
925}
926
927
936template <MInt nDim>
938 TRACE();
939
940 // Set nodes:
941 // Firstly, set the nodes vertex wise
942 // Secondly, set the nodes edge wise
943 // Thirdly, set the nodes surface wise
944 // Finally, set the inner nodes which have no neighbor
945 MInt noVertices = IPOW2(nDim);
946 MInt noEdges = (nDim == 2) ? 0 : 12;
947 MInt noSurfaces = 2 * nDim;
948
949 for(MInt cell = 0; cell < a_noCells(); cell++) {
950 if(a_isHalo(cell)) continue;
951 if(!c_isLeafCell(cell)) continue;
952 if(!a_isActive(cell)) continue;
953 // Set the node ids for the vertex nodes
954 for(MInt vertex = 0; vertex < noVertices; vertex++) {
955 if(a_nodeIdsGlobal(cell, vertex) == -1) {
956 a_nodeIdsGlobal(cell, vertex) = m_totalNoNodesGlobal;
957 m_totalNoNodesGlobal++;
958 // Check the neighbors and set the node ids there
959 for(MInt dir = 0; dir < noVertices - 1; dir++) {
960 if(c_neighborId(cell, Fd::nghbrCellOfVertex(vertex, dir)) < 0) continue;
961 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfVertex(vertex, dir));
962 a_nodeIdsGlobal(nghbrId, Fd::vertexIdOfOppCell(vertex, dir)) = a_nodeIdsGlobal(cell, vertex);
963 }
964 }
965 }
966 // Set the node ids for the edge nodes
967 for(MInt edge = 0; edge < noEdges; edge++) {
968 MInt pos = noVertices + edge * a_pRfnmnt(cell);
969 for(MInt points = 0; points < a_pRfnmnt(cell); points++) {
970 if(a_nodeIdsGlobal(cell, pos + points) == -1) {
971 a_nodeIdsGlobal(cell, pos + points) = m_totalNoNodesGlobal;
972 m_totalNoNodesGlobal++;
973 }
974 }
975 // Check the neighbors and set the node ids there
976 for(MInt dir = 0; dir < 3; dir++) {
977 if(c_neighborId(cell, Fd::nghbrCellOfEdge(edge, dir)) < 0) continue;
978 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfEdge(edge, dir));
979 MInt oppositePos = noVertices + Fd::edgeIdOfOppCell(edge, dir) * a_pRfnmnt(cell);
980 for(MInt points = 0; points < a_pRfnmnt(cell); points++) {
981 a_nodeIdsGlobal(nghbrId, oppositePos + points) = a_nodeIdsGlobal(cell, pos + points);
982 }
983 }
984 }
985 // Set the node ids for the surfaces
986 for(MInt surface = 0; surface < noSurfaces; surface++) {
987 MInt pos = noVertices + noEdges * a_pRfnmnt(cell) + surface * a_pRfnmnt(cell) * a_pRfnmnt(cell);
988 for(MInt points = 0; points < a_pRfnmnt(cell) * a_pRfnmnt(cell); points++) {
989 if(a_nodeIdsGlobal(cell, pos + points) == -1) {
990 a_nodeIdsGlobal(cell, pos + points) = m_totalNoNodesGlobal;
991 m_totalNoNodesGlobal++;
992 }
993 }
994 // Check the neighbors and set the node ids there
995 if(c_neighborId(cell, Fd::nghbrCellOfSurface(surface)) < 0) continue;
996 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfSurface(surface));
997 MInt oppositePos =
998 noVertices + noEdges * a_pRfnmnt(cell) + Fd::surfaceIdOfOppCell(surface) * a_pRfnmnt(cell) * a_pRfnmnt(cell);
999 for(MInt points = 0; points < a_pRfnmnt(cell) * a_pRfnmnt(cell); points++) {
1000 a_nodeIdsGlobal(nghbrId, oppositePos + points) = a_nodeIdsGlobal(cell, pos + points);
1001 }
1002 }
1003 // Set the node ids for all inner points
1004 MInt noInnerNodes = a_pRfnmnt(cell) * a_pRfnmnt(cell) * a_pRfnmnt(cell);
1005 for(MInt innerNodes = 0; innerNodes < noInnerNodes; innerNodes++) {
1006 MInt pos = noVertices + noEdges * a_pRfnmnt(cell) + noSurfaces * a_pRfnmnt(cell) * a_pRfnmnt(cell) + innerNodes;
1007 if(a_nodeIdsGlobal(cell, pos) == -1) {
1008 a_nodeIdsGlobal(cell, pos) = m_totalNoNodesGlobal;
1009 m_totalNoNodesGlobal++;
1010 }
1011 }
1012 }
1013}
1014
1024template <MInt nDim>
1026 TRACE();
1027
1028 m_totalNoNodes = 0;
1029
1030 // reset the node ids stored for each cell
1031 // TODO: At the moment the allocation is done
1032 // statically, but it should be dynamic to safe memory
1033 for(MInt cell = 0; cell < a_noCells(); cell++) {
1034 for(MInt node = 0; node < a_noNodes(cell); node++) {
1035 a_nodeIdsLocal(cell, node) = -1;
1036 a_nodeIdsGlobal(cell, node) = -1;
1037 }
1038 }
1039
1040 // Set nodes:
1041 // Firstly, set the nodes vertex wise
1042 // Secondly, set the nodes edge wise
1043 // Thirdly, set the nodes surface wise
1044 // Finally, set the inner nodes which have no neighbor
1045 MInt noVertices = IPOW2(nDim);
1046 MInt noEdges = (nDim == 2) ? 0 : 12;
1047 MInt noSurfaces = 2 * nDim;
1048 MInt innerCounter = 0;
1049 MInt surfaceCounter = 0;
1050 MInt edgeCounter = 0;
1051 MInt vertexCounter = 0;
1052
1053 for(MInt cell = 0; cell < a_noCells(); cell++) {
1054 if(!c_isLeafCell(cell)) continue;
1055 if(!a_isActive(cell)) continue;
1056 // Set the node ids for the vertex nodes
1057 for(MInt vertex = 0; vertex < noVertices; vertex++) {
1058 if(a_nodeIdsLocal(cell, vertex) == -1) {
1059 a_nodeIdsLocal(cell, vertex) = m_totalNoNodes;
1060 m_totalNoNodes++;
1061 vertexCounter++;
1062 // Check the neighbors and set the node ids there
1063 for(MInt dir = 0; dir < noVertices - 1; dir++) {
1064 if(c_neighborId(cell, Fd::nghbrCellOfVertex(vertex, dir)) < 0) continue;
1065 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfVertex(vertex, dir));
1066 a_nodeIdsLocal(nghbrId, Fd::vertexIdOfOppCell(vertex, dir)) = a_nodeIdsLocal(cell, vertex);
1067 }
1068 }
1069 }
1070 // Set the node ids for the edge nodes
1071 for(MInt edge = 0; edge < noEdges; edge++) {
1072 MInt pos = noVertices + edge * a_pRfnmnt(cell);
1073 for(MInt points = 0; points < a_pRfnmnt(cell); points++) {
1074 if(a_nodeIdsLocal(cell, pos + points) == -1) {
1075 a_nodeIdsLocal(cell, pos + points) = m_totalNoNodes;
1076 m_totalNoNodes++;
1077 edgeCounter++;
1078 }
1079 }
1080 // Check the neighbors and set the node ids there
1081 for(MInt dir = 0; dir < 3; dir++) {
1082 if(c_neighborId(cell, Fd::nghbrCellOfEdge(edge, dir)) < 0) continue;
1083 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfEdge(edge, dir));
1084 MInt oppositePos = noVertices + Fd::edgeIdOfOppCell(edge, dir) * a_pRfnmnt(cell);
1085 for(MInt points = 0; points < a_pRfnmnt(cell); points++) {
1086 a_nodeIdsLocal(nghbrId, oppositePos + points) = a_nodeIdsLocal(cell, pos + points);
1087 }
1088 }
1089 }
1090 // Set the node ids for the surfaces
1091 for(MInt surface = 0; surface < noSurfaces; surface++) {
1092 MInt pos = noVertices + noEdges * a_pRfnmnt(cell) + surface * a_pRfnmnt(cell) * a_pRfnmnt(cell);
1093 for(MInt points = 0; points < a_pRfnmnt(cell) * a_pRfnmnt(cell); points++) {
1094 if(a_nodeIdsLocal(cell, pos + points) == -1) {
1095 a_nodeIdsLocal(cell, pos + points) = m_totalNoNodes;
1096 m_totalNoNodes++;
1097 surfaceCounter++;
1098 }
1099 }
1100 // Check the neighbors and set the node ids there
1101 if(c_neighborId(cell, Fd::nghbrCellOfSurface(surface)) < 0) continue;
1102 MInt nghbrId = c_neighborId(cell, Fd::nghbrCellOfSurface(surface));
1103 MInt oppositePos =
1104 noVertices + noEdges * a_pRfnmnt(cell) + Fd::surfaceIdOfOppCell(surface) * a_pRfnmnt(cell) * a_pRfnmnt(cell);
1105 for(MInt points = 0; points < a_pRfnmnt(cell) * a_pRfnmnt(cell); points++) {
1106 a_nodeIdsLocal(nghbrId, oppositePos + points) = a_nodeIdsLocal(cell, pos + points);
1107 }
1108 }
1109 // Set the node ids for all inner points
1110 MInt noInnerNodes = a_pRfnmnt(cell) * a_pRfnmnt(cell) * a_pRfnmnt(cell);
1111 for(MInt innerNodes = 0; innerNodes < noInnerNodes; innerNodes++) {
1112 MInt pos = noVertices + noEdges * a_pRfnmnt(cell) + noSurfaces * a_pRfnmnt(cell) * a_pRfnmnt(cell) + innerNodes;
1113 if(a_nodeIdsLocal(cell, pos) == -1) {
1114 a_nodeIdsLocal(cell, pos) = m_totalNoNodes;
1115 m_totalNoNodes++;
1116 innerCounter++;
1117 }
1118 }
1119 }
1120
1121 cout << "Number of Nodes on cell vertices (no vertices per cell: " << noVertices << "): " << vertexCounter << endl;
1122 cout << "Number of Nodes on cell edges (no edges per cell: " << noEdges << ") : " << edgeCounter << endl;
1123 cout << "Number of Nodes on cell surfaces (no surfaces per cell: " << noSurfaces << "): " << surfaceCounter << endl;
1124 cout << "Number of Nodes within the cells : " << innerCounter << endl;
1125 cout << "Number of Nodes total : " << m_totalNoNodes << endl;
1126 cout << "Number of Cells total without halo cells (on domain " << domainId() << ") : " << grid().noInternalCells()
1127 << endl;
1128 cout << "Number of Cells total with halo cells (on domain " << domainId() << ") : " << a_noCells() << endl;
1129 cout << endl;
1130 m_log << "Number of Nodes on cell vertices (no vertices per cell: " << noVertices << "): " << vertexCounter << endl;
1131 m_log << "Number of Nodes on cell edges (no edges per cell: " << noEdges << ") : " << edgeCounter << endl;
1132 m_log << "Number of Nodes on cell surfaces (no surfaces per cell: " << noSurfaces << "): " << surfaceCounter << endl;
1133 m_log << "Number of Nodes within the cells : " << innerCounter << endl;
1134 m_log << "Number of Nodes total : " << m_totalNoNodes << endl;
1135 m_log << endl;
1136}
1137
1138
1146template <MInt nDim>
1147void FcSolver<nDim>::interpolateGeometry(const MInt pCellId, const MFloat* z, MFloat* x) {
1148 TRACE();
1149
1150 const MFloat cellHalfLength = c_cellLengthAtCell(pCellId) * F1B2;
1151
1152 for(MInt d = 0; d < nDim; d++) {
1153 x[d] = c_coordinate(pCellId, d) + z[d] * cellHalfLength;
1154 }
1155}
1156
1164template <MInt nDim>
1165void FcSolver<nDim>::interpolateSubCellGeometry(const MInt pCellId, const MFloat* z, MFloat* x, const MInt subCellLevel,
1166 const MFloat* subCellCoord) {
1167 TRACE();
1168
1169 const MFloat cellHalfLength = c_cellLengthAtCell(pCellId) * FFPOW2(subCellLevel + 1);
1170
1171 for(MInt d = 0; d < nDim; d++) {
1172 x[d] = subCellCoord[d] + z[d] * cellHalfLength;
1173 }
1174}
1175
1183template <MInt nDim>
1184void FcSolver<nDim>::transformToLocal(const MInt pCellId, const MFloat* x, MFloat* z) {
1185 TRACE();
1186
1187 const MFloat F1BcellHalfLength = F1 / (c_cellLengthAtCell(pCellId) * F1B2);
1188
1189 for(MInt d = 0; d < nDim; d++) {
1190 z[d] = (x[d] - c_coordinate(pCellId, d)) * F1BcellHalfLength;
1191 }
1192}
1193
1194
1203template <MInt nDim>
1205 TRACE();
1206
1207 for(MInt cell = 0; cell < a_noCells(); cell++) {
1208 const MInt pCellId = cell;
1209
1210 if(!a_isActive(pCellId)) {
1211 for(MInt d = 0; d < nDim; d++) {
1212 a_elementDispl(pCellId, d) = F0;
1213 }
1214 continue;
1215 }
1216
1217 std::array<MFloat, nDim> z{};
1218
1219 getDisplacementsAtPoint(pCellId, z.data(), m_totalNodalDisplacements, &a_elementDispl(pCellId, 0));
1220 }
1221}
1222
1223template <MInt nDim>
1224void FcSolver<nDim>::getDisplacementsAtPoint(const MInt cellId, const MFloat* z, const MFloat* displ, MFloat* result) {
1225 TRACE();
1226
1227 // Calculate the lagrangian polynome for calculating the
1228 // element displacement by interpolation of the nodal displacement
1229 MFloatScratchSpace L_coef(nDim, a_noNodes(cellId) * nDim, AT_, "L_coef");
1230
1231 L_coef.fill(F1);
1232 getDisplacementInterpolationMatrix(cellId, z, L_coef);
1233
1234 if(m_testRun && m_polyDeg < 1) getDisplacementInterpolationMatrixDebug(cellId, z, L_coef);
1235
1236 // Loop over all directions and all points to get the
1237 // displacement of the cell
1238 for(MInt dim = 0; dim < nDim; dim++) {
1239 MFloat displacement = F0;
1240 for(MInt node = 0; node < a_noNodes(cellId); node++) {
1241 for(MInt d = 0; d < nDim; d++) {
1242 MInt nodeId = a_nodeIdsLocal(cellId, node);
1243 displacement += L_coef(dim, node * nDim + d) * displ[nodeId * nDim + d];
1244 }
1245 }
1246 result[dim] = displacement;
1247 }
1248}
1249
1258template <MInt nDim>
1260 TRACE();
1261
1262 for(MInt cell = 0; cell < a_noCells(); cell++) {
1263 if(!a_isActive(cell)) continue;
1264
1265 // Calculate the strain interpolation matrix
1266 MFloat z[nDim] = {F0};
1267
1268 getStrainsAtPoint(cell, z, m_totalNodalDisplacements, &a_elementStrains(cell, 0));
1269 }
1270}
1271
1272template <MInt nDim>
1273void FcSolver<nDim>::getStrainsAtPoint(const MInt cellId, const MFloat* z, const MFloat* displ, MFloat* strains) {
1274 TRACE();
1275
1276 MFloatScratchSpace Be(m_noStrains, nDim * a_noNodes(cellId), AT_, "Be");
1277 getStrainInterpolationMatrix(Be, cellId, z);
1278
1279 // Calculate the strains from the matrix product Be * u
1280 // strain interpolation matrix times displacement
1281 for(MInt d1 = 0; d1 < m_noStrains; d1++) {
1282 MFloat strain = F0;
1283 for(MInt node = 0; node < a_noNodes(cellId); node++) {
1284 MInt nodeId = a_nodeIdsLocal(cellId, node);
1285 for(MInt d2 = 0; d2 < nDim; d2++) {
1286 strain += Be(d1, node * nDim + d2) * displ[nodeId * nDim + d2];
1287 }
1288 }
1289 strains[d1] = strain;
1290 }
1291}
1292
1301template <MInt nDim>
1303 TRACE();
1304
1305 for(MInt cell = 0; cell < a_noCells(); cell++) {
1306 if(!a_isActive(cell)) continue;
1307
1308 std::array<MFloat, nDim> z{};
1309 getStressesAtPoint(cell, z.data(), m_totalNodalDisplacements, &a_elementStresses(cell, 0));
1310 }
1311}
1312
1313template <MInt nDim>
1314void FcSolver<nDim>::getStressesAtPoint(const MInt cellId, const MFloat* z, const MFloat* displ, MFloat* stresses) {
1315 TRACE();
1316
1317 ASSERT(string2enum(solverMethod()) == MAIA_LINEAR_ELASTIC, "This function is not valid for plastic simulations.");
1318
1319 std::array<MFloat, m_noStrains> strains{};
1320 getStrainsAtPoint(cellId, z, displ, strains.data());
1321
1322 MFloatScratchSpace C(m_noStrains, m_noStrains, AT_, "C");
1323 getMaterialTensor(C, cellId);
1324 for(MInt d1 = 0; d1 < m_noStrains; d1++) {
1325 MFloat stress = F0;
1326 for(MInt d2 = 0; d2 < m_noStrains; d2++) {
1327 const MFloat strain = strains[d2];
1328 stress += C(d2, d1) * strain;
1329 }
1330 stresses[d1] = stress;
1331 }
1332}
1333
1346template <MInt nDim>
1348 MFloatScratchSpace& L_coef) {
1349 TRACE();
1350
1351 const MInt p = a_pRfnmnt(pCellId);
1352 MFloatScratchSpace L(nDim, p + 2, AT_, "L");
1353
1354 // initialize the arrays for the mapping
1355 MInt noVertices = IPOW2(nDim);
1356 MInt noEdges = (nDim == 2) ? 0 : 12;
1357 MInt noSurfaces = (nDim == 2) ? 4 : 6;
1358
1359 // initialize the L matrix with 1.0
1360 for(MInt d = 0; d < nDim; d++) {
1361 for(MInt i = 0; i < p + 2; i++) {
1362 L(d, i) = F1;
1363 }
1364 }
1365
1366 // calculate the lagrangian polynominal
1367 // see Lagrange polynominal
1368 // Maybe L can be stored once at the beginning
1369 for(MInt d = 0; d < nDim; d++) {
1370 for(MInt i = 0; i < p + 2; i++) {
1371 for(MInt j = 0; j < p + 2; j++) {
1372 if(i == j) continue;
1373 L(d, i) *= (z[d] - a_nodePosition(pCellId, j)) / (a_nodePosition(pCellId, i) - a_nodePosition(pCellId, j));
1374 }
1375 }
1376 }
1377
1378 // Now that all polynominals are calculated, the polynominals
1379 // for the different directions need to be multiplied for each node
1380 // First the values at the vertices, then at the edges, than at the
1381 // surfaces and finally at the inner points are determined
1382 for(MInt dim = 0; dim < nDim; dim++) {
1383 for(MInt node = 0; node < a_noNodes(pCellId); node++) {
1384 // vertices
1385 if(node < noVertices) {
1386 for(MInt d = 0; d < nDim; d++) {
1387 if(d == dim) {
1388 L_coef(dim, node * nDim + d) = F1;
1389 } else {
1390 L_coef(dim, node * nDim + d) = F0;
1391 }
1392 for(MInt d2 = 0; d2 < nDim; d2++) {
1393 MInt pos = -1;
1394 if(Fd::vertexPosition(node, d2) < F0) {
1395 pos = 0;
1396 } else {
1397 pos = p + 1;
1398 }
1399 L_coef(dim, node * nDim + d) *= L(d2, pos);
1400 }
1401 }
1402 // edges
1403 } else if(node < noVertices + noEdges * p) {
1404 // Which edge do we consider right now?
1405 MInt edge = (MInt)floor((node - noVertices) / p);
1406 // Which point of the edge do we consider right now?
1407 MInt l = (node - noVertices) % p;
1408 for(MInt d = 0; d < nDim; d++) {
1409 if(d == dim) {
1410 L_coef(dim, node * nDim + d) = F1;
1411 } else {
1412 L_coef(dim, node * nDim + d) = F0;
1413 }
1414 for(MInt d2 = 0; d2 < nDim; d2++) {
1415 MInt pos = -1;
1416 if(Fd::edgePosition(edge, d2) < F0) {
1417 pos = 0;
1418 } else if(Fd::edgePosition(edge, d2) > F0) {
1419 pos = p + 1;
1420 } else {
1421 pos = l + 1;
1422 }
1423 L_coef(dim, node * nDim + d) *= L(d2, pos);
1424 }
1425 }
1426 // surfaces
1427 } else if(node < noVertices + noEdges * p + noSurfaces * p * p) {
1428 // Which surface do we consider right now?
1429 MInt surface = (MInt)floor((node - noVertices - noEdges * p) / (p * p));
1430 // Which point of the surface do we consider right now?
1431 MInt l[2] = {0};
1432 l[1] = (node - noVertices - noEdges * p) % (p * p);
1433 while(l[1] >= p) {
1434 l[0]++;
1435 l[1] -= p;
1436 }
1437 for(MInt d = 0; d < nDim; d++) {
1438 if(d == dim) {
1439 L_coef(dim, node * nDim + d) = F1;
1440 } else {
1441 L_coef(dim, node * nDim + d) = F0;
1442 }
1443 MInt counter = 0;
1444 for(MInt d2 = 0; d2 < nDim; d2++) {
1445 MInt pos = -1;
1446 if(Fd::surfacePosition(surface, d2) < F0) {
1447 pos = 0;
1448 } else if(Fd::surfacePosition(surface, d2) > F0) {
1449 pos = p + 1;
1450 } else {
1451 pos = l[counter] + 1;
1452 counter++;
1453 }
1454 L_coef(dim, node * nDim + d) *= L(d2, pos);
1455 }
1456 }
1457 // inner points
1458 } else {
1459 MInt l[3] = {0};
1460 // Which point of the inner points do we consider right now?
1461 l[2] = node - noVertices - noEdges * p - noSurfaces * p * p;
1462 while(l[2] >= (p * p)) {
1463 l[0]++;
1464 l[2] -= (p * p);
1465 }
1466 while(l[2] >= p) {
1467 l[1]++;
1468 l[2] -= p;
1469 }
1470 for(MInt d = 0; d < nDim; d++) {
1471 if(d == dim) {
1472 L_coef(dim, node * nDim + d) = F1;
1473 } else {
1474 L_coef(dim, node * nDim + d) = F0;
1475 }
1476 MInt counter = 0;
1477 for(MInt d2 = 0; d2 < nDim; d2++) {
1478 MInt pos = l[counter] + 1;
1479 counter++;
1480 L_coef(dim, node * nDim + d) *= L(d2, pos);
1481 }
1482 }
1483 }
1484 }
1485 }
1486}
1487
1501template <MInt nDim>
1503 MFloatScratchSpace& L_prime) {
1504 TRACE();
1505
1506 const MInt p = a_pRfnmnt(pCellId);
1507 MFloatScratchSpace L(nDim, p + 2, AT_, "L");
1508 MFloatScratchSpace L_deriv(nDim, p + 2, AT_, "L");
1509
1510 // initialize the arrays for the mapping
1511 MInt noVertices = IPOW2(nDim);
1512 MInt noEdges = (nDim == 2) ? 0 : 12;
1513 MInt noSurfaces = (nDim == 2) ? 4 : 6;
1514
1515 // initialize the L matrix with 1.0 and L_deriv with 0.0
1516 for(MInt d = 0; d < nDim; d++) {
1517 for(MInt i = 0; i < p + 2; i++) {
1518 L(d, i) = F1;
1519 L_deriv(d, i) = F0;
1520 }
1521 }
1522
1523 // calculate the lagrangian polynominal and its derivative
1524 // see Lagrange polynominal
1525 // Maybe L can be stored once at the beginning
1526 for(MInt d = 0; d < nDim; d++) {
1527 for(MInt i = 0; i < p + 2; i++) {
1528 for(MInt j = 0; j < p + 2; j++) {
1529 if(i == j) continue;
1530 L(d, i) *= (z[d] - a_nodePosition(pCellId, j)) / (a_nodePosition(pCellId, i) - a_nodePosition(pCellId, j));
1531 MFloat L_p = (F1 / (a_nodePosition(pCellId, i) - a_nodePosition(pCellId, j)));
1532 for(MInt l = 0; l < p + 2; l++) {
1533 if(l == i || l == j) continue;
1534 L_p *= (z[d] - a_nodePosition(pCellId, l)) / (a_nodePosition(pCellId, i) - a_nodePosition(pCellId, l));
1535 }
1536 L_deriv(d, i) += L_p;
1537 }
1538 }
1539 }
1540
1541 // Now that all polynominals are calculated, the polynominals
1542 // for the different directions need to be multiplied for each node
1543 // First the values at the vertices, then at the edges, than at the
1544 // surfaces and finally at the inner points are determined
1545 for(MInt node = 0; node < a_noNodes(pCellId); node++) {
1546 // vertices
1547 if(node < noVertices) {
1548 for(MInt dir = 0; dir < nDim; dir++) {
1549 for(MInt d = 0; d < nDim; d++) {
1550 MInt pos = -1;
1551 // Vertices are located at the ends of the L array
1552 // so the position is either 0 or p + 1
1553 if(Fd::vertexPosition(node, d) < F0) {
1554 pos = 0;
1555 } else {
1556 pos = p + 1;
1557 }
1558 if(dir == d) {
1559 L_prime(node, dir) *= L_deriv(d, pos);
1560 } else {
1561 L_prime(node, dir) *= L(d, pos);
1562 }
1563 }
1564 }
1565 // edges
1566 } else if(node < noVertices + noEdges * p) {
1567 // Which edge do we consider right now?
1568 MInt edge = (MInt)floor((node - noVertices) / p);
1569 // Which point of the edge do we consider right now?
1570 MInt l = (node - noVertices) % p;
1571 for(MInt dir = 0; dir < nDim; dir++) {
1572 for(MInt d = 0; d < nDim; d++) {
1573 MInt pos = -1;
1574 if(Fd::edgePosition(edge, d) < F0) {
1575 pos = 0;
1576 } else if(Fd::edgePosition(edge, d) > F0) {
1577 pos = p + 1;
1578 } else {
1579 pos = l + 1;
1580 }
1581 if(dir == d) {
1582 L_prime(node, dir) *= L_deriv(d, pos);
1583 } else {
1584 L_prime(node, dir) *= L(d, pos);
1585 }
1586 }
1587 }
1588 // surfaces
1589 } else if(node < noVertices + noEdges * p + noSurfaces * p * p) {
1590 // Which surface do we consider right now?
1591 MInt surface = (MInt)floor((node - noVertices - noEdges * p) / (p * p));
1592 // Which point of the surface do we consider right now?
1593 MInt l[2] = {0};
1594 l[1] = (node - noVertices - noEdges * p) % (p * p);
1595 while(l[1] >= p) {
1596 l[0]++;
1597 l[1] -= p;
1598 }
1599 for(MInt dir = 0; dir < nDim; dir++) {
1600 MInt counter = 0;
1601 for(MInt d = 0; d < nDim; d++) {
1602 MInt pos = -1;
1603 if(Fd::surfacePosition(surface, d) < F0) {
1604 pos = 0;
1605 } else if(Fd::surfacePosition(surface, d) > F0) {
1606 pos = p + 1;
1607 } else {
1608 pos = l[counter] + 1;
1609 counter++;
1610 }
1611 if(dir == d) {
1612 L_prime(node, dir) *= L_deriv(d, pos);
1613 } else {
1614 L_prime(node, dir) *= L(d, pos);
1615 }
1616 }
1617 }
1618 // inner points
1619 } else {
1620 MInt l[3] = {0};
1621 // Which point of the inner points do we consider right now?
1622 l[2] = node - noVertices - noEdges * p - noSurfaces * p * p;
1623 while(l[2] >= (p * p)) {
1624 l[0]++;
1625 l[2] -= (p * p);
1626 }
1627 while(l[2] >= p) {
1628 l[1]++;
1629 l[2] -= p;
1630 }
1631 for(MInt dir = 0; dir < nDim; dir++) {
1632 MInt counter = 0;
1633 for(MInt d = 0; d < nDim; d++) {
1634 MInt pos = l[counter] + 1;
1635 counter++;
1636 if(dir == d) {
1637 L_prime(node, dir) *= L_deriv(d, pos);
1638 } else {
1639 L_prime(node, dir) *= L(d, pos);
1640 }
1641 }
1642 }
1643 }
1644 }
1645}
1646
1647
1659template <MInt nDim>
1661 TRACE();
1662
1663 MFloatScratchSpace L_prime(a_noNodes(pCellId), nDim, AT_, "L_prime");
1664 MFloatScratchSpace L_mul_Xinverse(a_noNodes(pCellId), nDim, AT_, "L_mul_Jac");
1665
1666 // initialize L_prime with 1.0 and L_mul_Xinverse with 0.0
1667 for(MInt n = 0; n < a_noNodes(pCellId); n++) {
1668 for(MInt d = 0; d < nDim; d++) {
1669 L_prime(n, d) = F1;
1670 L_mul_Xinverse(n, d) = F0;
1671 }
1672 }
1673 getDerivativeOfDisplacementInterpolationMatrix(pCellId, z, L_prime);
1674
1675 // Calculate the jacobian matrix
1676 MFloatScratchSpace X_inverse(nDim * nDim, AT_, "X_inverse");
1677 for(MInt d1 = 0; d1 < nDim; d1++) {
1678 for(MInt d2 = 0; d2 < nDim; d2++) {
1679 if(d1 == d2) {
1680 X_inverse(d2 + d1 * nDim) = a_invJacobian(pCellId);
1681 } else {
1682 X_inverse(d2 + d1 * nDim) = F0;
1683 }
1684 }
1685 }
1686 if(m_testRun && m_polyDeg < 1) getJacobiMatrixDebug(pCellId, z, X_inverse);
1687
1688 // Calculate the matrix product of L_prime and X_inverse
1689 for(MInt n = 0; n < a_noNodes(pCellId); n++) {
1690 for(MInt d1 = 0; d1 < nDim; d1++) {
1691 for(MInt d2 = 0; d2 < nDim; d2++) {
1692 L_mul_Xinverse(n, d1) += L_prime(n, d2) * X_inverse(d2 + d1 * nDim);
1693 }
1694 }
1695 }
1696
1697 // Set the entries of the strain inverpolation matrix
1698 for(MInt n = 0; n < a_noNodes(pCellId); n++) {
1699 for(MInt d1 = 0; d1 < nDim; d1++) {
1700 for(MInt d2 = 0; d2 < nDim; d2++) {
1701 if(d1 == d2) {
1702 Be(d2, n * nDim + d1) = L_mul_Xinverse(n, d2);
1703 } else {
1704 Be(d2, n * nDim + d1) = F0;
1705 }
1706 }
1707 if(nDim == 2) {
1708 MInt pos = ((d1 + 1) < nDim) ? (d1 + 1) : (d1 - 1);
1709 Be(nDim, n * nDim + d1) = L_mul_Xinverse(n, pos);
1710 } else {
1711 for(MInt d2 = 0; d2 < nDim; d2++) {
1712 MInt d3 = ((d2 + 1) < nDim) ? (d2 + 1) : 0;
1713 MInt d4 = ((d1 + 1) < nDim) ? (d1 + 1) : 0;
1714 if(d1 == d2) {
1715 Be(d2 + nDim, n * nDim + d1) = L_mul_Xinverse(n, d3);
1716 } else if(d2 == d4) {
1717 Be(d2 + nDim, n * nDim + d1) = F0;
1718 } else {
1719 Be(d2 + nDim, n * nDim + d1) = L_mul_Xinverse(n, d2);
1720 }
1721 }
1722 }
1723 }
1724 }
1725 if(m_testRun && m_polyDeg < 1) getStrainInterpolationMatrixDebug(pCellId, z, Be);
1726}
1727
1735template <MInt nDim>
1736void FcSolver<nDim>::getMaterialTensor(MFloatScratchSpace& C, const MInt pCellId, const MInt node) {
1737 TRACE();
1738
1739 switch(string2enum(solverMethod())) {
1740 case MAIA_LINEAR_ELASTIC: {
1741 const MFloat nu = a_poissonRatio(pCellId);
1742 const MFloat c1 = m_E * (F1 - nu) / ((F1 + nu) * (F1 - F2 * nu));
1743 const MFloat c2 = m_E * nu / ((F1 + nu) * (F1 - F2 * nu));
1744 const MFloat c3 = m_E / (F2 * (F1 + nu));
1745 if(m_first && m_testRun) {
1746 cout << "///////////////////////////////////////////////////////////////" << endl;
1747 cout << "///////////////////////////////////////////////////////////////" << endl;
1748 cout << endl;
1749 cout << "MATERIAL PROPERTIES: " << endl;
1750 cout << endl;
1751 cout << "E-Modul E = " << m_E << endl;
1752 cout << "Poisson Ratio nu = " << nu << endl;
1753 cout << "c1 = E * (F1 - nu) / ((F1 + nu) * (F1 - F2 * nu)) = " << c1 << endl;
1754 cout << "c2 = E * nu / ((F1 + nu) * (F1 - F2 * nu)) = " << c2 << endl;
1755 cout << "c3 = E / (F2 * (F1 + nu)) = " << c3 << endl;
1756 cout << endl;
1757 m_log << "///////////////////////////////////////////////////////////////" << endl;
1758 m_log << "///////////////////////////////////////////////////////////////" << endl;
1759 m_log << endl;
1760 m_log << "MATERIAL PROPERTIES: " << fixed << setprecision(5) << endl;
1761 m_log << endl;
1762 m_log << "E-Modul E = " << m_E << endl;
1763 m_log << "Poisson Ratio nu = " << nu << endl;
1764 m_log << "c1 = E * (F1 - nu) / ((F1 + nu) * (F1 - F2 * nu)) = " << c1 << endl;
1765 m_log << "c2 = E * nu / ((F1 + nu) * (F1 - F2 * nu)) = " << c2 << endl;
1766 m_log << "c3 = E / (F2 * (F1 + nu)) = " << c3 << endl;
1767 m_log << endl;
1768 }
1769
1770 for(MInt dirA = 0; dirA < m_noStrains; dirA++) {
1771 for(MInt dirB = 0; dirB < m_noStrains; dirB++) {
1772 C(dirA, dirB) = F0;
1773 }
1774 }
1775 for(MInt dirA = 0; dirA < nDim; dirA++) {
1776 for(MInt dirB = 0; dirB < nDim; dirB++) {
1777 C(dirA, dirB) = (dirA == dirB) ? c1 : c2;
1778 }
1779 }
1780 for(MInt dirA = nDim; dirA < m_noStrains; dirA++) {
1781 for(MInt dirB = nDim; dirB < m_noStrains; dirB++) {
1782 C(dirA, dirB) = (dirA == dirB) ? c3 : F0;
1783 }
1784 }
1785 if(m_first && m_testRun) {
1786 cout << "Material tensor: " << endl;
1787 m_log << "Material tensor: " << endl;
1788 for(MInt dirA = 0; dirA < m_noStrains; dirA++) {
1789 for(MInt dirB = 0; dirB < m_noStrains; dirB++) {
1790 cout << C(dirA, dirB) << "\t\t\t";
1791 m_log << C(dirA, dirB) << "\t\t\t";
1792 }
1793 cout << endl;
1794 m_log << endl;
1795 }
1796 cout << endl;
1797 m_log << endl;
1798 }
1799 m_first = false;
1800 break;
1801 }
1802 case MAIA_NONLINEAR_BAR: {
1803 std::array<MFloat, nDim> coordA{};
1804 getCoordinatesOfNode(node, pCellId, coordA.data());
1805 const MInt nodeIdA = a_nodeIdsLocal(pCellId, node);
1806
1807 for(MInt nodeB = node + 1; nodeB < a_noNodes(pCellId); nodeB++) {
1808 const MInt nodeIdB = a_nodeIdsLocal(pCellId, nodeB);
1809 const MFloat A = F1;
1810 const MFloat E = m_E;
1811 std::array<MFloat, nDim> coordB{};
1812 getCoordinatesOfNode(nodeB, pCellId, coordB.data());
1813 std::array<MFloat, nDim> diff{};
1814 for(MInt d = 0; d < nDim; d++) {
1815 diff[d] = coordB[d] - coordA[d];
1816 }
1817 const MFloat LSq = std::inner_product(&diff[0], &diff[nDim], &diff[0], .0);
1818 const MFloat L = sqrt(LSq);
1819 const MFloat pre = E * A / (L * L * L);
1820 std::array<MFloat, 2 * nDim> c{};
1821 std::array<MInt, 2 * nDim> gGlobal{};
1822 std::array<MInt, 2 * nDim> gLocal{};
1823 std::array<MFloat, 2 * nDim> sign{};
1824 for(MInt d = 0; d < nDim; d++) {
1825 gGlobal[d] = nodeIdA * nDim + d;
1826 gLocal[d] = node * nDim + d;
1827 c[d] = diff[d];
1828 sign[d] = F1;
1829 }
1830 for(MInt d = nDim; d < 2 * nDim; d++) {
1831 gGlobal[d] = nodeIdB * nDim + (d - nDim);
1832 gLocal[d] = nodeB * nDim + (d - nDim);
1833 c[d] = diff[d - nDim];
1834 sign[d] = -F1;
1835 }
1836 for(MInt n1 = 0; n1 < m_noStrains; n1++) {
1837 for(MInt n2 = 0; n2 < m_noStrains; n2++) {
1838 const MFloat disA = m_totalNodalDisplacements[gGlobal[n1]];
1839 const MFloat disB = m_totalNodalDisplacements[gGlobal[n2]];
1840 const MInt nA = gLocal[n1];
1841 const MInt nB = gLocal[n2];
1842 C(nA, nB) += pre * (F1 + F1B2 * (disA - disB)) * c[n1] * c[n2] * sign[n1] * sign[n2];
1843 }
1844 }
1845 }
1846 break;
1847 }
1848 default: {
1849 stringstream errorMessage;
1850 errorMessage << "Error!!! Solver method not implemented." << endl;
1851 mTerm(1, AT_, errorMessage.str());
1852 }
1853 }
1854}
1855
1864template <MInt nDim>
1865void FcSolver<nDim>::getNodalStiffnessMatrix(const MInt pCellId, const MInt node, MFloatScratchSpace& Ke, MInt* nodePos,
1866 MFloat* z, MFloat determinant, const MFloat alpha,
1867 const MInt subCellLevel) {
1868 TRACE();
1869
1870 for(MInt d1 = 0; d1 < nDim * a_noNodes(pCellId); d1++) {
1871 for(MInt d2 = 0; d2 < nDim * a_noNodes(pCellId); d2++) {
1872 Ke(d1, d2) = F0;
1873 }
1874 }
1875
1876 if(solverMethod() == "MAIA_NONLINEAR_BAR") {
1877 getMaterialTensor(Ke, pCellId, node);
1878 } else {
1879 MFloatScratchSpace Be(m_noStrains, nDim * a_noNodes(pCellId), AT_, "Be");
1880 MFloatScratchSpace BeT(nDim * a_noNodes(pCellId), m_noStrains, AT_, "BeT");
1881 MFloatScratchSpace BeT_mul_C(nDim * a_noNodes(pCellId), m_noStrains, AT_, "BeT_mul_C");
1882
1883 // Get the material tensor
1884 MFloatScratchSpace C(m_noStrains, m_noStrains, AT_, "C");
1885 getMaterialTensor(C, pCellId, node);
1886
1887 // Get strain interpolation matrix and transpose it
1888 getStrainInterpolationMatrix(Be, pCellId, z);
1889 for(MInt d = 0; d < m_noStrains; d++) {
1890 for(MInt e = 0; e < a_noNodes(pCellId) * nDim; e++) {
1891 BeT(e, d) = Be(d, e);
1892 }
1893 }
1894
1895 // Calculate the integration weigths
1896 MFloat weight = F1;
1897 for(MInt d = 0; d < nDim; d++) {
1898 weight *= m_gaussWeights[a_pRfnmnt(pCellId)][nodePos[d]];
1899 }
1900
1901 if(m_testRun) {
1902 m_volume += determinant * weight * alpha;
1903 }
1904 // Multiply the integration weights and the determinant to the material tensor
1905 for(MInt d1 = 0; d1 < m_noStrains; d1++) {
1906 for(MInt d2 = 0; d2 < m_noStrains; d2++) {
1907 C(d1, d2) *= determinant * weight * alpha;
1908 }
1909 }
1910
1911 if(m_testRun && subCellLevel < 1) {
1912 cout << "Strain-Interpolation-Matrix B^T_e at this point:" << endl;
1913 for(MInt e = 0; e < a_noNodes(pCellId) * nDim; e++) {
1914 for(MInt d = 0; d < m_noStrains; d++) {
1915 cout << BeT(e, d) << " ";
1916 }
1917 cout << endl;
1918 }
1919 cout << endl;
1920 cout << "Material tensor multiplied with the determinant " << determinant << " and the integration weights w "
1921 << weight << " and alpha " << alpha << ":" << endl;
1922 for(MInt d1 = 0; d1 < m_noStrains; d1++) {
1923 for(MInt d2 = 0; d2 < m_noStrains; d2++) {
1924 cout << C(d1, d2) << " ";
1925 }
1926 cout << endl;
1927 }
1928 cout << endl;
1929 cout << "Strain-Interpolation-Matrix B_e at this point:" << endl;
1930 for(MInt d = 0; d < m_noStrains; d++) {
1931 for(MInt e = 0; e < a_noNodes(pCellId) * nDim; e++) {
1932 cout << Be(d, e) << " ";
1933 }
1934 cout << endl;
1935 }
1936 cout << endl;
1937 }
1938
1939 // Matrix Multiplication
1940 maia::math::multiplyMatrices(BeT, C, BeT_mul_C, nDim * a_noNodes(pCellId), m_noStrains, m_noStrains, m_noStrains);
1941
1942 maia::math::multiplyMatrices(BeT_mul_C, Be, Ke, nDim * a_noNodes(pCellId), m_noStrains, m_noStrains,
1943 nDim * a_noNodes(pCellId));
1944
1945 if(m_testRun && subCellLevel < 1) {
1946 cout << "Intermediate result, B^T_e * C * B_e * det(X_,z) * w:" << endl;
1947 for(MInt d = 0; d < a_noNodes(pCellId) * nDim; d++) {
1948 for(MInt e = 0; e < a_noNodes(pCellId) * nDim; e++) {
1949 cout << Ke(d, e) << " ";
1950 }
1951 cout << endl;
1952 }
1953 cout << endl;
1954 cout << "---------------------------------------" << endl;
1955 cout << endl;
1956 }
1957 }
1958}
1959
1966template <MInt nDim>
1967void FcSolver<nDim>::getElementMatrix(MFloatScratchSpace& Ke, const MInt pCellId, const MFloat alpha,
1968 const MInt subCellLevel, const MFloat* subCellCoord) {
1969 TRACE();
1970
1971 MInt nodePos[nDim] = {0};
1972 MFloat z[nDim] = {F0};
1973 MFloat determinant = F1;
1974 for(MInt d = 0; d < nDim; d++) {
1975 determinant *= a_jacobianMatrix(pCellId) * FFPOW2(subCellLevel);
1976 }
1977
1978 if(subCellLevel < 1 && m_testRun) {
1979 cout << endl;
1980 cout << "The Element-Stiffness-Matrix is calculated " << endl;
1981 cout << "by adding together the resulting matrices of the product " << endl;
1982 cout << endl;
1983 cout << "B^T_e(z) * C(z) * B_e(z) * det(X_,z(z))" << endl;
1984 cout << endl;
1985 cout << "calculated at each of the following integration points z:" << endl;
1986 cout << endl;
1987 cout << "---------------------------------------" << endl;
1988 cout << endl;
1989 }
1990
1991 for(MInt node = 0; node < a_noNodes(node); node++) {
1992 MFloatScratchSpace Mat_part(a_noNodes(pCellId) * nDim, a_noNodes(pCellId) * nDim, AT_, "Mat_part");
1993
1994 const MInt nodesPerDir = a_pRfnmnt(pCellId) + 2;
1995 Fd::nodePosition(node, nodesPerDir, nodePos);
1996
1997 for(MInt d = 0; d < nDim; d++) {
1998 z[d] = m_gaussPoints[a_pRfnmnt(pCellId)][nodePos[d]];
1999 }
2000
2001 if(subCellLevel > 0) {
2002 std::array<MFloat, nDim> point{};
2003 interpolateSubCellGeometry(pCellId, z, point.data(), subCellLevel, subCellCoord);
2004 MBool outside = m_geometry->pointIsInside2(point.data());
2005 if(outside) {
2006 continue;
2007 } else {
2008 transformToLocal(pCellId, point.data(), z);
2009 }
2010 }
2011
2012 if(m_testRun) {
2013 if(subCellLevel < 1) {
2014 cout << "Integration points used: ";
2015 for(MInt d = 0; d < nDim; d++) {
2016 if(subCellLevel < 1) {
2017 cout << z[d] << " ";
2018 }
2019 }
2020 cout << endl;
2021 }
2022
2023 MFloatScratchSpace x(nDim, nDim, AT_, "x");
2024 for(MInt d1 = 0; d1 < nDim; d1++) {
2025 for(MInt d2 = 0; d2 < nDim; d2++) {
2026 x(d1, d2) = F0;
2027 }
2028 }
2029 lagrangianPointsJacobi(pCellId, z, x);
2030 std::array<std::array<MFloat, nDim>, nDim> x_{};
2031 for(MInt d1 = 0; d1 < nDim; d1++) {
2032 for(MInt d2 = 0; d2 < nDim; d2++) {
2033 x_[d1][d2] = x(d1, d2);
2034 }
2035 }
2036 MFloat determinantDebug = maia::math::determinant(x_);
2037 for(MInt d = 0; d < nDim; d++) {
2038 determinantDebug *= FFPOW2(subCellLevel);
2039 }
2040 if(!approx(determinantDebug, determinant, m_eps)) {
2041 stringstream errorMessage;
2042 errorMessage << "Error in calculating the determinant of the jaconbian matrix" << determinant << " "
2043 << determinantDebug << endl;
2044 mTerm(1, AT_, errorMessage.str());
2045 }
2046 if(subCellLevel < 1) {
2047 cout << "determinant at this point: " << determinant << endl;
2048 }
2049 }
2050
2051 getNodalStiffnessMatrix(pCellId, node, Mat_part, nodePos, z, determinant, alpha, subCellLevel);
2052 for(MInt m1 = 0; m1 < a_noNodes(pCellId) * nDim; m1++) {
2053 for(MInt m2 = 0; m2 < a_noNodes(pCellId) * nDim; m2++) {
2054 Ke(m1, m2) += Mat_part(m1, m2);
2055 }
2056 }
2057 }
2058}
2059
2060template <MInt nDim>
2062 TRACE();
2063
2064 for(MInt cell = 0; cell < a_noCells(); cell++) {
2065 if(!a_isActive(cell)) continue;
2066 MFloat z[nDim] = {F0};
2067 MInt nodePos[nDim] = {0};
2068
2069 MFloat determinant = F1;
2070 for(MInt d = 0; d < nDim; d++) {
2071 determinant *= a_jacobianMatrix(cell);
2072 }
2073
2074 for(MInt node = 0; node < a_noNodes(cell); node++) {
2075 const MInt nodesPerDir = a_pRfnmnt(cell) + 2;
2076 Fd::nodePosition(node, nodesPerDir, nodePos);
2077
2078 for(MInt d = 0; d < nDim; d++) {
2079 z[d] = m_gaussPoints[a_pRfnmnt(cell)][nodePos[d]];
2080 }
2081
2082 MFloat weight = F1;
2083 for(MInt d = 0; d < nDim; d++) {
2084 weight *= m_gaussWeights[a_pRfnmnt(cell)][nodePos[d]];
2085 }
2086 weight *= determinant;
2087
2088 MFloatScratchSpace Be(m_noStrains, nDim * a_noNodes(cell), AT_, "Be");
2089
2090 // Get strain interpolation matrix and transpose it
2091 getStrainInterpolationMatrix(Be, cell, z);
2092
2093 std::array<MFloat, m_noStrains> stresses{};
2094 if(string2enum(solverMethod()) == MAIA_LINEAR_ELASTIC) {
2095 getStressesAtPoint(cell, z, m_totalNodalDisplacements, stresses.data());
2096 } else {
2097 for(MInt d = 0; d < m_noStrains; d++) {
2098 stresses[d] = a_nodalStresses(cell, node, d);
2099 }
2100 }
2101 // Loop over all directions and all integration points to get the
2102 // load at the nodes
2103 for(MInt n = 0; n < a_noNodes(cell); n++) {
2104 for(MInt dim = 0; dim < nDim; dim++) {
2105 MInt nodeId = a_nodeIdsLocal(cell, n);
2106 MFloat load = F0;
2107 for(MInt d = 0; d < m_noStrains; d++) {
2108 MFloat BeT = Be(d, n * nDim + dim);
2109 load += BeT * stresses[d];
2110 }
2111 m_internalLoadVector[nodeId * nDim + dim] += load * weight;
2112 }
2113 }
2114 }
2115 }
2116}
2117
2118template <MInt nDim>
2120 TRACE();
2121
2122 m_bndryCnd->calcReactionForces();
2123}
2124
2125// Not required at the moment
2126template <MInt nDim>
2127void FcSolver<nDim>::rhs() {
2128 TRACE();
2129}
2130
2138template <MInt nDim>
2140 TRACE();
2141
2142 // Apply boundary condition
2143 m_bndryCnd->updateForceVector();
2144}
2145
2146// Not required at the moment
2147template <MInt nDim>
2148void FcSolver<nDim>::lhs() {
2149 TRACE();
2150}
2151
2159template <MInt nDim>
2161 TRACE();
2162
2163 m_globalBndryMatrix.clear();
2164
2165 // Apply boundary condition
2166 m_bndryCnd->updateSystemMatrix();
2167}
2168
2176template <MInt nDim>
2178 TRACE();
2179}
2180
2185template <MInt nDim>
2187 TRACE();
2188
2189 NEW_TIMER_GROUP(tg_solver, "FC Solver (solverId=" + std::to_string(m_solverId) + ")");
2190 NEW_TIMER_NOCREATE(m_t.solver, "complete solver", tg_solver);
2191
2192 NEW_SUB_TIMER_NOCREATE(m_t.initSolver, "init solver", m_t.solver);
2193 NEW_SUB_TIMER_NOCREATE(m_t.calcStiffMat, "calc Siffness Matrix per Level", m_t.initSolver);
2194 NEW_SUB_TIMER_NOCREATE(m_t.solutionStep, "SolutionStep", m_t.solver);
2195 NEW_SUB_TIMER_NOCREATE(m_t.subCellInt, "subcell Integration", m_t.solutionStep);
2196 NEW_SUB_TIMER_NOCREATE(m_t.forceBC, "boundary forces", m_t.solutionStep);
2197 NEW_SUB_TIMER_NOCREATE(m_t.displacementBC, "boundary displacement", m_t.solutionStep);
2198 NEW_SUB_TIMER_NOCREATE(m_t.solving, "Solution of System of Equations", m_t.solutionStep);
2199 NEW_SUB_TIMER_NOCREATE(m_t.exchange, "Exchange", m_t.solutionStep);
2200}
2201
2206template <MInt nDim>
2208 TRACE();
2209 if(!grid().isActive()) return;
2210 // 0) map timer ids for safety
2211 std::vector<MInt> timerIds_;
2212 timerIds_.reserve(17);
2213 timerIds_.emplace_back(m_t.solver);
2214 timerIds_.emplace_back(m_t.initSolver);
2215 timerIds_.emplace_back(m_t.calcStiffMat);
2216 timerIds_.emplace_back(m_t.solutionStep);
2217 timerIds_.emplace_back(m_t.subCellInt);
2218 timerIds_.emplace_back(m_t.forceBC);
2219 timerIds_.emplace_back(m_t.displacementBC);
2220 timerIds_.emplace_back(m_t.solving);
2221 timerIds_.emplace_back(m_t.exchange);
2222 const MInt noTimers = timerIds_.size();
2223 // 1) fill buffer with local timer values
2224 std::vector<MFloat> timerValues_;
2225 timerValues_.reserve(noTimers);
2226 for(MInt i = 0; i < noTimers; i++) {
2227 timerValues_.emplace_back(RETURN_TIMER_TIME(timerIds_[i]));
2228 }
2229 // 2) collect values from all ranks
2230 MPI_Allreduce(MPI_IN_PLACE, timerValues_.data(), noTimers, maia::type_traits<MFloat>::mpiType(), MPI_SUM, mpiComm(),
2231 AT_, "MPI_IN_PLACE", "timerValues_");
2232 // 3) perform averaging on timer and4) set new timer values
2233 const MInt noDomains_ = noDomains();
2234 for(MInt i = 0; i < noTimers; i++) {
2235 const MFloat meanValue = timerValues_[i] / noDomains_;
2236 SET_RECORD(timerIds_[i], meanValue);
2237 }
2238}
2239
2240// Not required at the moment
2241template <MInt nDim>
2243 TRACE();
2244}
2245
2246// Not required at the moment
2247template <MInt nDim>
2249 TRACE();
2250}
2251
2260template <MInt nDim>
2262 TRACE();
2263
2264 if(m_testRun) {
2265 // For testing, fill the Displacement vector with the point coordinates
2266 // Thus, the cell strains must be unity the shear components vanish
2267 fillDisplacementVectorWithCoords();
2268 calcElementDisplacements();
2269 for(MInt i = 0; i < a_noCells(); i++) {
2270 if(!a_isActive(i)) continue;
2271 for(MInt d = 0; d < nDim; d++) {
2272 if(!approx(c_coordinate(i, d), a_elementDispl(i, d), 1e-14)) {
2273 stringstream errorMessage;
2274 errorMessage << "Error in interpolating the strains " << c_coordinate(i, d) << " " << a_elementDispl(i, d)
2275 << endl;
2276 mTerm(1, AT_, errorMessage.str());
2277 }
2278 }
2279 }
2280 resetDisplacements();
2281 }
2282
2283 switch(string2enum(solverMethod())) {
2284 case MAIA_LINEAR_ELASTIC: {
2285 // Reset vectors
2286 resetDisplacements(0);
2287 resetLoadVector(0);
2288
2289 // Calculate stiffness matrix
2290 if(globalTimeStep == 1) {
2291 calculateStiffnessMatrix();
2292 }
2293 lhsBnd();
2294 assembleFinalMatrix();
2295 createCompressedMatrix();
2296
2297 // Calculate Force vector
2298 rhsBnd();
2299 getInternalLoadsFromStresses();
2300 getReactionForces();
2301 updateLoadVector();
2302
2303 // Solve system of equations
2304 solveSystemOfEquations();
2305
2306 // Update total displacements and calculate strains and stresses
2307 m_bndryCnd->writeOutModifiedBoundaries();
2308 calcElementDisplacements();
2309 calcElementStrains();
2310 calcElementStresses();
2311
2312 break;
2313 }
2314 case MAIA_NONLINEAR_BAR: {
2315 // Reset vectors and calculate external forces
2316 resetLoadVector(-1);
2317 rhsBnd();
2318
2319 for(MInt step = 0; step < m_noLoadSteps; step++) {
2320 // Reset Displacements
2321 resetDisplacements(0);
2322
2323 // Calculate force vector
2324 const MFloat lambda = ((MFloat)step + F1) / (MFloat)m_noLoadSteps;
2325 updateLoadVector(lambda);
2326
2327 MInt k = 0;
2328 MFloat error = F1;
2329
2330 while(error > 1e-8 && k < 5) {
2331 // Calculate stiffness matrix
2332 calculateStiffnessMatrix();
2333 lhsBnd();
2334 assembleFinalMatrix();
2335 createCompressedMatrix();
2336
2337 // Solve system of equations
2338 solveSystemOfEquations();
2339
2340 // Calculate internal forces and reaction forces
2341 resetLoadVector(1);
2342
2343 // Calculate stiffness matrix
2344 calculateStiffnessMatrix();
2345 m_globalBndryMatrix.clear();
2346 assembleFinalMatrix();
2347 createCompressedMatrix();
2348
2349 const MInt n = m_finalGlobalMatrix.size();
2350 const MInt m = (m_totalNoNodes * nDim);
2351 maia::math::multiplySparseMatrixVector(m_sysMatCompressed, m_compressionIndexSys, n, m, m_internalLoadVector,
2352 m_totalNodalDisplacements);
2353
2354 for(MInt i = 0; i < m_totalNoNodes; i++) {
2355 cout << "Displacements (node " << i << ")";
2356 for(MInt d = 0; d < nDim; d++) {
2357 cout << std::setprecision(8) << " " << m_totalNodalDisplacements[i * nDim + d];
2358 }
2359 cout << endl;
2360 }
2361 cout << endl;
2362
2363 for(MInt i = 0; i < m_totalNoNodes; i++) {
2364 cout << "External forces (node " << i << ")";
2365 for(MInt d = 0; d < nDim; d++) {
2366 cout << std::setprecision(8) << " " << m_nodalLoadVector[i * nDim + d];
2367 }
2368 cout << endl;
2369 }
2370 cout << endl;
2371
2372 for(MInt i = 0; i < m_totalNoNodes; i++) {
2373 cout << "Internal forces (node " << i << ")";
2374 for(MInt d = 0; d < nDim; d++) {
2375 cout << std::setprecision(8) << " " << m_internalLoadVector[i * nDim + d];
2376 }
2377 cout << endl;
2378 }
2379 cout << endl;
2380
2381 getReactionForces();
2382 for(MInt i = 0; i < m_totalNoNodes; i++) {
2383 cout << "Reaction forces (node " << i << ")";
2384 for(MInt d = 0; d < nDim; d++) {
2385 cout << std::setprecision(8) << " " << m_reactionForceVector[i * nDim + d];
2386 }
2387 cout << endl;
2388 }
2389 cout << endl;
2390
2391 updateLoadVector(lambda);
2392
2393 const MFloat norm2Res = maia::math::norm(m_nodalLoadVector, m);
2394 const MFloat norm2Int = maia::math::norm(m_internalLoadVector, m);
2395 const MFloat norm2Reac = maia::math::norm(m_reactionForceVector, m);
2396
2397 error = (fabs(norm2Int) > m_eps) ? norm2Res / (norm2Int) : norm2Res;
2398 if(m_testRun) {
2399 cout << fixed << setprecision(15) << endl;
2400 cout << "Error in step " << step << " and iteration " << k << " is: " << error << endl;
2401 cout << "Lambda in step " << step << " and iteration " << k << " is: " << lambda << endl;
2402 cout << "Residual in step " << step << " and iteration " << k << " is: " << norm2Res << endl;
2403 cout << "IntForce vector in step " << step << " and iteration " << k << " is: " << norm2Int << endl;
2404 cout << "ReacForce vector in step " << step << " and iteration " << k << " is: " << norm2Reac << endl;
2405 cout << fixed << setprecision(5) << endl;
2406 }
2407 k++;
2408 }
2409 }
2410 break;
2411 }
2412 default: {
2413 stringstream errorMessage;
2414 errorMessage << "Error!!! Solver method not implemented." << endl;
2415 mTerm(1, AT_, errorMessage.str());
2416 }
2417 }
2418
2419 return true;
2420}
2421
2422// Not required at the moment
2423template <MInt nDim>
2424void FcSolver<nDim>::saveSolverSolution(MBool forceOutput, const MBool finalTimeStep) {
2425 TRACE();
2426 std::ignore = forceOutput;
2427 std::ignore = finalTimeStep;
2428}
2429
2430// Not required at the moment
2431template <MInt nDim>
2433 TRACE();
2434}
2435
2440template <MInt nDim>
2441MBool FcSolver<nDim>::prepareRestart(MBool writeRestart, MBool& writeGridRestart) {
2442 TRACE();
2443
2444 writeGridRestart = false;
2445
2446 if(((globalTimeStep % m_restartInterval) == 0) || writeRestart) {
2447 writeRestart = true;
2448
2449 if(m_adaptationSinceLastRestart) {
2450 writeGridRestart = true;
2451 }
2452 }
2453
2454 return writeRestart;
2455}
2456
2461template <MInt nDim>
2462void FcSolver<nDim>::writeRestartFile(const MBool writeRestart, const MBool writeBackup, const MString gridFileName,
2463 MInt* recalcIdTree) {
2464 TRACE();
2465 std::ignore = writeBackup;
2466
2467 if(writeRestart) {
2468 stringstream fileName;
2469 fileName << outputDir() << "restart_" << globalTimeStep << ParallelIo::fileExt();
2470
2471 if(m_recalcIds != nullptr) {
2472 // for multisolver recalc size needs to be raw grid size?
2473 for(MInt cellId = 0; cellId < maxNoGridCells(); cellId++) {
2474 m_recalcIds[cellId] = recalcIdTree[cellId];
2475 }
2476
2477 MIntScratchSpace recalcIdsSolver(grid().tree().size(), AT_, "recalcIds");
2478
2479 MInt recalcCounter = 0;
2480 for(MInt cell = 0; cell < grid().raw().m_noInternalCells; cell++) {
2481 // cerr <<"cell : " << cell << " recalc: " << m_recalcIds[cell] << endl;
2482 if(grid().raw().a_hasProperty(cell, Cell::IsHalo)) {
2483 continue;
2484 }
2485 MInt sId = grid().tree().grid2solver(m_recalcIds[cell]);
2486 if(sId > -1) {
2487 recalcIdsSolver[recalcCounter] = sId;
2488 recalcCounter++;
2489 }
2490 }
2491 ASSERT(recalcCounter == grid().noInternalCells(), "recalc ids size is wrong");
2492
2493 saveRestartStrainsOnly(fileName.str().c_str(), gridFileName.c_str(), recalcIdsSolver.getPointer());
2494 cerr << "RecalcIds" << endl;
2495 } else {
2496 saveRestartStrainsOnly(fileName.str().c_str(), gridFileName.c_str(), m_recalcIds);
2497 cerr << "No RecalcIds" << endl;
2498 }
2499 }
2500}
2501
2513template <MInt nDim>
2514void FcSolver<nDim>::saveRestartStrainsOnly(const MChar* fileName, const MChar* gridInputFileName, MInt* recalcIdTree) {
2515 TRACE();
2516 if(nDim != 2 && nDim != 3) {
2517 cerr << " In global function saveRestartStrainsOnly: wrong number of dimensions !" << endl;
2518 exit(0);
2519 return;
2520 }
2521
2522 cerr << "Writing solution to file" << endl;
2523 using namespace maia::parallel_io;
2524 ParallelIo parallelIo(fileName, PIO_REPLACE, mpiComm());
2525 parallelIo.defineScalar(PIO_INT, "noCells");
2526
2527 // total #of cells in the grid == global cell index of the last cell in the last process:
2528 const MInt totalNoCells = domainOffset(noDomains());
2529 cerr << "totalNoCells " << totalNoCells << endl;
2530
2531 //--specify helper functions
2532 auto defFloatArray = [&](const MString arrayName, const MString varName, const MInt length) {
2533 parallelIo.defineArray(PIO_FLOAT, arrayName, length);
2534 parallelIo.setAttribute(varName, "name", arrayName);
2535 };
2536 // function: define macroscopic variables
2537 auto defineMacroscopicVariables = [&](const MString name, const MString prefix) {
2538 // velocities
2539 MInt noIds = (m_testRun) ? IPOW2(nDim) + 1 : 0;
2540 const MInt noOutputVar = (nDim == 2) ? (6 + nDim + noIds) : (12 + nDim + noIds);
2541 MStringScratchSpace velNames(noOutputVar, AT_, "velNames");
2542 if(nDim == 2) {
2543 velNames[0] = "Epsilon_x";
2544 velNames[1] = "Epsilon_y";
2545 velNames[2] = "Epsilon_xy";
2546 velNames[3] = "Stress_x";
2547 velNames[4] = "Stress_y";
2548 velNames[5] = "Stress_xy";
2549 velNames[6] = "Displacement_x";
2550 velNames[7] = "Displacement_y";
2551 if(m_testRun) {
2552 velNames[5] = "GlobalNodeId0";
2553 velNames[6] = "GlobalNodeId1";
2554 velNames[7] = "GlobalNodeId2";
2555 velNames[8] = "GlobalNodeId3";
2556 velNames[9] = "DomainId";
2557 }
2558 } else {
2559 velNames[0] = "Epsilon_x";
2560 velNames[1] = "Epsilon_y";
2561 velNames[2] = "Epsilon_z";
2562 velNames[3] = "Epsilon_xy";
2563 velNames[4] = "Epsilon_yz";
2564 velNames[5] = "Epsilon_xz";
2565 velNames[6] = "Stress_x";
2566 velNames[7] = "Stress_y";
2567 velNames[8] = "Stress_z";
2568 velNames[9] = "Stress_xy";
2569 velNames[10] = "Stress_yz";
2570 velNames[11] = "Stress_xz";
2571 velNames[12] = "Displacement_x";
2572 velNames[13] = "Displacement_y";
2573 velNames[14] = "Displacement_z";
2574 if(m_testRun) {
2575 velNames[15] = "GlobalNodeId0";
2576 velNames[16] = "GlobalNodeId1";
2577 velNames[17] = "GlobalNodeId2";
2578 velNames[18] = "GlobalNodeId3";
2579 velNames[19] = "GlobalNodeId4";
2580 velNames[20] = "GlobalNodeId5";
2581 velNames[21] = "GlobalNodeId6";
2582 velNames[22] = "GlobalNodeId7";
2583 velNames[23] = "DomainId";
2584 }
2585 }
2586
2587 for(MInt d = 0; d != noOutputVar; d++) {
2588 defFloatArray(name + std::to_string(d), prefix + velNames[d], totalNoCells);
2589 }
2590 };
2591 // function: write macroscopic variable
2592 auto writeMacroscopicStrain = [&](const MInt index) {
2593 MFloatScratchSpace tmp(noInternalCells(), AT_, "tmp");
2594 for(MInt i = 0; i < noInternalCells(); ++i) {
2595 tmp[i] = a_elementStrains(recalcIdTree != nullptr ? recalcIdTree[i] : i, index);
2596 }
2597 parallelIo.writeArray(tmp.getPointer(), "strain" + std::to_string(index));
2598 };
2599 // function: write macroscopic variable
2600 auto writeMacroscopicStress = [&](const MInt d, const MInt index) {
2601 MFloatScratchSpace tmp(noInternalCells(), AT_, "tmp");
2602 for(MInt i = 0; i < noInternalCells(); ++i) {
2603 tmp[i] = a_elementStresses(recalcIdTree != nullptr ? recalcIdTree[i] : i, d);
2604 }
2605 parallelIo.writeArray(tmp.getPointer(), "strain" + std::to_string(index));
2606 };
2607 // function: write macroscopic variable
2608 auto writeMacroscopicDisplacement = [&](const MInt d, const MInt index) {
2609 MFloatScratchSpace tmp(noInternalCells(), AT_, "tmp");
2610 for(MInt i = 0; i < noInternalCells(); ++i) {
2611 tmp[i] = a_elementDispl(recalcIdTree != nullptr ? recalcIdTree[i] : i, d);
2612 }
2613 parallelIo.writeArray(tmp.getPointer(), "strain" + std::to_string(index));
2614 };
2615 // function: write macroscopic variable
2616 auto writeGlobalNodeIds = [&](const MInt d, const MInt index) {
2617 MFloatScratchSpace tmp(noInternalCells(), AT_, "tmp");
2618 for(MInt i = 0; i < noInternalCells(); ++i) {
2619 tmp[i] = a_nodeIdsGlobal(recalcIdTree != nullptr ? recalcIdTree[i] : i, d);
2620 }
2621 parallelIo.writeArray(tmp.getPointer(), "strain" + std::to_string(index));
2622 };
2623 // function: write macroscopic variable
2624 auto writeDomainId = [&](const MInt d, const MInt index) {
2625 MFloatScratchSpace tmp(noInternalCells(), AT_, "tmp");
2626 std::ignore = d;
2627 for(MInt i = 0; i < noInternalCells(); ++i) {
2628 tmp[i] = (MFloat)domainId();
2629 }
2630 parallelIo.writeArray(tmp.getPointer(), "strain" + std::to_string(index));
2631 };
2632 //--define arrays
2633 defineMacroscopicVariables("strain", "");
2634
2635 //--define global attributes
2636 parallelIo.setAttribute(solverId(), "solverId");
2637 parallelIo.setAttribute(gridInputFileName, "gridFile", "");
2638 parallelIo.setAttribute(globalTimeStep, "globalTimeStep");
2639 parallelIo.setAttribute(totalNoCells, "noCells");
2640
2641 //--write arrays
2642 // Set file offsets (first globalId and #of cells to be written by this process):
2643 const MPI_Offset firstGlobalId = domainOffset(domainId());
2644 const MPI_Offset localNoCells = noInternalCells();
2645 parallelIo.setOffset(localNoCells, firstGlobalId);
2646
2647 cerr << "InternalCells " << localNoCells << endl;
2648 cerr << "Write out element strains" << endl;
2649 for(MInt index = 0; index < m_noStrains; index++) {
2650 writeMacroscopicStrain(index);
2651 }
2652 cerr << "Write out element stresses" << endl;
2653 for(MInt index = 0; index < m_noStrains; index++) {
2654 writeMacroscopicStress(index, index + m_noStrains);
2655 }
2656 cerr << "Write out element displacements" << endl;
2657 for(MInt d = 0; d < nDim; d++) {
2658 writeMacroscopicDisplacement(d, d + 2 * m_noStrains);
2659 }
2660 if(m_testRun) {
2661 cerr << "Write out global node Ids" << endl;
2662 for(MInt d = 0; d < IPOW2(nDim); d++) {
2663 writeGlobalNodeIds(d, d + nDim + 2 * m_noStrains);
2664 }
2665 writeDomainId(0, IPOW2(nDim) + nDim + 2 * m_noStrains);
2666 }
2667}
2668
2673template <MInt nDim>
2674void FcSolver<nDim>::reIntAfterRestart(MBool doneRestart) {
2675 TRACE();
2676
2677 if(doneRestart) {
2678 m_adaptationSinceLastRestart = false;
2679 }
2680}
2681
2686template <MInt nDim>
2687void FcSolver<nDim>::setCellWeights(MFloat* solverCellWeight) {
2688 TRACE();
2689 const MInt noCellsGrid = grid().raw().treeb().size();
2690 const MInt offset = noCellsGrid * solverId();
2691
2692 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
2693 const MInt gridCellId = grid().tree().solver2grid(cellId);
2694 const MInt id = gridCellId + offset;
2695 solverCellWeight[id] = F1; // 0.2;
2696 }
2697}
2698
2707template <MInt nDim>
2709 TRACE();
2710
2711 for(MInt m1 = 0; m1 < a_noNodes(pCellId); m1++) {
2712 for(MInt d1 = 0; d1 < nDim; d1++) {
2713 for(MInt m2 = 0; m2 < a_noNodes(pCellId); m2++) {
2714 for(MInt d2 = 0; d2 < nDim; d2++) {
2715 // Calculate node ids (global und local)
2716 MInt nodeIdA = a_nodeIdsLocal(pCellId, m1); // nodeId of all nodes
2717 MInt nodeIdB = a_nodeIdsLocal(pCellId, m2); // nodeId of all nodes
2718 MInt rowPosCell = m1 * nDim + d1; // position in Stiffness Matrix of Cell
2719 MInt colPosCell = m2 * nDim + d2; // position in Stiffness Matrix of Cell
2720 MInt rowPosRank = nodeIdA * nDim + d1; // position in assembled Stiffness Matrix
2721 MInt colPosRank = nodeIdB * nDim + d2; // position in assembled Stiffness Matrix
2722
2723 // add to global stiffness matrix in vector notation
2724 // store only non zero entries
2725 if(!approx(Ke(rowPosCell, colPosCell), F0, m_eps)) {
2726 // search in vector if the element already exists
2727 auto pos = std::make_pair(rowPosRank, colPosRank);
2728 auto iter = m_globalStiffnessMatrix.find(pos);
2729 // if the element exists add new value to the existing one
2730 if(iter != m_globalStiffnessMatrix.end()) {
2731 iter->second += Ke(rowPosCell, colPosCell);
2732
2733 // if the element does not exist insert it
2734 // at the correct position in the vector
2735 } else {
2736 MFloat value = Ke(rowPosCell, colPosCell);
2737 m_globalStiffnessMatrix.insert({pos, value});
2738 }
2739 }
2740 }
2741 }
2742 }
2743 }
2744}
2745
2754template <MInt nDim>
2756 TRACE();
2757
2758 for(MInt m1 = 0; m1 < a_noNodes(pCellId); m1++) {
2759 for(MInt d1 = 0; d1 < nDim; d1++) {
2760 for(MInt m2 = 0; m2 < a_noNodes(pCellId); m2++) {
2761 for(MInt d2 = 0; d2 < nDim; d2++) {
2762 // Calculate node ids (global und local)
2763 MInt nodeIdA = a_nodeIdsLocal(pCellId, m1); // nodeId of all nodes
2764 MInt nodeIdB = a_nodeIdsLocal(pCellId, m2); // nodeId of all nodes
2765 MInt rowPosCell = m1 * nDim + d1; // position in Bndry Matrix of Cell
2766 MInt colPosCell = m2 * nDim + d2; // position in Bndry Matrix of Cell
2767 MInt rowPosRank = nodeIdA * nDim + d1; // position in assembled Mass Matrix
2768 MInt colPosRank = nodeIdB * nDim + d2; // position in assembled Mass Matrix
2769
2770 // add to global Mass matrix in vector notation
2771 // store only non zero entries
2772 if(!approx(Bndry(rowPosCell, colPosCell), F0, m_eps)) {
2773 // search in vector if the element already exists
2774 auto pos = std::make_pair(rowPosRank, colPosRank);
2775 auto iter = m_globalBndryMatrix.find(pos);
2776 // if the element exists add new value to the existing one
2777 if(iter != m_globalBndryMatrix.end()) {
2778 if(m_addingPenalties) {
2779 iter->second += Bndry(rowPosCell, colPosCell);
2780 }
2781
2782 // if the element does not exist insert it
2783 // at the correct position in the vector
2784 } else {
2785 MFloat value = Bndry(rowPosCell, colPosCell);
2786 m_globalBndryMatrix.insert({pos, value});
2787 }
2788 }
2789 }
2790 }
2791 }
2792 }
2793}
2794
2803template <MInt nDim>
2805 TRACE();
2806
2807 m_finalGlobalMatrix.clear();
2808
2809 auto iterMat = m_globalStiffnessMatrix.begin();
2810 while(iterMat != m_globalStiffnessMatrix.end()) {
2811 auto pos = iterMat->first;
2812 auto value = iterMat->second;
2813 m_finalGlobalMatrix.insert({pos, value});
2814 iterMat++;
2815 }
2816
2817 iterMat = m_globalBndryMatrix.begin();
2818 while(iterMat != m_globalBndryMatrix.end()) {
2819 auto pos = iterMat->first;
2820 auto value = iterMat->second;
2821 auto iter = m_finalGlobalMatrix.find(pos);
2822 // if the element exists add new value to the existing one
2823 if(iter != m_finalGlobalMatrix.end()) {
2824 iter->second += value;
2825
2826 // if the element does not exist insert it
2827 // at the correct position in the vector
2828 } else {
2829 m_finalGlobalMatrix.insert({pos, value});
2830 }
2831 iterMat++;
2832 }
2833}
2834
2835template <MInt nDim>
2837 TRACE();
2838
2839 // Allocate vector for the global stiffness matrix, which stores only non-zero entries
2840 MFloat* eigenValues{};
2841 MFloat** Ke_final{};
2842 m_globalStiffnessMatrix.clear();
2843
2844 MBool first = true;
2845 for(MInt cell = 0; cell < a_noCells(); cell++) {
2846 m_volume = 0.0;
2847 if(!a_isActive(cell)) continue;
2848
2849 if(m_testRun) {
2850 cout << "///////////////////////////////////////////////////////////////" << endl;
2851 cout << "///////////////////////////////////////////////////////////////" << endl;
2852 cout << endl;
2853 cout << "CellId " << cell << endl;
2854 cout << "Cell center: ";
2855 for(MInt d = 0; d < nDim; d++) {
2856 cout << c_coordinate(cell, d) << " ";
2857 }
2858 cout << endl;
2859 cout << endl;
2860 cout << "Nodes of cell " << cell << endl;
2861 std::array<MInt, nDim> nodePos{};
2862 for(MInt p = 0; p < a_noNodes(cell); p++) {
2863 cout << "Global coordinates of Point " << p << " (localId = " << a_nodeIdsLocal(cell, p)
2864 << ", globalId = " << a_nodeIdsGlobal(cell, p) << "): ";
2865 for(MInt d = 0; d < nDim; d++) {
2866 cout << m_nodalDisplacements[a_nodeIdsLocal(cell, p) * nDim + d] << " ";
2867 }
2868 cout << endl;
2869 cout << "Local coordinates of Point " << p << " (localId = " << a_nodeIdsLocal(cell, p)
2870 << ", globalId = " << a_nodeIdsGlobal(cell, p) << "): ";
2871 for(MInt d = 0; d < nDim; d++) {
2872 cout << a_nodePosition(cell, nodePos[d]) << " (" << nodePos[d] << ") ";
2873 }
2874 cout << endl;
2875 cout << endl;
2876 if((nodePos[nDim - 1] + 1) < (a_pRfnmnt(cell) + 2)) {
2877 nodePos[nDim - 1]++;
2878 } else {
2879 nodePos[nDim - 1] = 0;
2880 if((nodePos[nDim - 2] + 1) < (a_pRfnmnt(cell) + 2)) {
2881 nodePos[nDim - 2]++;
2882 } else {
2883 nodePos[nDim - 2] = 0;
2884 nodePos[0]++;
2885 }
2886 }
2887 }
2888 }
2889
2890 // Allocate element stiffness matrix
2891 if(first) {
2892 first = false;
2893 mAlloc(eigenValues, a_noNodes(cell) * nDim, "eigenValues", F0, AT_);
2894 mAlloc(Ke_final, a_noNodes(cell) * nDim, a_noNodes(cell) * nDim, "Ke_final", F0, AT_);
2895 }
2896 MFloatScratchSpace Ke(a_noNodes(cell) * nDim, a_noNodes(cell) * nDim, AT_, "Ke");
2897
2898 // reset element stiffness matrix
2899 for(MInt m1 = 0; m1 < a_noNodes(cell) * nDim; m1++) {
2900 for(MInt m2 = 0; m2 < a_noNodes(cell) * nDim; m2++) {
2901 Ke(m1, m2) = F0;
2902 Ke_final[m1][m2] = F0;
2903 }
2904 eigenValues[m1] = F0;
2905 }
2906
2907 if(m_testRun) {
2908 // For testing of the interpolation matrix use random points. The results of x1 and x2
2909 // should be equal
2910 std::array<MFloat, nDim> z{};
2911 for(MInt d = 0; d < nDim; d++) {
2912 z[d] = (static_cast<MFloat>(rand()) / static_cast<MFloat>(RAND_MAX)) * F2 - F1;
2913 }
2914 std::array<MFloat, nDim> x1{};
2915 std::array<MFloat, nDim> x2{};
2916 interpolateGeometryDebug(cell, z.data(), x1.data());
2917 interpolateGeometry(cell, z.data(), x2.data());
2918 for(MInt d = 0; d < nDim; d++) {
2919 if(!approx(x1[d], x2[d], 1e-10)) {
2920 stringstream errorMessage;
2921 errorMessage << "Error in interpolating the geometry " << x1[d] << " " << x2[d] << endl;
2922 mTerm(1, AT_, errorMessage.str());
2923 }
2924 }
2925 }
2926
2927 // Calculate Element stiffness matrix without penalty factor
2928 const MFloat alpha = (a_maxSubCellLvl(cell) < 1) ? F1 : m_alpha;
2929 const MInt subCellLevel = 0;
2930 getElementMatrix(Ke, cell, alpha, subCellLevel);
2931 for(MInt m1 = 0; m1 < a_noNodes(cell) * nDim; m1++) {
2932 for(MInt m2 = 0; m2 < a_noNodes(cell) * nDim; m2++) {
2933 Ke_final[m1][m2] = Ke(m1, m2);
2934 }
2935 }
2936
2937 std::array<MFloat, nDim> coords{};
2938 for(MInt d = 0; d < nDim; d++) {
2939 coords[d] = c_coordinate(cell, d);
2940 }
2941 for(MInt child = 0; child < IPOW2(nDim); child++) {
2942 const MInt childLvl = subCellLevel + 1;
2943 m_bndryCnd->subCellIntegration(childLvl, coords.data(), child, cell, Ke_final);
2944 }
2945 for(MInt m1 = 0; m1 < a_noNodes(cell) * nDim; m1++) {
2946 for(MInt m2 = 0; m2 < a_noNodes(cell) * nDim; m2++) {
2947 Ke(m1, m2) = Ke_final[m1][m2];
2948 }
2949 }
2950
2951 if(m_testRun) {
2952 cout << "Element-Stiffness-Matrix of Cell :" << cell << endl;
2953 cout << "SubCellTree depth " << a_maxSubCellLvl(cell) << endl;
2954 cout << "Volume is " << m_volume << endl;
2955 for(MInt m1 = 0; m1 < a_noNodes(cell) * nDim; m1++) {
2956 for(MInt m2 = 0; m2 < a_noNodes(cell) * nDim; m2++) {
2957 cout << Ke_final[m1][m2] << " ";
2958 }
2959 cout << endl;
2960 }
2961 cout << endl;
2962 maia::math::calcEigenValues(Ke_final, eigenValues, a_noNodes(cell) * nDim);
2963
2964 for(MInt m1 = 0; m1 < a_noNodes(cell) * nDim; m1++) {
2965 cout << m1 + 1 << ". Eigen value = " << setprecision(12) << eigenValues[m1] << endl;
2966 }
2967 cout << endl;
2968 if(m_printEigenValues) {
2969 ofstream eigenOutput;
2970 eigenOutput.open("eigenValues.txt", ofstream::app);
2971 for(MInt m1 = 0; m1 < a_noNodes(cell) * nDim; m1++) {
2972 eigenOutput << m1 + 1 << ". Eigen value = " << setprecision(12) << eigenValues[m1] << endl;
2973 }
2974 eigenOutput << endl;
2975 }
2976 }
2977
2978 computeAssembledSystemMatrix(Ke, cell);
2979 }
2980
2981 mDeallocate(Ke_final);
2982 mDeallocate(eigenValues);
2983}
2984
2985template <MInt nDim>
2987 TRACE();
2988
2989 for(MInt i = 0; i < m_totalNoNodes; i++) {
2990 for(MInt d = 0; d < nDim; d++) {
2991 m_totalNodalDisplacements[i * nDim + d] += m_nodalDisplacements[i * nDim + d];
2992 }
2993 }
2994}
2995
2996template <MInt nDim>
2998 TRACE();
2999
3000 switch(mode) {
3001 case -1: {
3002 for(MInt i = 0; i < m_totalNoNodes; i++) {
3003 for(MInt d = 0; d < nDim; d++) {
3004 m_totalNodalDisplacements[i * nDim + d] = F0;
3005 m_nodalDisplacements[i * nDim + d] = F0;
3006 }
3007 }
3008 break;
3009 }
3010 case 0: {
3011 for(MInt i = 0; i < m_totalNoNodes; i++) {
3012 for(MInt d = 0; d < nDim; d++) {
3013 m_nodalDisplacements[i * nDim + d] = F0;
3014 }
3015 }
3016 break;
3017 }
3018 default: {
3019 TERMM(1, "Not implemented for this method (resetDisplacements).");
3020 }
3021 }
3022}
3023
3024template <MInt nDim>
3025void FcSolver<nDim>::resetLoadVector(const MInt mode) {
3026 TRACE();
3027
3028 switch(mode) {
3029 // DEfault: Reset all
3030 case -1: {
3031 for(MInt i = 0; i < m_totalNoNodes; i++) {
3032 for(MInt d = 0; d < nDim; d++) {
3033 m_externalLoadVector[i * nDim + d] = F0;
3034 m_internalLoadVector[i * nDim + d] = F0;
3035 m_reactionForceVector[i * nDim + d] = F0;
3036 m_nodalLoadVector[i * nDim + d] = F0;
3037 }
3038 }
3039 break;
3040 }
3041 // Mode 0: resets all forces but the the total load vector
3042 case 0: {
3043 for(MInt i = 0; i < m_totalNoNodes; i++) {
3044 for(MInt d = 0; d < nDim; d++) {
3045 m_externalLoadVector[i * nDim + d] = F0;
3046 m_internalLoadVector[i * nDim + d] = F0;
3047 m_reactionForceVector[i * nDim + d] = F0;
3048 }
3049 }
3050 break;
3051 }
3052 // Mode 1: resets only internal loads and reaction forces
3053 case 1: {
3054 for(MInt i = 0; i < m_totalNoNodes; i++) {
3055 for(MInt d = 0; d < nDim; d++) {
3056 m_internalLoadVector[i * nDim + d] = F0;
3057 m_reactionForceVector[i * nDim + d] = F0;
3058 }
3059 }
3060 break;
3061 }
3062 // Mode 2 : resets only the external forces
3063 case 2: {
3064 for(MInt i = 0; i < m_totalNoNodes; i++) {
3065 for(MInt d = 0; d < nDim; d++) {
3066 m_externalLoadVector[i * nDim + d] = F0;
3067 }
3068 }
3069 break;
3070 }
3071 default: {
3072 TERMM(1, "Not implemented for this method (resetLoadVector).");
3073 }
3074 }
3075}
3076
3077template <MInt nDim>
3078void FcSolver<nDim>::updateLoadVector(const MFloat lambda) {
3079 TRACE();
3080
3081 for(MInt i = 0; i < m_totalNoNodes; i++) {
3082 for(MInt d = 0; d < nDim; d++) {
3083 const MFloat extLoad = m_externalLoadVector[i * nDim + d] * lambda;
3084 const MFloat intLoad = m_internalLoadVector[i * nDim + d];
3085 const MFloat reacForce = m_reactionForceVector[i * nDim + d];
3086 m_nodalLoadVector[i * nDim + d] = extLoad - (intLoad - reacForce);
3087 }
3088 }
3089}
3090
3091template <MInt nDim>
3093 TRACE();
3094
3095 MInt length = m_finalGlobalMatrix.size();
3096
3097 if(m_sysMatCompressed != nullptr) {
3098 cerr << "Deallocate m_sysMatCompressed" << endl;
3099 mDeallocate(m_sysMatCompressed);
3100 }
3101 if(m_compressionIndexSys != nullptr) {
3102 cerr << "Deallocate m_compressionIndexSys" << endl;
3103 mDeallocate(m_compressionIndexSys);
3104 }
3105
3106 mAlloc(m_sysMatCompressed, length, "m_sysMatCompressed", F0, AT_);
3107
3108 mAlloc(m_compressionIndexSys, length, 2, "m_compressionIndexSys", 0, AT_);
3109
3110 MInt cnt = 0;
3111 auto iterMat = m_finalGlobalMatrix.begin();
3112 while(iterMat != m_finalGlobalMatrix.end()) {
3113 // TODO: Necessary??
3114 if(approx(iterMat->second, F0, m_eps)) {
3115 m_sysMatCompressed[cnt] = F0;
3116 } else {
3117 m_sysMatCompressed[cnt] = iterMat->second;
3118 }
3119 m_compressionIndexSys[cnt][0] = iterMat->first.first;
3120 m_compressionIndexSys[cnt][1] = iterMat->first.second;
3121 iterMat++;
3122 cnt++;
3123 }
3124}
3125
3135template <MInt nDim>
3137 TRACE();
3138
3139 if(m_testRun) {
3140 cout << "///////////////////////////////////////////////////////////////" << endl;
3141 cout << "///////////////////////////////////////////////////////////////" << endl;
3142 cout << endl;
3143 cout << "SOLUTION STEP STARTS:" << endl;
3144 cout << endl;
3145 cout << fixed << setprecision(12) << endl;
3146 cout << "FORCE VECTOR (sorted by the global point Id): " << endl;
3147 for(MInt dom = 0; dom < noDomains(); dom++) {
3148 MPI_Barrier(mpiComm(), AT_);
3149 if(domainId() != dom) continue;
3150 for(MInt i = 0; i < m_totalNoNodes; i++) {
3151 cout << "Node Id " << i << " ";
3152 for(MInt d = 0; d < nDim; d++) {
3153 cout << m_nodalLoadVector[i * nDim + d] << " ";
3154 }
3155 cout << endl;
3156 }
3157 }
3158 cout << fixed << setprecision(5) << endl;
3159 }
3160
3161 const MInt n = m_finalGlobalMatrix.size();
3162 MInt const m = (m_totalNoNodes * nDim);
3163 if(!m_solveSoEIteratively) {
3164 maia::math::solveSparseMatrix(m_sysMatCompressed, m_compressionIndexSys, n, m, m_nodalLoadVector,
3165 m_nodalDisplacements);
3166 } else {
3167 if(m_useEigen) {
3168 maia::math::solveSparseMatrixIterative(m_sysMatCompressed, m_compressionIndexSys, n, m, m_nodalLoadVector,
3169 m_nodalDisplacements);
3170 } else {
3171 solveMatrixIterativelyPreCon(m_sysMatCompressed, m_compressionIndexSys, n, m, m_nodalLoadVector,
3172 m_nodalDisplacements);
3173 }
3174 }
3175
3176 // Update total displacements and calculate strains and stresses
3177 updateDisplacements();
3178
3179 if(m_testRun) {
3180 MFloat sum = F0;
3181 cout << fixed << setprecision(12) << endl;
3182 cout << "DISPLACEMENT VECTOR (sorted by the global point Id): " << endl;
3183 for(MInt dom = 0; dom < noDomains(); dom++) {
3184 MPI_Barrier(mpiComm(), AT_);
3185 if(domainId() != dom) continue;
3186 for(MInt i = 0; i < m_totalNoNodes; i++) {
3187 cout << "Node Id " << i << " ";
3188 for(MInt d = 0; d < nDim; d++) {
3189 cout << m_totalNodalDisplacements[i * nDim + d] << " ";
3190 }
3191 cout << endl;
3192 }
3193 }
3194 cout << endl;
3195
3196 for(MInt i = 0; i < m_totalNoNodes; i++) {
3197 MFloat multi = F0;
3198 for(MInt d = 0; d < nDim; d++) {
3199 multi += F1B2 * (m_totalNodalDisplacements[i * nDim + d] * m_nodalLoadVector[i * nDim + d]);
3200 }
3201 sum += multi;
3202 }
3203 if(noDomains() > 1) {
3204 MPI_Allreduce(MPI_IN_PLACE, &sum, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "sum");
3205 }
3206 MFloat res = sqrt(fabs(m_analyticSolution + sum) / fabs(m_analyticSolution));
3207 cout << "SUM " << -sum << " " << res << endl;
3208 cout << fixed << setprecision(5) << endl;
3209 }
3210}
3211
3212template <MInt nDim>
3213void FcSolver<nDim>::getCoordinatesOfNode(MInt node, MInt cell, MFloat* coordinates) {
3214 TRACE();
3215
3216 MInt noVertices = IPOW2(nDim);
3217 MInt noEdges = (nDim == 2) ? 0 : 12;
3218 MInt noSurfaces = (nDim == 2) ? 4 : 6;
3219
3220 MFloat cellHalfLen = F1B2 * c_cellLengthAtCell(cell);
3221
3222 if(node < noVertices) {
3223 for(MInt d = 0; d < nDim; d++) {
3224 MFloat coord = c_coordinate(cell, d);
3225 MFloat nodeCoord = coord + cellHalfLen * Fd::vertexPosition(node, d);
3226 coordinates[d] = nodeCoord;
3227 }
3228 } else if(node < noVertices + noEdges * a_pRfnmnt(cell)) {
3229 MInt edge = (MInt)floor((node - noVertices) / a_pRfnmnt(cell));
3230 MInt l = (node - noVertices) % a_pRfnmnt(cell);
3231 for(MInt d = 0; d < nDim; d++) {
3232 MFloat nodeCoord = F0;
3233 MFloat coord = c_coordinate(cell, d);
3234 if(approx(Fd::edgePosition(edge, d), F0, 0.0000001)) {
3235 nodeCoord = coord + cellHalfLen * a_nodePosition(cell, l + 1);
3236 } else {
3237 nodeCoord = coord + cellHalfLen * Fd::edgePosition(edge, d);
3238 }
3239 coordinates[d] = nodeCoord;
3240 }
3241 } else if(node < noVertices + noEdges * a_pRfnmnt(cell) + noSurfaces * a_pRfnmnt(cell) * a_pRfnmnt(cell)) {
3242 MInt surface = (MInt)floor((node - noVertices - noEdges * a_pRfnmnt(cell)) / (a_pRfnmnt(cell) * a_pRfnmnt(cell)));
3243 MInt l[2] = {0};
3244 l[1] = (node - noVertices - noEdges * a_pRfnmnt(cell)) % (a_pRfnmnt(cell) * a_pRfnmnt(cell));
3245 while(l[1] >= a_pRfnmnt(cell)) {
3246 l[0]++;
3247 l[1] -= a_pRfnmnt(cell);
3248 }
3249 MInt counter = 0;
3250 for(MInt d = 0; d < nDim; d++) {
3251 MFloat nodeCoord = F0;
3252 MFloat coord = c_coordinate(cell, d);
3253 if(approx(Fd::surfacePosition(surface, d), F0, 0.0000001)) {
3254 nodeCoord = coord + cellHalfLen * a_nodePosition(cell, l[counter] + 1);
3255 counter++;
3256 } else {
3257 nodeCoord = coord + cellHalfLen * Fd::surfacePosition(surface, d);
3258 }
3259 coordinates[d] = nodeCoord;
3260 }
3261 } else {
3262 MInt l[3] = {0};
3263 l[2] = node - noVertices - noEdges * a_pRfnmnt(cell) - noSurfaces * a_pRfnmnt(cell) * a_pRfnmnt(cell);
3264 while(l[2] >= (a_pRfnmnt(cell) * a_pRfnmnt(cell))) {
3265 l[0]++;
3266 l[2] -= (a_pRfnmnt(cell) * a_pRfnmnt(cell));
3267 }
3268 while(l[2] >= a_pRfnmnt(cell)) {
3269 l[1]++;
3270 l[2] -= a_pRfnmnt(cell);
3271 }
3272 MInt counter = 0;
3273 for(MInt d = 0; d < nDim; d++) {
3274 MFloat coord = c_coordinate(cell, d);
3275 MFloat nodeCoord = coord + cellHalfLen * a_nodePosition(cell, l[counter] + 1);
3276 counter++;
3277 coordinates[d] = nodeCoord;
3278 }
3279 }
3280}
3281
3282// The reordered BiCGStab method for distributed memory computer systems
3283// International Conference on Computational Science, ICCS 2010
3284// Procedia Computer Science 1 (2012) 213–218
3285template <MInt nDim>
3286void FcSolver<nDim>::solveMatrixIteratively(MFloat* A_coeff, MInt** pos, const MInt n) {
3287 TRACE();
3288
3289 // 0. Allocate vectors required for the BiCGStab
3290 MFloatScratchSpace r0(m_totalNoNodes * nDim, "r0", AT_);
3291 r0.fill(F0);
3292 MFloatScratchSpace r(m_totalNoNodes * nDim, "r", AT_);
3293 r.fill(F0);
3294 MFloatScratchSpace nu(m_totalNoNodes * nDim, "nu", AT_);
3295 nu.fill(F0);
3296 MFloatScratchSpace p(m_totalNoNodes * nDim, "p", AT_);
3297 p.fill(F0);
3298 MFloatScratchSpace s(m_totalNoNodes * nDim, "s", AT_);
3299 s.fill(F0);
3300 MFloatScratchSpace t(m_totalNoNodes * nDim, "t", AT_);
3301 t.fill(F0);
3302 MFloatScratchSpace b_calc(m_totalNoNodes * nDim, "b_calc", AT_);
3303 b_calc.fill(F0);
3304
3305 MFloat rho = F0;
3306 MFloat alpha = F0;
3307 MFloat omega = F0;
3308 MFloat beta = F0;
3309 MFloat b = F0;
3310
3311 // 1. Initial guess of x0 is 0
3312 // 2. Calculate the dotProduct of r0 and r0
3313 // 3. Set p0 and r equal to r0
3314 for(MInt i = 0; i < m_totalNoNodes * nDim; i++) {
3315 r0[i] = m_nodalLoadVector[i];
3316 r[i] = r0[i];
3317 p[i] = m_nodalLoadVector[i];
3318 }
3319 for(MInt i = 0; i < m_noInternalNodes * nDim; i++) {
3320 rho += (r0[i] * r0[i]);
3321 b += (m_nodalLoadVector[i] * m_nodalLoadVector[i]);
3322 }
3323 cout << setprecision(12) << endl;
3324 MPI_Allreduce(MPI_IN_PLACE, &rho, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "rho");
3325 MPI_Allreduce(MPI_IN_PLACE, &b, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "b");
3326
3327 for(MInt j = 0; j < m_maxNoIterations; j++) {
3328 // 4. Recalculate the vector nu with nu = A * p_j
3329 for(MInt k = 0; k < m_totalNoNodes * nDim; k++) {
3330 nu[k] = F0;
3331 }
3332 for(MInt k = 0; k < n; k++) {
3333 nu[pos[k][0]] += A_coeff[k] * p[pos[k][1]];
3334 }
3335
3336 // 5. Set alpha_j to the ratio of rho and the dotproduct of nu and r0
3337 MFloat dotProduct = F0;
3338 for(MInt k = 0; k < m_noInternalNodes * nDim; k++) {
3339 dotProduct += (nu[k] * r0[k]);
3340 }
3341 MPI_Allreduce(MPI_IN_PLACE, &dotProduct, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dotProduct");
3342 alpha = rho / dotProduct;
3343
3344 // 6. Determine the vector s with s_j = r_j - alpha_j * nu
3345 for(MInt k = 0; k < m_totalNoNodes * nDim; k++) {
3346 s[k] = r[k] - alpha * nu[k];
3347 }
3348
3349 // 7. Recalculate the vector t with t = A * s_j
3350 for(MInt k = 0; k < m_totalNoNodes * nDim; k++) {
3351 t[k] = F0;
3352 }
3353 for(MInt k = 0; k < n; k++) {
3354 t[pos[k][0]] += A_coeff[k] * s[pos[k][1]];
3355 }
3356
3357 // 8. Set omega_j to the ratio of the dotproduct of t and s_j and the dotproduct of t and t
3358 dotProduct = F0;
3359 for(MInt k = 0; k < m_noInternalNodes * nDim; k++) {
3360 dotProduct += (t[k] * s[k]);
3361 }
3362 MPI_Allreduce(MPI_IN_PLACE, &dotProduct, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dotProduct");
3363 omega = dotProduct;
3364 dotProduct = F0;
3365 for(MInt k = 0; k < m_noInternalNodes * nDim; k++) {
3366 dotProduct += (t[k] * t[k]);
3367 }
3368 MPI_Allreduce(MPI_IN_PLACE, &dotProduct, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dotProduct");
3369 omega /= dotProduct;
3370
3371 // 9. Calculate the new result vector x_(j+1) with
3372 // x_(j+1) = x_j + alpha_j * p_j + omega_j * s_j and check the convergence
3373 for(MInt k = 0; k < m_totalNoNodes * nDim; k++) {
3374 m_nodalDisplacements[k] += alpha * p[k] + omega * s[k];
3375 }
3376
3377 // 9b. Check the convergence: c = ||b - A * x|| / ||b||
3378 for(MInt k = 0; k < m_totalNoNodes * nDim; k++) {
3379 b_calc[k] = F0;
3380 }
3381 for(MInt k = 0; k < n; k++) {
3382 b_calc[pos[k][0]] += A_coeff[k] * m_nodalDisplacements[pos[k][1]];
3383 }
3384 dotProduct = F0;
3385 for(MInt k = 0; k < m_noInternalNodes * nDim; k++) {
3386 dotProduct += ((m_nodalLoadVector[k] - b_calc[k]) * (m_nodalLoadVector[k] - b_calc[k]));
3387 }
3388 MPI_Allreduce(MPI_IN_PLACE, &dotProduct, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dotProduct");
3389 MFloat convergence = dotProduct / b;
3390 cout << "Convergence of iteration " << j << " is " << convergence << endl;
3391 if(convergence < m_eps) {
3392 cout << "REACHED CONVERGENCY" << endl;
3393 break;
3394 }
3395
3396 // 10. Calculate the vector r_(j+1) for the next iteration with r_(j+1) = s_j - omega_j * t
3397 for(MInt k = 0; k < m_totalNoNodes * nDim; k++) {
3398 r[k] = s[k] - omega * t[k];
3399 }
3400
3401 // 11a. We need to store 1.0/rho_j for later
3402 beta = F1 / rho;
3403
3404 // 11b. Set rho_(j+1) to the dotproduct of r_(j+1) and r_0
3405 dotProduct = F0;
3406 for(MInt k = 0; k < m_noInternalNodes * nDim; k++) {
3407 dotProduct += (r[k] * r0[k]);
3408 }
3409 MPI_Allreduce(MPI_IN_PLACE, &dotProduct, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dotProduct");
3410 rho = dotProduct;
3411
3412 // 12. Set beta_j to beta_j = rho_(j+1)/rho_j * alpha_j/omega_j
3413 beta *= rho * alpha / omega;
3414
3415 // 13. Calculate p_(j+1) for the next iteration with p_(j+1) = r_(j+1) + beta * (p_j - omega * nu)
3416 for(MInt k = 0; k < m_totalNoNodes * nDim; k++) {
3417 p[k] = r[k] + beta * (p[k] - omega * nu[k]);
3418 }
3419 }
3420 cout << setprecision(5) << endl;
3421}
3422
3423// The reordered BiCGStab method for distributed memory computer systems
3424// International Conference on Computational Science, ICCS 2010
3425// Procedia Computer Science 1 (2012) 213–218
3426template <MInt nDim>
3427void FcSolver<nDim>::solveMatrixIterativelyPreCon(MFloat* A_coeff, MInt** pos, const MInt n, const MInt m, MFloat* b,
3428 MFloat* x) {
3429 TRACE();
3430
3431 // 0. Allocate vectors required for the BiCGStab
3432 MFloatScratchSpace r0(m, "r0", AT_);
3433 r0.fill(F0);
3434 MFloatScratchSpace r(m, "r", AT_);
3435 r.fill(F0);
3436 MFloatScratchSpace nu(m, "nu", AT_);
3437 nu.fill(F0);
3438 MFloatScratchSpace nuHat(m, "nuHat", AT_);
3439 nuHat.fill(F0);
3440 MFloatScratchSpace p(m, "p", AT_);
3441 p.fill(F0);
3442 MFloatScratchSpace s(m, "s", AT_);
3443 s.fill(F0);
3444 MFloatScratchSpace t(m, "t", AT_);
3445 t.fill(F0);
3446 MFloatScratchSpace tHat(m, "tHat", AT_);
3447 tHat.fill(F0);
3448 MFloatScratchSpace z(m, "z", AT_);
3449 z.fill(F0);
3450 MFloatScratchSpace b_calc(m, "b_calc", AT_);
3451 b_calc.fill(F0);
3452
3453 MFloatScratchSpace bestSolution(m, "bestSolution", AT_);
3454 bestSolution.fill(F0);
3455
3456 MFloatScratchSpace M_inv(m, "M_inv", AT_);
3457 M_inv.fill(F0);
3458
3459 MFloat rho = F0;
3460 MFloat alpha = F0;
3461 MFloat omega = F0;
3462 MFloat beta = F0;
3463 MFloat theta = F0;
3464 MFloat phi = F0;
3465 MFloat psi = F0;
3466 MFloat b_mag = F0;
3467
3468 MFloat minConvergence = std::numeric_limits<MFloat>::max();
3469 MFloat currentConvergence = F0;
3470 MFloat previousConvergence = std::numeric_limits<MFloat>::max();
3471 MInt j = 0;
3472
3473 exchangeVector(b);
3474
3475 // 0. Initial guess of x0 is 0
3476 // 1. Calculate the dotProduct of r0 and r0
3477 // 2. Set r equal to r0
3478 for(MInt i = 0; i < m; i++) {
3479 r0[i] = b[i];
3480 r[i] = r0[i];
3481 }
3482
3483 for(MInt i = 0; i < m_noInternalNodes * nDim; i++) {
3484 rho += (r0[i] * r0[i]);
3485 b_mag += (b[i] * b[i]);
3486 }
3487
3488 // 3. M_inv is the inverse of diag(A) and we set z to M_inv * r0 and nuHat to z
3489 for(MInt k = 0; k < n; k++) {
3490 if(pos[k][0] == pos[k][1]) {
3491 M_inv[pos[k][0]] = F1 / A_coeff[k];
3492 }
3493 }
3494 exchangeVector(M_inv.data());
3495
3496 for(MInt i = 0; i < m; i++) {
3497 z[i] = M_inv[i] * r0[i];
3498 nuHat[i] = z[i];
3499 }
3500
3501 cout << setprecision(12) << endl;
3502 MPI_Allreduce(MPI_IN_PLACE, &rho, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "rho");
3503 MPI_Allreduce(MPI_IN_PLACE, &b_mag, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "b_mag");
3504
3505 if(b_mag < m_eps) return;
3506
3507 while(j < m_maxNoIterations
3508 || ((currentConvergence > minConvergence) && !approx(currentConvergence, previousConvergence, m_eps))) {
3509 // 4. Recalculate the vector nu with nu = A * nuHat
3510 for(MInt k = 0; k < m; k++) {
3511 nu[k] = F0;
3512 }
3513 for(MInt k = 0; k < n; k++) {
3514 nu[pos[k][0]] += A_coeff[k] * nuHat[pos[k][1]];
3515 }
3516 exchangeVector(nu.data());
3517
3518 // 5. Set alpha_j to the ratio of rho_j and the dotproduct of nu and r0
3519 MFloat dotProduct = F0;
3520 for(MInt k = 0; k < m_noInternalNodes * nDim; k++) {
3521 dotProduct += (nu[k] * r0[k]);
3522 }
3523 MPI_Allreduce(MPI_IN_PLACE, &dotProduct, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dotProduct");
3524 alpha = rho / dotProduct;
3525
3526 // 6. Determine the vector s with s = M_inv * nu
3527 for(MInt k = 0; k < m; k++) {
3528 s[k] = M_inv[k] * nu[k];
3529 }
3530
3531 // 7. Recalculate the vector t with t = A * tHat and tHat = z - alpha_j * s
3532 for(MInt k = 0; k < m; k++) {
3533 t[k] = F0;
3534 tHat[k] = z[k] - alpha * s[k];
3535 }
3536 for(MInt k = 0; k < n; k++) {
3537 t[pos[k][0]] += (A_coeff[k] * tHat[pos[k][1]]);
3538 }
3539 exchangeVector(t.data());
3540
3541 // 8. Calculate the new result vector x_(j+1) with
3542 // x_(j+1) = x_j + alpha_j * nuHat and check the convergence
3543 for(MInt k = 0; k < m; k++) {
3544 x[k] += alpha * nuHat[k];
3545 }
3546
3547 // 8b. Check the convergence: c = ||b - A * x|| / ||b||
3548 for(MInt k = 0; k < m; k++) {
3549 b_calc[k] = F0;
3550 }
3551 for(MInt k = 0; k < n; k++) {
3552 b_calc[pos[k][0]] += (A_coeff[k] * x[pos[k][1]]);
3553 }
3554 dotProduct = F0;
3555 for(MInt k = 0; k < m_noInternalNodes * nDim; k++) {
3556 dotProduct += ((b[k] - b_calc[k]) * (b[k] - b_calc[k]));
3557 }
3558 MPI_Allreduce(MPI_IN_PLACE, &dotProduct, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dotProduct");
3559 MFloat convergence = dotProduct / b_mag;
3560 previousConvergence = currentConvergence;
3561 currentConvergence = convergence;
3562 if(convergence < minConvergence) {
3563 minConvergence = convergence;
3564 for(MInt k = 0; k < m; k++) {
3565 bestSolution[k] = x[k];
3566 }
3567 }
3568 if(convergence < m_eps) {
3569 break;
3570 }
3571
3572 // 9. Calculate the vector r_(j+1) for the next iteration with r_(j+1) = r_j - alpha_j * nu
3573 for(MInt k = 0; k < m; k++) {
3574 r[k] = r[k] - alpha * nu[k];
3575 }
3576
3577 // 10a. Set theta_j to the dotproduct of t and r_(j+1)
3578 dotProduct = F0;
3579 for(MInt k = 0; k < m_noInternalNodes * nDim; k++) {
3580 dotProduct += (t[k] * r[k]);
3581 }
3582 MPI_Allreduce(MPI_IN_PLACE, &dotProduct, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dotProduct");
3583 theta = dotProduct;
3584
3585 // 10b. Set phi_j to the dotproduct of t and t
3586 dotProduct = F0;
3587 for(MInt k = 0; k < m_noInternalNodes * nDim; k++) {
3588 dotProduct += (t[k] * t[k]);
3589 }
3590 MPI_Allreduce(MPI_IN_PLACE, &dotProduct, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dotProduct");
3591 phi = dotProduct;
3592
3593 // 10c. Set psi_j to the dotproduct of t and r0
3594 dotProduct = F0;
3595 for(MInt k = 0; k < m_noInternalNodes * nDim; k++) {
3596 dotProduct += (t[k] * r0[k]);
3597 }
3598 MPI_Allreduce(MPI_IN_PLACE, &dotProduct, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dotProduct");
3599 psi = dotProduct;
3600
3601 // 11. Recalculate z with M_inv * t
3602 for(MInt k = 0; k < m; k++) {
3603 z[k] = M_inv[k] * t[k];
3604 }
3605
3606 // 12. Set omega_j to the ratio of theta_j and phi_j
3607 omega = theta / phi;
3608
3609 // 13. Calculate the new result vector x_(j+1) with
3610 // x_(j+1) = x_(j+1) + omega_j * tHat and check the convergence
3611 for(MInt k = 0; k < m; k++) {
3612 x[k] += omega * tHat[k];
3613 }
3614
3615 // 13b. Check the convergence: c = ||b - A * x|| / ||b||
3616 for(MInt k = 0; k < m; k++) {
3617 b_calc[k] = F0;
3618 }
3619 for(MInt k = 0; k < n; k++) {
3620 b_calc[pos[k][0]] += A_coeff[k] * x[pos[k][1]];
3621 }
3622 dotProduct = F0;
3623 for(MInt k = 0; k < m_noInternalNodes * nDim; k++) {
3624 dotProduct += ((b[k] - b_calc[k]) * (b[k] - b_calc[k]));
3625 }
3626 MPI_Allreduce(MPI_IN_PLACE, &dotProduct, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dotProduct");
3627 convergence = dotProduct / b_mag;
3628 previousConvergence = currentConvergence;
3629 currentConvergence = convergence;
3630 if(convergence < minConvergence) {
3631 minConvergence = convergence;
3632 for(MInt k = 0; k < m; k++) {
3633 bestSolution[k] = x[k];
3634 }
3635 }
3636 if(convergence < m_eps) {
3637 break;
3638 }
3639
3640 // 14. Recalculate r_(j+1) with r_(j+1) = r_(j+1) - omega * t
3641 for(MInt k = 0; k < m; k++) {
3642 r[k] = r[k] - omega * t[k];
3643 }
3644
3645 // 15a. We need to store rho in beta
3646 beta = F1 / rho;
3647
3648 // 15b. Set rho_(j+1) to -omega_j * psi_j
3649 rho = -omega * psi;
3650
3651 // 14. Recalculate z with z = tHat - omega_j * z
3652 for(MInt k = 0; k < m; k++) {
3653 z[k] = tHat[k] - omega * z[k];
3654 }
3655
3656 // 17. Set beta_j to beta_j = rho_(j+1)/rho_j * alpha_j/omega_j
3657 beta *= rho * alpha / omega;
3658
3659 // 18. Recalculate nuHat with nuHat = z + beta_j * (nuHat - omega * s)
3660 for(MInt k = 0; k < m; k++) {
3661 nuHat[k] = z[k] + beta * (nuHat[k] - omega * s[k]);
3662 }
3663 j++;
3664 cout << j << " " << minConvergence << " " << currentConvergence << " " << previousConvergence << endl;
3665 }
3666
3667 for(MInt k = 0; k < m; k++) {
3668 x[k] = bestSolution[k];
3669 }
3670 cout << "Solved SOE with " << j << " iterations and min convergence " << minConvergence << " and current convergence "
3671 << currentConvergence << endl;
3672 m_log << "Solved SOE with " << j << " iterations and min convergence " << minConvergence
3673 << " and current convergence " << currentConvergence << endl;
3674 cout << setprecision(5) << endl;
3675}
3676
3683template <MInt nDim>
3685 TRACE();
3686
3687 if(noNeighborDomains() < 1) return;
3688
3689 // Create arrays for the data offsets and data count
3690 MIntScratchSpace windowDataPerRank(noNeighborDomains(), "windowDataPerRank", AT_);
3691 MIntScratchSpace haloDataPerRank(noNeighborDomains(), "haloDataPerRank", AT_);
3692 MIntScratchSpace windowDataOffsets(noNeighborDomains() + 1, "windowDataOffsets", AT_);
3693 MIntScratchSpace haloDataOffsets(noNeighborDomains() + 1, "haloDataOffsets", AT_);
3694 windowDataPerRank.fill(0);
3695 haloDataPerRank.fill(0);
3696 windowDataOffsets.fill(0);
3697 haloDataOffsets.fill(0);
3698
3699 // Determine the data count and the data offsets
3700 MInt totalCounterWindow = 0;
3701 MInt totalCounterHalo = 0;
3702 for(MInt n = 0; n < noNeighborDomains(); n++) {
3703 MInt dataCounterWindow = 0;
3704 MInt dataCounterHalo = 0;
3705 for(MInt w = 0; w < noWindowCells(n); w++) {
3706 if(!a_isActive(windowCell(n, w))) continue;
3707 for(MInt node = 0; node < a_noNodes(windowCell(n, w)); node++) {
3708 for(MInt dim = 0; dim < nDim; dim++) {
3709 dataCounterWindow++;
3710 }
3711 }
3712 }
3713 for(MInt h = 0; h < noHaloCells(n); h++) {
3714 if(!a_isActive(haloCell(n, h))) continue;
3715 for(MInt node = 0; node < a_noNodes(haloCell(n, h)); node++) {
3716 for(MInt dim = 0; dim < nDim; dim++) {
3717 dataCounterHalo++;
3718 }
3719 }
3720 }
3721 windowDataPerRank(n) = dataCounterWindow;
3722 haloDataPerRank(n) = dataCounterHalo;
3723 totalCounterWindow += dataCounterWindow;
3724 totalCounterHalo += dataCounterHalo;
3725 windowDataOffsets(n + 1) = totalCounterWindow;
3726 haloDataOffsets(n + 1) = totalCounterHalo;
3727 }
3728
3729 // Allocate the buffers
3730 MFloat* sendBuffers{};
3731 MFloat* receiveBuffers{};
3732 MPI_Request* mpi_request{};
3733 mAlloc(sendBuffers, totalCounterWindow, "sendBuffers", F0, AT_);
3734 mAlloc(receiveBuffers, totalCounterHalo, "receiveBuffers", F0, AT_);
3735 mAlloc(mpi_request, noNeighborDomains(), "mpi_request", AT_);
3736
3737 // Gather data
3738 for(MInt n = 0; n < noNeighborDomains(); n++) {
3739 MInt cnt = 0;
3740 for(MInt j = 0; j < noWindowCells(n); j++) {
3741 if(!a_isActive(windowCell(n, j))) continue;
3742 for(MInt node = 0; node < a_noNodes(windowCell(n, j)); node++) {
3743 MInt nodeIdLocal = a_nodeIdsLocal(windowCell(n, j), node);
3744 for(MInt dim = 0; dim < nDim; dim++) {
3745 sendBuffers[windowDataOffsets(n) + cnt] = vector[nodeIdLocal * nDim + dim];
3746 cnt++;
3747 }
3748 }
3749 }
3750 }
3751
3752 // Send data
3753 for(MInt n = 0; n < noNeighborDomains(); n++) {
3754 MPI_Issend(&sendBuffers[windowDataOffsets(n)], windowDataPerRank(n), MPI_DOUBLE, neighborDomain(n), 0, mpiComm(),
3755 &mpi_request[n], AT_, "sendBuffers[n]");
3756 }
3757
3758 // Receive data
3759 MPI_Status status;
3760 for(MInt n = 0; n < noNeighborDomains(); n++) {
3761 MPI_Recv(&receiveBuffers[haloDataOffsets(n)], haloDataPerRank(n), MPI_DOUBLE, neighborDomain(n), 0, mpiComm(),
3762 &status, AT_, "receiveBuffers[n]");
3763 }
3764 for(MInt n = 0; n < noNeighborDomains(); n++) {
3765 MPI_Wait(&mpi_request[n], &status, AT_);
3766 }
3767
3768 // Scatter data
3769 for(MInt n = 0; n < noNeighborDomains(); n++) {
3770 MInt cnt = 0;
3771 for(MInt j = 0; j < noHaloCells(n); j++) {
3772 if(!a_isActive(haloCell(n, j))) continue;
3773 for(MInt node = 0; node < a_noNodes(haloCell(n, j)); node++) {
3774 MInt nodeIdLocal = a_nodeIdsLocal(haloCell(n, j), node);
3775 for(MInt dim = 0; dim < nDim; dim++) {
3776 vector[nodeIdLocal * nDim + dim] = receiveBuffers[haloDataOffsets(n) + cnt];
3777 cnt++;
3778 }
3779 }
3780 }
3781 }
3782
3783 mDeallocate(sendBuffers);
3784 mDeallocate(receiveBuffers);
3785 mDeallocate(mpi_request);
3786}
3787
3789// BELOW THIS LINE YOU CAN FIND ONLY DEBUG FUNCTIONS
3791
3810template <MInt nDim>
3811void FcSolver<nDim>::interpolateGeometryDebug(const MInt pCellId, const MFloat* z, MFloat* x) {
3812 TRACE();
3813
3814 // p holds the number of lagrangian points in one direction without the corner points
3815 const MInt p = a_pRfnmnt(pCellId);
3816
3817 // calculation of the lagrangian polynom
3818 MFloatScratchSpace L_coef(nDim, a_noNodes(pCellId) * nDim, AT_, "L_coef");
3819 L_coef.fill(F1);
3820 getDisplacementInterpolationMatrix(pCellId, z, L_coef);
3821
3822 if(m_testRun && m_polyDeg < 1) getDisplacementInterpolationMatrixDebug(pCellId, z, L_coef);
3823
3824 // Set the arrays containing the order of the surfaces, edges, and vertices
3825 // for the 2D or 3D case
3826 MInt noVertices = IPOW2(nDim);
3827 MInt noEdges = (nDim == 2) ? 0 : 12;
3828 MInt noSurfaces = (nDim == 2) ? 4 : 6;
3829
3830 // Calculate the global coordinate for each lagrangian point
3831 MFloatScratchSpace X(nDim, p + 2, AT_, "X");
3832
3833 MFloat coord[nDim] = {F0};
3834 MFloat cellHalfLength = F1B2 * c_cellLengthAtCell(pCellId);
3835
3836 for(MInt d = 0; d < nDim; d++)
3837 coord[d] = c_coordinate(pCellId, d);
3838
3839 for(MInt d = 0; d < nDim; d++) {
3840 X(d, 0) = coord[d] - cellHalfLength;
3841 X(d, p + 1) = coord[d] + cellHalfLength;
3842 }
3843
3844 for(MInt d = 0; d < nDim; d++) {
3845 for(MInt i = 1; i < p + 1; i++) {
3846 X(d, i) = coord[d] + Fd::nodePosLobattoPoints(p, i - 1) * cellHalfLength;
3847 }
3848 }
3849
3850 // Loop over all points of the current cell
3851 // depending on the point number, the point is a
3852 // vertex, edge point, surface point, or inner point
3853 // The location of the point is calculated.
3854 // The product of the lagrangian polynom and the global
3855 // coordinate of the current point is added for each point
3856 for(MInt node = 0; node < a_noNodes(pCellId); node++) {
3857 if(node < noVertices) {
3858 for(MInt d = 0; d < nDim; d++) {
3859 MInt pos = -1;
3860 if(Fd::vertexPosition(node, d) < F0) {
3861 pos = 0;
3862 } else {
3863 pos = p + 1;
3864 }
3865 MFloat L = L_coef(d, node * nDim + d);
3866 x[d] += L * X(d, pos);
3867 }
3868 } else if(node < noVertices + noEdges * p) {
3869 MInt edge = (MInt)floor((node - noVertices) / p);
3870 MInt l = node - noVertices - edge * p;
3871 for(MInt d = 0; d < nDim; d++) {
3872 MInt pos = -1;
3873 if(Fd::edgePosition(edge, d) < F0) {
3874 pos = 0;
3875 } else if(Fd::edgePosition(edge, d) > F0) {
3876 pos = p + 1;
3877 } else {
3878 pos = l + 1;
3879 }
3880 MFloat L = L_coef(d, node * nDim + d);
3881 x[d] += L * X(d, pos);
3882 }
3883 } else if(node < noVertices + noEdges * p + noSurfaces * p * p) {
3884 MInt surface = (MInt)floor((node - noVertices - noEdges * p) / (p * p));
3885 MInt l[2] = {0};
3886 l[1] = (node - noVertices - noEdges * p) % (p * p);
3887 while(l[1] >= p) {
3888 l[0]++;
3889 l[1] -= p;
3890 }
3891 MInt counter = 0;
3892 for(MInt d = 0; d < nDim; d++) {
3893 MInt pos = -1;
3894 if(Fd::surfacePosition(surface, d) < F0) {
3895 pos = 0;
3896 } else if(Fd::surfacePosition(surface, d) > F0) {
3897 pos = p + 1;
3898 } else {
3899 pos = l[counter] + 1;
3900 counter++;
3901 }
3902 MFloat L = L_coef(d, node * nDim + d);
3903 x[d] += L * X(d, pos);
3904 }
3905 } else {
3906 MInt l[3] = {0};
3907 l[2] = node - noVertices - noEdges * p - noSurfaces * p * p;
3908 while(l[2] >= (p * p)) {
3909 l[0]++;
3910 l[2] -= (p * p);
3911 }
3912 while(l[2] >= p) {
3913 l[1]++;
3914 l[2] -= p;
3915 }
3916 MInt counter = 0;
3917 for(MInt d = 0; d < nDim; d++) {
3918 MInt pos = l[counter] + 1;
3919 counter++;
3920 MFloat L = L_coef(d, node * nDim + d);
3921 x[d] += L * X(d, pos);
3922 }
3923 }
3924 }
3925}
3926
3938template <MInt nDim>
3940 TRACE();
3941
3942 for(MInt cell = 0; cell < a_noCells(); cell++) {
3943 if(!a_isActive(cell)) continue;
3944 for(MInt node = 0; node < a_noNodes(cell); node++) {
3945 MInt nodeId = a_nodeIdsLocal(cell, node);
3946 for(MInt d = 0; d < nDim; d++) {
3947 m_nodalDisplacements[nodeId * nDim + d] = 10000.0;
3948 }
3949 }
3950 }
3951
3952 for(MInt cell = 0; cell < a_noCells(); cell++) {
3953 if(!a_isActive(cell)) continue;
3954
3955 for(MInt node = 0; node < a_noNodes(cell); node++) {
3956 MFloat nodalCoord[nDim];
3957 MInt nodeId = a_nodeIdsLocal(cell, node);
3958 getCoordinatesOfNode(node, cell, nodalCoord);
3959 for(MInt d = 0; d < nDim; d++) {
3960 if(m_nodalDisplacements[nodeId * nDim + d] < 10000.0) {
3961 if(!approx(m_nodalDisplacements[nodeId * nDim + d], nodalCoord[d], m_eps)) {
3962 stringstream errorMessage;
3963 errorMessage << "ERROR in node coordinates" << m_nodalDisplacements[nodeId * nDim + d] << " "
3964 << nodalCoord[d] << " " << c_coordinate(cell, d) << endl;
3965 mTerm(1, AT_, errorMessage.str());
3966 }
3967 } else {
3968 m_nodalDisplacements[nodeId * nDim + d] = nodalCoord[d];
3969 }
3970 }
3971 }
3972 }
3973 updateDisplacements();
3974}
3975
3987template <MInt nDim>
3988void FcSolver<nDim>::lagrangianPointsJacobi(const MInt pCellId, const MFloat* z, MFloatScratchSpace& x_prime) {
3989 TRACE();
3990
3991 const MInt p = a_pRfnmnt(pCellId);
3992 MFloatScratchSpace X(nDim, p + 2, AT_, "X");
3993
3994 MFloatScratchSpace L_prime(a_noNodes(pCellId), nDim, AT_, "L_prime");
3995 for(MInt n = 0; n < a_noNodes(pCellId); n++) {
3996 for(MInt d = 0; d < nDim; d++) {
3997 L_prime(n, d) = F1;
3998 }
3999 }
4000 getDerivativeOfDisplacementInterpolationMatrix(pCellId, z, L_prime);
4001
4002 MInt noVertices = IPOW2(nDim);
4003 MInt noEdges = (nDim == 2) ? 0 : 12;
4004 MInt noSurfaces = (nDim == 2) ? 4 : 6;
4005
4006 MFloat coord[nDim] = {F0};
4007 MFloat cellHalfLength = F1B2 * c_cellLengthAtCell(pCellId);
4008
4009 for(MInt d = 0; d < nDim; d++)
4010 coord[d] = c_coordinate(pCellId, d);
4011
4012 for(MInt d = 0; d < nDim; d++) {
4013 X(d, 0) = coord[d] - cellHalfLength;
4014 X(d, p + 1) = coord[d] + cellHalfLength;
4015 }
4016
4017 for(MInt d = 0; d < nDim; d++) {
4018 for(MInt i = 1; i < p + 1; i++) {
4019 X(d, i) = coord[d] + Fd::nodePosLobattoPoints(p, i - 1) * cellHalfLength;
4020 }
4021 }
4022
4023 for(MInt node = 0; node < a_noNodes(pCellId); node++) {
4024 if(node < noVertices) {
4025 for(MInt dir = 0; dir < nDim; dir++) {
4026 for(MInt d = 0; d < nDim; d++) {
4027 MInt pos = -1;
4028 if(Fd::vertexPosition(node, d) < F0) {
4029 pos = 0;
4030 } else {
4031 pos = p + 1;
4032 }
4033 x_prime(d, dir) += L_prime(node, dir) * X(d, pos);
4034 }
4035 }
4036 } else if(node < noVertices + noEdges * p) {
4037 MInt edge = (MInt)floor((node - noVertices) / p);
4038 MInt l = node - noVertices - edge * p;
4039 for(MInt dir = 0; dir < nDim; dir++) {
4040 for(MInt d = 0; d < nDim; d++) {
4041 MInt pos = -1;
4042 if(Fd::edgePosition(edge, d) < F0) {
4043 pos = 0;
4044 } else if(Fd::edgePosition(edge, d) > F0) {
4045 pos = p + 1;
4046 } else {
4047 pos = l + 1;
4048 }
4049 x_prime(d, dir) += L_prime(node, dir) * X(d, pos);
4050 }
4051 }
4052 } else if(node < noVertices + noEdges * p + noSurfaces * p * p) {
4053 MInt surface = (MInt)floor((node - noVertices - noEdges * p) / (p * p));
4054 MInt l[2] = {0};
4055 l[1] = (node - noVertices - noEdges * p) % (p * p);
4056 while(l[1] >= p) {
4057 l[0]++;
4058 l[1] -= p;
4059 }
4060 for(MInt dir = 0; dir < nDim; dir++) {
4061 MInt counter = 0;
4062 for(MInt d = 0; d < nDim; d++) {
4063 MInt pos = -1;
4064 if(Fd::surfacePosition(surface, d) < F0) {
4065 pos = 0;
4066 } else if(Fd::surfacePosition(surface, d) > F0) {
4067 pos = p + 1;
4068 } else {
4069 pos = l[counter] + 1;
4070 counter++;
4071 }
4072 x_prime(d, dir) += L_prime(node, dir) * X(d, pos);
4073 }
4074 }
4075 } else {
4076 MInt l[3] = {0};
4077 l[2] = node - noVertices - noEdges * p - noSurfaces * p * p;
4078 while(l[2] >= (p * p)) {
4079 l[0]++;
4080 l[2] -= (p * p);
4081 }
4082 while(l[2] >= p) {
4083 l[1]++;
4084 l[2] -= p;
4085 }
4086 for(MInt dir = 0; dir < nDim; dir++) {
4087 MInt counter = 0;
4088 for(MInt d = 0; d < nDim; d++) {
4089 MInt pos = l[counter] + 1;
4090 counter++;
4091 x_prime(d, dir) += L_prime(node, dir) * X(d, pos);
4092 }
4093 }
4094 }
4095 }
4096}
4097
4098template <MInt nDim>
4100 MFloatScratchSpace& L_coef_lagrange) {
4101 TRACE();
4102
4103 MFloatScratchSpace L_coef(a_noNodes(pCellId), AT_, "L_coef");
4104
4105 if(a_noNodes(pCellId) != IPOW2(nDim)) TERMM(1, "Not implemented for solver.");
4106 if(a_pRfnmnt(pCellId) != 0) TERMM(1, "Not implemented for solver.");
4107
4108 for(MInt dim = 0; dim < nDim; dim++) {
4109 for(MInt i = 0; i < IPOW2(nDim); i++) {
4110 L_coef(i) = FFPOW2(nDim);
4111 for(MInt d = 0; d < nDim; d++) {
4112 L_coef(i) *= (F1 + Fd::vertexPosition(i, d) * z[d]);
4113 }
4114 for(MInt d = 0; d < nDim; d++) {
4115 MFloat L = L_coef_lagrange(dim, i * nDim + d);
4116 if(d == dim) {
4117 if(!approx(L_coef(i), L, 1e-14)) {
4118 stringstream errorMessage;
4119 errorMessage << "ERROR!! Displacement Interpolation for x " << i << " is: " << L_coef(i) << " and " << L
4120 << endl;
4121 mTerm(1, AT_, errorMessage.str());
4122 }
4123 } else {
4124 if(!approx(F0, L, 1e-14)) {
4125 stringstream errorMessage;
4126 errorMessage << "ERROR!! Displacement Interpolation for x " << i << " is: " << F0 << " and " << L << endl;
4127 mTerm(1, AT_, errorMessage.str());
4128 }
4129 }
4130 }
4131 }
4132 }
4133}
4134
4135template <MInt nDim>
4136void FcSolver<nDim>::getJacobiMatrixDebug(const MInt pCellId, const MFloat* z, MFloatScratchSpace& jacobi_lagrange) {
4137 TRACE();
4138
4139 MFloatScratchSpace jacobi(nDim * nDim, AT_, "jacobi");
4140
4141 if(a_noNodes(pCellId) != IPOW2(nDim)) TERMM(1, "Not implemented for solver.");
4142 if(a_pRfnmnt(pCellId) != 0) TERMM(1, "Not implemented for solver.");
4143
4144 MFloat halfLength = c_cellLengthAtCell(pCellId) * F1B2;
4145 for(MInt d1 = 0; d1 < nDim; d1++) { // Derivative direction
4146 for(MInt d2 = 0; d2 < nDim; d2++) { // Coordinate direction
4147 jacobi(d1 * nDim + d2) = F0;
4148 for(MInt n = 0; n < IPOW2(nDim); n++) { // Number of vertices
4149 MFloat cCoord = c_coordinate(pCellId, d1) + Fd::vertexPosition(n, d1) * halfLength;
4150 MFloat jac = cCoord * FFPOW2(nDim);
4151 for(MInt d = 0; d < nDim; d++) {
4152 if(d == d2) {
4153 jac *= Fd::vertexPosition(n, d);
4154 } else {
4155 jac *= (F1 + Fd::vertexPosition(n, d) * z[d]);
4156 }
4157 }
4158 jacobi(d1 * nDim + d2) += jac;
4159 }
4160 }
4161 }
4162 for(MInt d1 = 0; d1 < nDim; d1++) { // Derivative direction
4163 for(MInt d2 = 0; d2 < nDim; d2++) { // Coordinate direction
4164 if(!approx(jacobi(d1 * nDim + d2), F0, 1e-10)) {
4165 MFloat inv = F1 / jacobi(d1 * nDim + d2);
4166 if(!approx(inv, jacobi_lagrange(d1 * nDim + d2), 1e-10)) {
4167 stringstream errorMessage;
4168 errorMessage << "ERROR!! Jacobi for x" << d1 << " and z" << d2 << " is: " << jacobi(d1 * nDim + d2) << " and "
4169 << F1 / jacobi_lagrange(d1 * nDim + d2) << endl;
4170 mTerm(1, AT_, errorMessage.str());
4171 }
4172 }
4173 }
4174 }
4175}
4176
4177template <MInt nDim>
4179 MFloatScratchSpace& strain_lagrange) {
4180 TRACE();
4181
4182 MFloatScratchSpace strain(m_noStrains, nDim * a_noNodes(pCellId), AT_, "strain");
4183 strain.fill(F0);
4184
4185 MFloatScratchSpace L_prime(a_noNodes(pCellId), nDim, AT_, "L_prime");
4186 MFloatScratchSpace L_prime_mul_inv_jac(a_noNodes(pCellId), nDim, AT_, "L_prime_mul_inv_jac");
4187
4188 MFloatScratchSpace jacobi(nDim * nDim, AT_, "jacobi");
4189
4190 if(a_noNodes(pCellId) != IPOW2(nDim)) TERMM(1, "Not implemented for solver.");
4191 if(a_pRfnmnt(pCellId) != 0) TERMM(1, "Not implemented for solver.");
4192
4193 MFloat halfLength = c_cellLengthAtCell(pCellId) * F1B2;
4194 for(MInt d1 = 0; d1 < nDim; d1++) {
4195 for(MInt d2 = 0; d2 < nDim; d2++) {
4196 jacobi(d1 * nDim + d2) = F0;
4197 for(MInt n = 0; n < IPOW2(nDim); n++) {
4198 MFloat cCoord = c_coordinate(pCellId, d1) + Fd::vertexPosition(n, d1) * halfLength;
4199 MFloat jac = cCoord * FFPOW2(nDim);
4200 for(MInt d = 0; d < nDim; d++) {
4201 if(d == d2) {
4202 jac *= Fd::vertexPosition(n, d);
4203 } else {
4204 jac *= (F1 + Fd::vertexPosition(n, d) * z[d]);
4205 }
4206 }
4207 jacobi(d1 * nDim + d2) += jac;
4208 }
4209 }
4210 }
4211 maia::math::invert(jacobi.getPointer(), nDim, nDim);
4212
4213 for(MInt n = 0; n < a_noNodes(pCellId); n++) {
4214 for(MInt d1 = 0; d1 < nDim; d1++) {
4215 MFloat derivative = FFPOW2(nDim);
4216 for(MInt d2 = 0; d2 < nDim; d2++) {
4217 if(d2 == d1) {
4218 derivative *= Fd::vertexPosition(n, d2);
4219 } else {
4220 derivative *= (F1 + Fd::vertexPosition(n, d2) * z[d2]);
4221 }
4222 }
4223 L_prime(n, d1) = derivative;
4224 }
4225 }
4226
4227 for(MInt n = 0; n < a_noNodes(pCellId); n++) {
4228 for(MInt d1 = 0; d1 < nDim; d1++) {
4229 L_prime_mul_inv_jac(n, d1) = F0;
4230 for(MInt d2 = 0; d2 < nDim; d2++) {
4231 L_prime_mul_inv_jac(n, d1) += (L_prime(n, d2) * jacobi(d2 * nDim + d1));
4232 }
4233 }
4234 }
4235
4236 for(MInt s = 0; s < nDim; s++) {
4237 for(MInt n = 0; n < a_noNodes(pCellId); n++) {
4238 for(MInt d = 0; d < nDim; d++) {
4239 if(s == d) {
4240 strain(s, n * nDim + d) = L_prime_mul_inv_jac(n, d);
4241 }
4242 }
4243 }
4244 }
4245 for(MInt s = 0; s < m_noStrains - nDim; s++) {
4246 for(MInt n = 0; n < a_noNodes(pCellId); n++) {
4247 for(MInt d = 0; d < nDim; d++) {
4248 if(s == d) {
4249 if((d + 1) < nDim) {
4250 strain(s + nDim, n * nDim + d) = L_prime_mul_inv_jac(n, d + 1);
4251 strain(s + nDim, n * nDim + d + 1) = L_prime_mul_inv_jac(n, d);
4252 } else {
4253 strain(s + nDim, n * nDim + d) = L_prime_mul_inv_jac(n, 0);
4254 strain(s + nDim, n * nDim + 0) = L_prime_mul_inv_jac(n, d);
4255 }
4256 }
4257 }
4258 }
4259 }
4260 for(MInt s = 0; s < m_noStrains; s++) {
4261 for(MInt n = 0; n < a_noNodes(pCellId) * nDim; n++) {
4262 if(!approx(strain(s, n), strain_lagrange(s, n), m_eps)) {
4263 stringstream errorMessage;
4264 errorMessage << "ERROR!! Strain Interpolation for s " << s << " and x " << n << " is: " << strain(s, n)
4265 << " and " << strain_lagrange(s, n) << endl;
4266 mTerm(1, AT_, errorMessage.str());
4267 }
4268 }
4269 }
4270}
4271
4273// ABOVE THIS LINE YOU CAN FIND ONLY DEBUG FUNCTIONS
4275
4276
4277template class FcSolver<2>;
4278template class FcSolver<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
MBool mDeallocate(T *&a)
deallocates the memory previously allocated for element 'a'
Definition: alloc.h:544
This class represents a structure solver using the Finite Cell Method.
Definition: fcsolver.h:27
void allocateNodeVectors()
void solveSystemOfEquations()
void solveMatrixIteratively(MFloat *A_coeff, MInt **pos, const MInt n)
void updateCellCollectorFromGrid()
void consistencyCheck()
void postTimeStep() override
void setCellWeights(MFloat *solverCellWeight) override
Set cell weights.
void fillDisplacementVectorWithCoords()
void reIntAfterRestart(MBool doneRestart)
void saveRestartStrainsOnly(const MChar *fileName, const MChar *gridInputFileName, MInt *recalcIdTree=nullptr)
void getMaterialTensor(MFloatScratchSpace &C, const MInt pCellId, const MInt node=-1)
void initJacobianMatrix()
void getStrainInterpolationMatrix(MFloatScratchSpace &Be, const MInt pCellId, const MFloat *z)
void saveSolverSolution(MBool forceOutput, const MBool finalTimeStep) override
void createCompressedMatrix()
void computeAssembledSystemMatrix(MFloatScratchSpace &Ke, const MInt pCellId)
void createElementToNodeMappingGlobal()
void createElementToNodeMapping()
void exchangeVector(MFloat *vector)
void calcElementDisplacements()
void getInternalLoadsFromStresses()
void getReactionForces()
void lhsBnd()
void rhsBnd()
FcSolver(MInt id, GridProxy &gridProxy_, Geometry< nDim > &geometry_, const MPI_Comm comm)
void getStressesAtPoint(const MInt cellId, const MFloat *z, const MFloat *displ, MFloat *stresses)
void getDisplacementInterpolationMatrix(const MInt pCellId, const MFloat *z, MFloatScratchSpace &x)
void initTimer()
void getNodalStiffnessMatrix(const MInt pCellId, const MInt node, MFloatScratchSpace &Ke, MInt *nodePos, MFloat *z, MFloat determinant, const MFloat alpha, const MInt subCellLevel)
void resetDisplacements(const MInt mode=-1)
void rhs()
void calculateStiffnessMatrix()
void getCoordinatesOfNode(MInt node, MInt cell, MFloat *coordinates)
void resetLoadVector(const MInt mode=-1)
void interpolateGeometry(const MInt pCellId, const MFloat *x, MFloat *z)
void averageTimer()
void getStrainsAtPoint(const MInt cellId, const MFloat *z, const MFloat *displ, MFloat *strains)
void transformToLocal(const MInt pCellId, const MFloat *z, MFloat *x)
MInt initSolver
Definition: fcsolver.h:471
void consistencyCheck2()
void deactivateCells()
~FcSolver() override
void reorderLocalNodeIds()
void exchangeNodeIds(MInt currentDomain)
void updateLoadVector(const MFloat lambda=F1)
void computeAssembledBndryMatrix(MFloatScratchSpace &Bndry, const MInt pCellId)
void finalizeInitSolver() override
void interpolateSubCellGeometry(const MInt pCellId, const MFloat *z, MFloat *x, const MInt subCellLevel, const MFloat *subCellCoord)
void updateDisplacements()
void writeRestartFile(const MBool writeRestart, const MBool writeBackup, const MString gridFileName, MInt *recalcIdTree) override
void lhs()
void getDerivativeOfDisplacementInterpolationMatrix(const MInt pCellId, const MFloat *z, MFloatScratchSpace &x)
void calcElementStrains()
void getElementMatrix(MFloatScratchSpace &Ke, const MInt pCellId, const MFloat alpha, const MInt subCellLevel, const MFloat *subCellCoord=nullptr)
void preTimeStep() override
void interpolateGeometryDebug(const MInt pCellId, const MFloat *z, MFloat *x)
void setIntegrationWeights()
void getStrainInterpolationMatrixDebug(const MInt pCellId, const MFloat *z, MFloatScratchSpace &strain_lagrange)
void lagrangianPointsJacobi(const MInt pCellId, const MFloat *z, MFloatScratchSpace &x)
void getDisplacementInterpolationMatrixDebug(const MInt pCellId, const MFloat *z, MFloatScratchSpace &L_coef_lagrange)
void getDisplacementsAtPoint(const MInt cellId, const MFloat *z, const MFloat *displ, MFloat *result)
void calcElementStresses()
void solveMatrixIterativelyPreCon(MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
void getJacobiMatrixDebug(const MInt pCellId, const MFloat *z, MFloatScratchSpace &jacobi_lagrange)
MInt solutionStep
Definition: fcsolver.h:473
MBool prepareRestart(MBool writeRestart, MBool &writeGridRestart) override
Prepare the solvers for a grid-restart.
void assembleFinalMatrix()
This class is a ScratchSpace.
Definition: scratch.h:758
void fill(T val)
fill the scratch with a given value
Definition: scratch.h:311
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
Definition: enums.cpp:20
@ LEGENDRE_INTERP
Definition: enums.h:267
@ EQUIDIST_LAGRANGE_INTERP
Definition: enums.h:267
@ LAGRANGE_INTERP
Definition: enums.h:267
@ EQUIDIST_LEGENDRE_INTERP
Definition: enums.h:267
@ MAIA_NONLINEAR_BAR
Definition: enums.h:100
@ MAIA_LINEAR_ELASTIC
Definition: enums.h:99
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
MInt globalTimeStep
InfoOutFile m_log
constexpr MLong IPOW2(MInt x)
constexpr MFloat FFPOW2(MInt x)
int32_t MInt
Definition: maiatypes.h:62
std::basic_string< char > MString
Definition: maiatypes.h:55
double MFloat
Definition: maiatypes.h:52
bool MBool
Definition: maiatypes.h:58
char MChar
Definition: maiatypes.h:56
MInt id
Definition: maiatypes.h:71
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status, const MString &name, const MString &varname)
same as MPI_Recv
int MPI_Barrier(MPI_Comm comm, const MString &name)
same as MPI_Barrier
int MPI_Issend(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_Issend
int MPI_Wait(MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Wait
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
void const MInt cellId
Definition: collector.h:239
constexpr std::underlying_type< FcCell >::type p(const FcCell property)
Converts property name to underlying integer value.
IdType index(const FloatType *const x, const IdType level)
Return Hilbert index for given location and level in 2D or 3D.
Definition: hilbert.h:165
MFloat determinant(std::array< T, N > &m)
Definition: maiamath.cpp:130
void multiplySparseMatrixVector(MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
Definition: maiamath.cpp:431
void invert(MFloat *A, const MInt m, const MInt n)
Definition: maiamath.cpp:171
void solveSparseMatrix(MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
Definition: maiamath.cpp:315
void solveSparseMatrixIterative(MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
Definition: maiamath.cpp:357
MFloat norm(const std::array< T, N > &u)
Definition: maiamath.h:148
void multiplyMatrices(MFloatScratchSpace &m1, MFloatScratchSpace &m2, MFloatScratchSpace &result, MInt m1_n, MInt m1_m, MInt m2_n, MInt m2_m)
Definition: maiamath.h:297
void calcEigenValues(MFloat A[3][3], MFloat w[3])
Definition: maiamath.cpp:475
void exchangeData(const MInt noNghbrDomains, const MInt *const nghbrDomains, const MInt *const noHaloCells, const MInt **const, const MInt *const noWindowCells, const MInt **const windowCells, const MPI_Comm comm, const U *const data, U *const haloBuffer, const MInt noDat=1)
Generic exchange of data.
Definition: mpiexchange.h:295
Namespace for auxiliary functions/classes.
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292