OOFEM 3.0
Loading...
Searching...
No Matches
prescribedgradientbcweak.C
Go to the documentation of this file.
1/*
2 *
3 * ##### ##### ###### ###### ### ###
4 * ## ## ## ## ## ## ## ### ##
5 * ## ## ## ## #### #### ## # ##
6 * ## ## ## ## ## ## ## ##
7 * ## ## ## ## ## ## ## ##
8 * ##### ##### ## ###### ## ##
9 *
10 *
11 * OOFEM : Object Oriented Finite Element Code
12 *
13 * Copyright (C) 1993 - 2025 Borek Patzak
14 *
15 *
16 *
17 * Czech Technical University, Faculty of Civil Engineering,
18 * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19 *
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
29 *
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 */
34
36#include "classfactory.h"
37#include "node.h"
38#include "masterdof.h"
39#include "element.h"
40#include "feinterpol.h"
41#include "feinterpol2d.h"
42#include "gausspoint.h"
43#include "sparsemtrx.h"
46#include "spatiallocalizer.h"
47#include "geometry.h"
48#include "dynamicinputrecord.h"
49#include "timestep.h"
50#include "function.h"
51#include "engngm.h"
52#include "mathfem.h"
53#include "sparselinsystemnm.h"
57
58#include "timer.h"
59
60#include "xfem/XFEMDebugTools.h"
61
62#include <cmath>
63#include <string>
64#include <sstream>
65#include <iterator>
66
67#ifdef _OPENMP
68#include <omp.h>
69#endif
70
71
72namespace oofem {
73
75{
76 mFirstNode->giveLocationArray({Trac_u, Trac_v}, rows, s);
77}
78
79void TracSegArray :: setupIntegrationRuleOnEl()
80{
81 mIntRule = std::make_unique<DiscontinuousSegmentIntegrationRule>(1, nullptr, mInteriorSegmentsFine);
82
83 int numPointsPerSeg = 1;
84 mIntRule->SetUpPointsOnLine(numPointsPerSeg, _PlaneStrain);
85}
86
87
88PrescribedGradientBCWeak :: PrescribedGradientBCWeak(int n, Domain *d) :
91 mTractionDofIDs( {Trac_u, Trac_v} ),
92 mDispLockDofIDs( {LMP_u, LMP_v} ),
93 mRegularDispDofIDs( {D_u, D_v} ),
94 mTractionInterpOrder(0),
95 mNumTractionNodesAtIntersections(1),
96 mTractionNodeSpacing(1),
97 mMeshIsPeriodic(false),
98 mDuplicateCornerNodes(false),
99 mTangDistPadding(0.0),
100 mTracDofScaling(1.0e0),
101 mLockNodeInd(0),
102 mDispLockScaling(1.0),
103 mSpringNodeInd1(-1),
104 mSpringNodeInd2(-1),
105 mSpringPenaltyStiffness(1.0e-3),
106 mPeriodicityNormal(Vec2(0.0, 1.0)),
107 mDomainSize(0.0),
108 mMirrorFunction(0)
109{
110 if ( d ) {
111 // Compute bounding box of the domain
112 computeDomainBoundingBox(* d, mLC, mUC);
113 }
114}
115
116
117PrescribedGradientBCWeak :: ~PrescribedGradientBCWeak()
118{
119 clear();
120}
121
122
123void PrescribedGradientBCWeak :: clear()
124{
125 mpTracElNew.clear();
126 mpDisplacementLock = nullptr;
127}
128
129//#define DAMAGE_TEST
130
131int PrescribedGradientBCWeak :: giveNumberOfInternalDofManagers()
132{
133 int numDMan = mpTracElNew.size();
134
135 if ( mpDisplacementLock ) {
136 numDMan++;
137 }
138
139 return numDMan;
140}
141
142
143DofManager *PrescribedGradientBCWeak :: giveInternalDofManager(int i)
144{
145 if ( i - 1 < int( mpTracElNew.size() ) ) {
146 return mpTracElNew [ i - 1 ].mFirstNode.get();
147 } else {
148 OOFEM_ERROR("return mpDisplacementLock")
149 //return mpDisplacementLock.get();
150 }
151}
152
153
154void PrescribedGradientBCWeak :: initializeFrom(InputRecord &ir)
155{
156 ActiveBoundaryCondition :: initializeFrom(ir);
157 PrescribedGradientHomogenization :: initializeFrom(ir);
158
160// printf("mTractionInterpOrder: %d\n", mTractionInterpOrder);
161
163// printf("mNumTractionNodesAtIntersections: %d\n", mNumTractionNodesAtIntersections);
164
166 OOFEM_ERROR("mNumTractionNodesAtIntersections > 1 is not allowed if mTractionInterpOrder == 0.")
167 }
168
170// printf("mTractionNodeSpacing: %d\n", mTractionNodeSpacing);
171
172 int duplicateCorners = 0;
174// printf("duplicateCorners: %d\n", duplicateCorners);
175
176 if ( duplicateCorners == 1 ) {
178 } else {
179 mDuplicateCornerNodes = false;
180 }
181
182 mTangDistPadding = 0.0;
184// printf("mTangDistPadding: %e\n", mTangDistPadding);
185
187// printf("mTracDofScaling: %e\n", mTracDofScaling );
188
190 mPeriodicityNormal.normalize();
191// printf("mPeriodicityNormal: "); mPeriodicityNormal.printYourself();
192
193
195// printf("mMirrorFunction: %d\n", mMirrorFunction );
196
197 if ( mMirrorFunction == 0 ) {
198 mPeriodicityNormal = Vec2(0.0, 1.0);
199 }
200}
201
202
226
227void PrescribedGradientBCWeak :: postInitialize()
228{}
229
230void PrescribedGradientBCWeak :: assembleVector(FloatArray &answer, TimeStep *tStep,
231 CharType type, ValueModeType mode,
232 const UnknownNumberingScheme &s,
233 FloatArray *eNorm,
234 void* lock)
235{
236 int dim = domain->giveNumberOfSpatialDimensions();
237
238 if ( type == ExternalForcesVector ) {
239 // The external force vector is given by
240 // f_ext = int N^trac H . (x - x_c)
241
242
243 for ( auto &el : mpTracElNew ) {
244
245 FloatArray contrib;
246 computeExtForceElContrib(contrib, el, dim, tStep);
247
248 IntArray rows;
249 el.giveTractionLocationArray(rows, type, s);
250#ifdef _OPENMP
251 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
252#endif
253 answer.assemble(contrib, rows);
254#ifdef _OPENMP
255 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
256#endif
257
258 }
259
260 } else if ( type == InternalForcesVector ) {
261
262 for ( auto &el : mpTracElNew ) {
263
264 for ( auto &gp: *el.mIntRule ) {
265
266 // Contribution on gamma_plus
267 FloatArray contrib_disp, contrib_trac;
268 IntArray disp_loc_array, trac_loc_array;
269 computeIntForceGPContrib(contrib_disp, disp_loc_array, contrib_trac, trac_loc_array, el, *gp, dim, tStep, gp->giveGlobalCoordinates(), 1.0, mode, type, s);
270#ifdef _OPENMP
271 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
272#endif
273 answer.assemble(contrib_disp, disp_loc_array);
274 answer.assemble(contrib_trac, trac_loc_array);
275#ifdef _OPENMP
276 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
277#endif
278
279 // Contribution on gamma_minus
280 contrib_disp.clear(); contrib_trac.clear();
281 disp_loc_array.clear(); trac_loc_array.clear();
282 FloatArray xMinus;
283 this->giveMirroredPointOnGammaMinus(xMinus, gp->giveGlobalCoordinates());
284 computeIntForceGPContrib(contrib_disp, disp_loc_array, contrib_trac, trac_loc_array, el, *gp, dim, tStep, xMinus, -1.0, mode, type, s);
285#ifdef _OPENMP
286 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
287#endif
288 answer.assemble(contrib_disp, disp_loc_array);
289 answer.assemble(contrib_trac, trac_loc_array);
290#ifdef _OPENMP
291 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
292#endif
293
294 }
295 }
296
297 if ( mpDisplacementLock ) {
298 IntArray dispLockRows;
299 mpDisplacementLock->giveLocationArray(giveDispLockDofIDs(), dispLockRows, s);
300
301
302 int lockNodePlaceInArray = domain->giveDofManPlaceInArray(mLockNodeInd);
303 FloatArray nodeUnknowns;
304 domain->giveDofManager(lockNodePlaceInArray)->giveUnknownVector(nodeUnknowns,this->giveRegularDispDofIDs(), mode, tStep);
305
306 FloatArray fe_dispLock(domain->giveNumberOfSpatialDimensions());
307 for ( int i = 0; i < domain->giveNumberOfSpatialDimensions(); i++ ) {
308 fe_dispLock[i] = nodeUnknowns [ i ];
309 }
310
311 fe_dispLock.times(mDispLockScaling);
312#ifdef _OPENMP
313 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
314#endif
315 answer.assemble(fe_dispLock, dispLockRows);
316#ifdef _OPENMP
317 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
318#endif
319 }
320
321 }
322}
323
324void PrescribedGradientBCWeak :: computeExtForceElContrib(FloatArray &oContrib, TracSegArray &iEl, int iDim, TimeStep *tStep)
325{
326
327 oContrib.clear();
328 FloatArray contrib_gp;
329
330 for ( auto &gp: *iEl.mIntRule ) {
331
332 // Fetch global coordinate x
333 const FloatArray &x = gp->giveGlobalCoordinates();
334
335 // Compute H.[x]
336 FloatArray temp;
338
339 FloatArray Hx;
340 FloatMatrix grad2D = mGradient;
341 grad2D.resizeWithData(2,2);
342 Hx.beProductOf(grad2D, temp);
343
344
345 // For now, assume piecewise constant approx
346 FloatArray Ntrac = Vec1 ( 1.0*mTracDofScaling );
347
348 // N-matrix
349 FloatMatrix Nmat;
350 Nmat.beNMatrixOf(Ntrac, iDim);
351
352
353 // Assemble contribution to the global vector directly
354 contrib_gp.beTProductOf(Nmat, Hx);
355 double detJ = 0.5 * iEl.giveLength();
356 double loadLevel = this->giveTimeFunction()->evaluateAtTime(tStep->giveTargetTime());
357 contrib_gp.times(-detJ * gp->giveWeight()*loadLevel);
358
359 oContrib.add(contrib_gp);
360 }
361
362}
363
364void PrescribedGradientBCWeak :: computeIntForceGPContrib(FloatArray &oContrib_disp, IntArray &oDisp_loc_array, FloatArray &oContrib_trac, IntArray &oTrac_loc_array,TracSegArray &iEl, GaussPoint &iGP, int iDim, TimeStep *tStep, const FloatArray &iBndCoord, const double &iScaleFac, ValueModeType mode, CharType type, const UnknownNumberingScheme &s)
365{
366
367 SpatialLocalizer *localizer = domain->giveSpatialLocalizer();
368
369 FloatMatrix contrib;
370 assembleTangentGPContributionNew(contrib, iEl, iGP, iScaleFac, iBndCoord);
371
372 // Compute vector of traction unknowns
373 FloatArray tracUnknowns;
374 iEl.mFirstNode->giveUnknownVector(tracUnknowns, giveTracDofIDs(), mode, tStep);
375
376 iEl.giveTractionLocationArray(oTrac_loc_array, type, s);
377
378 FloatArray dispElLocCoord, closestPoint;
379 Element *dispEl = localizer->giveElementClosestToPoint(dispElLocCoord, closestPoint, iBndCoord );
380
381 // Compute vector of displacement unknowns
382 int numDMan = dispEl->giveNumberOfDofManagers();
383 std::vector<double> dispUnknowns_;
384 for ( int i = 1; i <= numDMan; i++ ) {
385 FloatArray nodeUnknowns;
386 DofManager *dMan = dispEl->giveDofManager(i);
387
389 if ( domain->hasXfemManager() ) {
390 XfemManager *xMan = domain->giveXfemManager();
391 dispIDs.followedBy(xMan->giveEnrichedDofIDs(*dMan));
392 }
393
394 dMan->giveUnknownVector(nodeUnknowns, dispIDs,mode, tStep);
395 dispUnknowns_.insert(dispUnknowns_.end(),nodeUnknowns.begin(),nodeUnknowns.end());
396
397 }
398
399 dispEl->giveLocationArray(oDisp_loc_array, s);
400
401
402 oContrib_disp.beTProductOf(contrib, tracUnknowns);
403 oContrib_disp.negated();
404
405 FloatArray dispUnknowns=FloatArray::fromVector(dispUnknowns_);
406 oContrib_trac.beProductOf(contrib, dispUnknowns);
407 oContrib_trac.negated();
408}
409
410void PrescribedGradientBCWeak :: assemble( SparseMtrx &answer,
411 TimeStep *tStep,
412 CharType type,
413 const UnknownNumberingScheme &r_s,
414 const UnknownNumberingScheme &c_s,
415 double scale,
416 void* lock)
417{
418 std::vector<FloatArray> gpCoordArray;
419
420 if ( type == TangentStiffnessMatrix || type == SecantStiffnessMatrix || type == ElasticStiffnessMatrix ) {
421
422 for ( auto &el : mpTracElNew ) {
423
424 for ( auto &gp: *el.mIntRule ) {
425
426 gpCoordArray.push_back( gp->giveGlobalCoordinates() );
427 assembleGPContrib(answer, tStep, type, r_s, c_s, el, *gp, scale);
428 }
429 }
430
431 if ( mpDisplacementLock ) {
432 int nsd = domain->giveNumberOfSpatialDimensions();
433 FloatMatrix KeDispLock(nsd, nsd);
434 KeDispLock.beUnitMatrix();
435 KeDispLock.times(mDispLockScaling);
436
437 int placeInArray = domain->giveDofManPlaceInArray(mLockNodeInd);
438 DofManager *node = domain->giveDofManager(placeInArray);
439
440 IntArray lockRows, lockCols, nodeRows, nodeCols;
441 mpDisplacementLock->giveLocationArray(giveDispLockDofIDs(), lockRows, r_s);
442 node->giveLocationArray(giveRegularDispDofIDs(), nodeRows, r_s);
443
444 mpDisplacementLock->giveLocationArray(giveDispLockDofIDs(), lockCols, c_s);
445 node->giveLocationArray(giveRegularDispDofIDs(), nodeCols, c_s);
446#ifdef _OPENMP
447 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
448#endif
449 answer.assemble(lockRows, nodeCols, KeDispLock);
450 answer.assemble(nodeRows, lockCols, KeDispLock);
451#ifdef _OPENMP
452 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
453#endif
454
455 FloatMatrix KZero( lockRows.giveSize(), lockCols.giveSize() );
456 KZero.zero();
457 KZero.times(scale);
458#ifdef _OPENMP
459 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
460#endif
461 answer.assemble(lockRows, lockCols, KZero);
462#ifdef _OPENMP
463 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
464#endif
465 }
466
467
468 int nsd = domain->giveNumberOfSpatialDimensions();
469 FloatMatrix KeDispLock(nsd, nsd);
470 KeDispLock.beUnitMatrix();
471 KeDispLock.times(mSpringPenaltyStiffness);
472
473// printf("mSpringNodeInd1: %d\n", mSpringNodeInd1);
474 int placeInArray = domain->giveDofManPlaceInArray(mSpringNodeInd1);
475 DofManager *node1 = domain->giveDofManager(placeInArray);
476
477 IntArray nodeRows, nodeCols;
478 node1->giveLocationArray(giveRegularDispDofIDs(), nodeRows, r_s);
479 node1->giveLocationArray(giveRegularDispDofIDs(), nodeCols, c_s);
480 KeDispLock.times(scale);
481#ifdef _OPENMP
482 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
483#endif
484 answer.assemble(nodeRows, nodeCols, KeDispLock);
485#ifdef _OPENMP
486 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
487#endif
488
489
490 } else {
491 printf("Skipping assembly in PrescribedGradientBCWeak::assemble().\n");
492 }
493
494// std :: string fileName("TracGpCoord.vtk");
495// XFEMDebugTools :: WritePointsToVTK(fileName, gpCoordArray);
496}
497
498void PrescribedGradientBCWeak :: assembleExtraDisplock(SparseMtrx &answer, TimeStep *tStep,
499 CharType type, const UnknownNumberingScheme &r_s, const UnknownNumberingScheme &c_s)
500
501{
502// printf("Entering PrescribedGradientBCWeak :: assembleExtraDisplock.\n");
503
504#if 1
505
506 int nsd = domain->giveNumberOfSpatialDimensions();
507 FloatMatrix KeDispLock(nsd, nsd);
508 KeDispLock.zero();
509
510 // Lock in y-direction to get rid of rigid body rotation.
511 double scaling = 1.0e0;
512 KeDispLock.at(2,2) = mSpringPenaltyStiffness*scaling;
513
514 IntArray nodeRows, nodeCols;
515
516// printf("mSpringNodeInd2: %d\n", mSpringNodeInd2);
517 int placeInArray = domain->giveDofManPlaceInArray(mSpringNodeInd2);
518 DofManager *node1 = domain->giveDofManager(placeInArray);
519
520 node1->giveLocationArray(giveRegularDispDofIDs(), nodeRows, r_s);
521 node1->giveLocationArray(giveRegularDispDofIDs(), nodeCols, c_s);
522
523 answer.assemble(nodeRows, nodeCols, KeDispLock);
524
525
526#else
527 int nsd = domain->giveNumberOfSpatialDimensions();
528 FloatMatrix KeDispLock(2*nsd, 2*nsd);
529 KeDispLock.zero();
530
531 // Lock in y-direction to get rid of rigid body rotation.
532 double scaling = 1.0e0;
533 KeDispLock.at(2,2) = mSpringPenaltyStiffness*scaling;
534 KeDispLock.at(2,nsd+1) = -mSpringPenaltyStiffness*scaling;
535 KeDispLock.at(nsd+1,2) = -mSpringPenaltyStiffness*scaling;
536 KeDispLock.at(nsd+1,nsd+1) = mSpringPenaltyStiffness*scaling;
537// KeDispLock.times(mSpringPenaltyStiffness);
538
539 IntArray nodeRows, nodeCols;
540
541
542 int placeInArray = domain->giveDofManPlaceInArray(mSpringNodeInd2);
543 DofManager *node1 = domain->giveDofManager(placeInArray);
544
545 IntArray nodeRows1, nodeCols1;
546 node1->giveLocationArray(giveRegularDispDofIDs(), nodeRows1, r_s);
547 node1->giveLocationArray(giveRegularDispDofIDs(), nodeCols1, c_s);
548
549 nodeRows.followedBy(nodeRows1);
550 nodeCols.followedBy(nodeCols1);
551
552
553 placeInArray = domain->giveDofManPlaceInArray(mSpringNodeInd3);
554 DofManager *node2 = domain->giveDofManager(placeInArray);
555
556 IntArray nodeRows2, nodeCols2;
557 node2->giveLocationArray(giveRegularDispDofIDs(), nodeRows2, r_s);
558 node2->giveLocationArray(giveRegularDispDofIDs(), nodeCols2, c_s);
559
560 nodeRows.followedBy(nodeRows2);
561 nodeCols.followedBy(nodeCols2);
562
563 answer.assemble(nodeRows, nodeCols, KeDispLock);
564#endif
565
566}
567
568void PrescribedGradientBCWeak :: assembleGPContrib(SparseMtrx &answer, TimeStep *tStep,
569 CharType type, const UnknownNumberingScheme &r_s,
570 const UnknownNumberingScheme &c_s, TracSegArray &iEl,
571 GaussPoint &iGP, double k, void* lock)
572{
573
574 SpatialLocalizer *localizer = domain->giveSpatialLocalizer();
575
577 // Gamma_plus
578 FloatMatrix contrib;
579 assembleTangentGPContributionNew(contrib, iEl, iGP, -1.0, iGP.giveGlobalCoordinates());
580
581 // Compute vector of traction unknowns
582 FloatArray tracUnknowns;
583 iEl.mFirstNode->giveUnknownVector(tracUnknowns, giveTracDofIDs(), VM_Total, tStep);
584
585 IntArray trac_rows;
586 iEl.giveTractionLocationArray(trac_rows, type, r_s);
587
588
589 FloatArray dispElLocCoord, closestPoint;
590 Element *dispEl = localizer->giveElementClosestToPoint(dispElLocCoord, closestPoint, iGP.giveGlobalCoordinates() );
591
592 IntArray disp_cols;
593 dispEl->giveLocationArray(disp_cols, c_s);
594
595 contrib.times(k);
596#ifdef _OPENMP
597 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
598#endif
599 answer.assemble(trac_rows, disp_cols, contrib);
600#ifdef _OPENMP
601 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
602#endif
603
604 FloatMatrix contribT;
605 contribT.beTranspositionOf(contrib);
606#ifdef _OPENMP
607 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
608#endif
609 answer.assemble(disp_cols, trac_rows, contribT);
610#ifdef _OPENMP
611 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
612#endif
614 // Gamma_minus
615 contrib.clear();
616 FloatArray xMinus;
618 assembleTangentGPContributionNew(contrib, iEl, iGP, 1.0, xMinus);
619
620 // Compute vector of traction unknowns
621 tracUnknowns.clear();
622 iEl.mFirstNode->giveUnknownVector(tracUnknowns, giveTracDofIDs(), VM_Total, tStep);
623
624 trac_rows.clear();
625 iEl.giveTractionLocationArray(trac_rows, type, r_s);
626
627
628 dispElLocCoord.clear(); closestPoint.clear();
629 dispEl = localizer->giveElementClosestToPoint(dispElLocCoord, closestPoint, xMinus );
630
631 disp_cols.clear();
632 dispEl->giveLocationArray(disp_cols, c_s);
633 contrib.times(k);
634#ifdef _OPENMP
635 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
636#endif
637 answer.assemble(trac_rows, disp_cols, contrib);
638#ifdef _OPENMP
639 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
640#endif
641 contribT.clear();
642 contribT.beTranspositionOf(contrib);
643#ifdef _OPENMP
644 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
645#endif
646 answer.assemble(disp_cols, trac_rows, contribT);
647#ifdef _OPENMP
648 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
649#endif
650
651 // Assemble zeros on diagonal (required by PETSc solver)
652 FloatMatrix KZero(1,1);
653 KZero.zero();
654#ifdef _OPENMP
655 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
656#endif
657 for ( int i : trac_rows) {
658 answer.assemble(IntArray({i}), IntArray({i}), KZero);
659 }
660#ifdef _OPENMP
661 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
662#endif
663}
664
665void PrescribedGradientBCWeak :: giveLocationArrays(std :: vector< IntArray > &rows, std :: vector< IntArray > &cols, CharType type,
666 const UnknownNumberingScheme &r_s, const UnknownNumberingScheme &c_s)
667{
668
669}
670
671void PrescribedGradientBCWeak :: giveTractionLocationArray(IntArray &rows,
672 const UnknownNumberingScheme &s)
673{
674 // Used for the condensation when computing the macroscopic tangent.
675
676 rows.clear();
677
678 // Loop over traction elements
679 for ( auto &el : mpTracElNew ) {
680
681 IntArray trac_loc_r;
682 el.mFirstNode->giveLocationArray(giveTracDofIDs(), trac_loc_r, s);
683
684 rows.followedBy(trac_loc_r);
685 }
686
687#if 0
688 rows.clear();
689
690 // Loop over traction elements
691 for ( size_t tracElInd = 0; tracElInd < mpTractionElements.size(); tracElInd++ ) {
692 IntArray tracElRows, trac_loc_r;
693
694 const TractionElement &tEl = mpTractionElements [ tracElInd ];
695 for ( int tracNodeInd : tEl.mTractionNodeInd ) {
696 Node *tNode = mpTractionNodes [ tracNodeInd ];
697 tNode->giveLocationArray(giveTracDofIDs(), trac_loc_r, s);
698 tracElRows.followedBy(trac_loc_r);
699 }
700
701 rows.followedBy(tracElRows);
702 }
703
704 if ( mpDisplacementLock ) {
705 IntArray dispLock_r;
706 mpDisplacementLock->giveLocationArray(giveDispLockDofIDs(), dispLock_r, s);
707
708 rows.followedBy(dispLock_r);
709 }
710#endif
711}
712
713void PrescribedGradientBCWeak :: giveDisplacementLocationArray(IntArray &rows, const UnknownNumberingScheme &s)
714{
715 // Used for the condensation when computing the macroscopic tangent.
716}
717
718void PrescribedGradientBCWeak :: compute_x_times_N_1(FloatMatrix &o_x_times_N)
719{
720 //double rve_size = this->domainSize();
721 const int dim = domain->giveNumberOfSpatialDimensions();
722
723 IntArray loc_t;
725 giveTractionLocationArray(loc_t, fnum);
726
727 int num_t_eq = loc_t.giveSize();
728
729 //o_x_times_N.resize(3, num_t_eq);
730 o_x_times_N.resize(num_t_eq,3);
731
732 IntArray cols = {1,2,3};
733
734 int trac_el_ind = 1;
735
736 for ( auto &el : mpTracElNew ) {
737
738 IntArray rows = {trac_el_ind*2-1,trac_el_ind*2};
739
740 for ( auto &gp : *el.mIntRule ) {
741
742 FloatMatrix contrib(2,3);
743
744 // For now, assume piecewise constant approx
745 FloatArray Ntrac = Vec1( 1.0*mTracDofScaling );
746
747 // N-matrix
748 FloatMatrix Nmat;
749 Nmat.beNMatrixOf(Ntrac, dim);
750// printf("Nmat: "); Nmat.printYourself();
751
752 // Fetch global coordinate x
753 const FloatArray &x = gp->giveGlobalCoordinates();
754
755// // Compute vector of traction unknowns
756// FloatArray tracUnknowns;
757// el.mFirstNode->giveUnknownVector(tracUnknowns, giveTracDofIDs(), VM_Total, tStep);
758
759
760// FloatArray traction;
761// traction.beProductOf(Nmat, tracUnknowns);
762
763 FloatArray tmp;
765
766 FloatMatrix coord_mat(2,3);
767 coord_mat.at(1,1) = tmp.at(1);
768 coord_mat.at(2,2) = tmp.at(2);
769
770// coord_mat.at(3,2) = tmp.at(1);
771
772// coord_mat.at(3,1) = tmp.at(2);
773// coord_mat.at(4,2) = tmp.at(1);
774
775// coord_mat.at(4,1) = tmp.at(2);
776// coord_mat.at(3,2) = tmp.at(1);
777
778 coord_mat.at(1,3) = 0.5*tmp.at(2);
779 coord_mat.at(2,3) = 0.5*tmp.at(1);
780
781// coord_mat.at(4,2) = 0.5*tmp.at(2);
782// coord_mat.at(4,1) = 0.5*tmp.at(1);
783
784
785// FloatMatrix contrib;
786// contrib.beDyadicProductOf(traction, tmp);
787
788 contrib.beProductOf(Nmat, coord_mat);
789
790// contrib = coord_mat;
791
792 double detJ = 0.5 * el.giveLength();
793 contrib.times( detJ * gp->giveWeight() );
794
795// printf("\n\ncontrib: "); contrib.printYourself();
796// printf("rows: "); rows.printYourself();
797// printf("cols: "); cols.printYourself();
798
799 o_x_times_N.assemble(contrib, rows, cols);
800 }
801
802 trac_el_ind++;
803 }
804}
805
806void PrescribedGradientBCWeak :: compute_x_times_N_2(FloatMatrix &o_x_times_N)
807{
808 //double rve_size = this->domainSize();
809 const int dim = domain->giveNumberOfSpatialDimensions();
810
811 IntArray loc_t;
813 giveTractionLocationArray(loc_t, fnum);
814
815 int num_t_eq = loc_t.giveSize();
816
817 //o_x_times_N.resize(4, num_t_eq);
818 o_x_times_N.resize(3, num_t_eq);
819
820 IntArray rows = {1,2,3};
821
822 int trac_el_ind = 1;
823
824 for ( auto &el : mpTracElNew ) {
825
826 IntArray cols = {trac_el_ind*2-1,trac_el_ind*2};
827
828 for ( auto &gp : *el.mIntRule ) {
829
830 FloatMatrix contrib(4,2);
831
832 // For now, assume piecewise constant approx
833 FloatArray Ntrac = Vec1( 1.0*mTracDofScaling );
834
835 // N-matrix
836 FloatMatrix Nmat;
837 Nmat.beNMatrixOf(Ntrac, dim);
838// printf("Nmat: "); Nmat.printYourself();
839
840 // Fetch global coordinate x
841 const FloatArray &x = gp->giveGlobalCoordinates();
842
843// // Compute vector of traction unknowns
844// FloatArray tracUnknowns;
845// el.mFirstNode->giveUnknownVector(tracUnknowns, giveTracDofIDs(), VM_Total, tStep);
846
847
848// FloatArray traction;
849// traction.beProductOf(Nmat, tracUnknowns);
850
851 FloatArray tmp;
853
854 FloatMatrix coord_mat(4,2);
855 coord_mat.at(1,1) = tmp.at(1);
856 coord_mat.at(2,2) = tmp.at(2);
857
858// coord_mat.at(3,2) = tmp.at(1);
859// coord_mat.at(3,1) = tmp.at(2);
860
861// coord_mat.at(3,1) = tmp.at(2);
862// coord_mat.at(4,2) = tmp.at(1);
863
864 coord_mat.at(3,1) = 0.5*tmp.at(2);
865 coord_mat.at(3,2) = 0.5*tmp.at(1);
866//
867// coord_mat.at(4,2) = 0.5*tmp.at(2);
868// coord_mat.at(4,1) = 0.5*tmp.at(1);
869
870
871// FloatMatrix contrib;
872// contrib.beDyadicProductOf(traction, tmp);
873
874 contrib.beProductOf(coord_mat, Nmat);
875
876// contrib = coord_mat;
877
878 double detJ = 0.5 * el.giveLength();
879 contrib.times( detJ * gp->giveWeight() );
880
881// printf("\n\ncontrib: "); contrib.printYourself();
882// printf("rows: "); rows.printYourself();
883// printf("cols: "); cols.printYourself();
884
885 o_x_times_N.assemble(contrib, rows, cols);
886 }
887
888 trac_el_ind++;
889 }
890}
891
892
893void PrescribedGradientBCWeak :: computeField(FloatArray &sigma, TimeStep *tStep)
894{
895 double Lx = mUC[0] - mLC[0];
896 double Ly = mUC[1] - mLC[1];
897 double dSize = Lx*Ly;
898// printf("dSize: %e\n", dSize);
899
900 const int dim = domain->giveNumberOfSpatialDimensions();
901 FloatMatrix stressMatrix(dim, dim);
902
903 for ( auto &el : mpTracElNew ) {
904
905 for ( auto &gp : *el.mIntRule ) {
906
907 // For now, assume piecewise constant approx
908 FloatArray Ntrac = Vec1( 1.0*mTracDofScaling );
909
910 // N-matrix
911 FloatMatrix Nmat;
912 Nmat.beNMatrixOf(Ntrac, dim);
913
914 // Fetch global coordinate x
915 const FloatArray &x = gp->giveGlobalCoordinates();
916
917 // Compute vector of traction unknowns
918 FloatArray tracUnknowns;
919 el.mFirstNode->giveUnknownVector(tracUnknowns, giveTracDofIDs(), VM_Total, tStep);
920
921
922 FloatArray traction;
923 traction.beProductOf(Nmat, tracUnknowns);
924
925 FloatArray tmp;
927
928 FloatMatrix contrib;
929 contrib.beDyadicProductOf(traction, tmp);
930
931 double detJ = 0.5 * el.giveLength();
932 contrib.times( detJ * gp->giveWeight() );
933
934 for ( int m = 0; m < dim; m++ ) {
935 for ( int n = 0; n < dim; n++ ) {
936 stressMatrix(m, n) += contrib(m, n);
937 }
938 }
939
940 }
941
942 }
943
944 if ( dim == 2 ) {
945 sigma = Vec6(
946 stressMatrix(0, 0), stressMatrix(1, 1), 0.0, 0.0, 0.0, 0.5*(stressMatrix(0, 1) + stressMatrix(1, 0))
947 );
948 } else {
949 sigma.beVectorForm(stressMatrix);
950 }
951
952 sigma.times(1.0 / dSize);
953
954}
955
956//#define TIME_INFO
957
958void PrescribedGradientBCWeak :: computeTangent(FloatMatrix& E, TimeStep* tStep)
959{
960#ifdef TIME_INFO
961 static double tot_time = 0.0;
962 Timer timer;
963 timer.startTimer();
964
965 static double assemble_time = 0.0;
966 Timer assemble_timer;
967
968#endif
969
970 E.resize(9,9);
971
972
973 // Extract the relevant submatrices from the RVE problem.
974 // At equilibrium, the RVE problem has the structure
975 //
976 // [ S C; C^T 0 ]*[a_u a_t] = [0; f]
977 //
978 // where a_u and a_t denote displacement and traction dofs, respectively.
979 // We need to extract S and C.
980
981 EngngModel *rve = this->giveDomain()->giveEngngModel();
983 std :: unique_ptr< SparseLinearSystemNM > solver(
984 classFactory.createSparseLinSolver( ST_Petsc, this->domain, this->domain->giveEngngModel() ) ); // = rve->giveLinearSolver();
985 bool symmetric_matrix = false;
986 SparseMtrxType stype = solver->giveRecommendedMatrix(symmetric_matrix);
987// double rve_size = this->domainSize();
988 double Lx = mUC[0] - mLC[0];
989 double Ly = mUC[1] - mLC[1];
990 double rve_size = Lx*Ly;
991
992
994 std :: unique_ptr< SparseMtrx > Kmicro( classFactory.createSparseMtrx(stype) );
995 if ( !Kmicro ) {
996 OOFEM_ERROR("Couldn't create sparse matrix of type %d\n", stype);
997 }
998
999#ifdef __SM_MODULE
1000 StaticStructural *rveStatStruct = dynamic_cast<StaticStructural*>(rve);
1001 if ( rveStatStruct ) {
1002 //printf("Successfully casted rve to StaticStructural.\n");
1003
1004 if ( rveStatStruct->stiffnessMatrix ) {
1005 Kmicro = rveStatStruct->stiffnessMatrix->clone();
1006 }
1007 }
1008#endif
1009
1010
1011#ifdef TIME_INFO
1012 assemble_timer.startTimer();
1013#endif
1014
1015 if ( Kmicro->giveNumberOfColumns() == 0 ) {
1016 //printf("Rebuilding stiffness matrix.\n");
1017 Kmicro->buildInternalStructure(rve, this->domain->giveNumber(), fnum);
1018 rve->assemble(*Kmicro, tStep, TangentAssembler(TangentStiffness), fnum, this->domain);
1019 }
1020// else {
1021// printf("Using existing stiffness matrix.\n");
1022// }
1023
1024 assembleExtraDisplock(*Kmicro, tStep, TangentStiffnessMatrix, fnum, fnum);
1025#ifdef TIME_INFO
1026 assemble_timer.stopTimer();
1027 assemble_time += assemble_timer.getUtime();
1028 printf("Assembly time for RVE tangent: %e\n", assemble_time);
1029#endif
1030
1031 // Fetch displacement and traction location arrays
1032 IntArray loc_u, loc_t;
1033
1034 giveTractionLocationArray(loc_t, fnum);
1035
1036 int neq = Kmicro->giveNumberOfRows();
1037 loc_u.resize(neq - loc_t.giveSize());
1038 int k = 1;
1039 for ( int i = 1; i <= neq; i++ ) {
1040 if ( !loc_t.contains(i) ) {
1041 loc_u.at(k) = i;
1042 k++;
1043 }
1044 }
1045
1046 // Fetch the submatrices
1047 std :: unique_ptr< SparseMtrx > S = Kmicro->giveSubMatrix(loc_u, loc_u);
1048 // NOTE: Kus is actually a dense matrix, but we have to make it a dense matrix first
1049 std :: unique_ptr< SparseMtrx > C = Kmicro->giveSubMatrix(loc_u, loc_t);
1050 FloatMatrix Cd;
1051 C->toFloatMatrix(Cd);
1052
1053 // Let Sm = C. Solve for m.
1054 FloatMatrix m;
1055 solver->solve(*S, Cd, m);
1056
1057 // Compute G := C^T m. (Which could, formally, be written as G = C^T S^-1 C.)
1058 FloatMatrix G;
1059 G.beTProductOf(Cd, m);
1060
1061 // Compute D := \int x \otimes N
1062 FloatMatrix D;
1064// FloatMatrix D;
1065// compute_x_times_N_1(DT2);
1066// D.beTranspositionOf(DT);
1067
1068 // Let Gp = D. Solve for p. (Which could, formally, be written as p = G^-1 D = (C^T S^-1 C)^-1 D.)
1069 // Need to make G sparse;
1070 std :: unique_ptr< SparseMtrx > Gs( classFactory.createSparseMtrx(stype) );
1071 if ( !Gs ) {
1072 OOFEM_ERROR("Couldn't create sparse matrix of type %d\n", stype);
1073 }
1074
1075 int num_eq_G = G.giveNumberOfRows();
1076 IntArray loc_G;
1077 loc_G.enumerate(num_eq_G);
1078
1079 Gs->buildInternalStructure(rve, num_eq_G, num_eq_G, loc_G, loc_G);
1080 Gs->assemble(loc_G, loc_G, G);
1081
1082 Gs->assembleBegin();
1083 Gs->assembleEnd();
1084
1085// Gs->writeToFile("Gs.txt");
1086
1087 FloatMatrix p;
1088 solver->solve(*Gs, D, p);
1089
1090 // Compute d_sigma_depsilon = D^T p.
1091 FloatMatrix Ered;
1092 Ered.beTProductOf(D,p);
1093// rve_size = 25.0;
1094 Ered.times(1.0/rve_size);
1095// printf("rve_size: %e\n", rve_size);
1096// Ered.printYourself();
1097
1098 IntArray indx = {1,2,6,9}; // to make it independednt of sm module
1099 //StructuralMaterial :: giveVoigtVectorMask(indx, _PlaneStress);
1100
1101
1102// FloatMatrix EredT;
1103// EredT.beTranspositionOf(Ered);
1104// Ered.add(EredT);
1105// Ered.times(0.5);
1106
1107// Ered.at(1,3) = 0.0;
1108// Ered.at(2,3) = 0.0;
1109// Ered.at(3,1) = 0.0;
1110// Ered.at(3,2) = 0.0;
1111
1112 E.assemble(Ered, indx, indx);
1113// E.printYourself();
1114
1115#ifdef TIME_INFO
1116 timer.stopTimer();
1117 tot_time += timer.getUtime();
1118// printf("Total time for RVE tangent: %e\n", tot_time);
1119#endif
1120
1121}
1122
1123void PrescribedGradientBCWeak :: giveTractionElNormal(size_t iElInd, FloatArray &oNormal, FloatArray &oTangent) const
1124{
1125 FloatArray xS, xE;
1126 giveTractionElCoord(iElInd, xS, xE);
1127
1128 oTangent.beDifferenceOf(xE, xS);
1129 oTangent.normalize();
1130
1131 oNormal = Vec2(
1132 oTangent [ 1 ], -oTangent [ 0 ]
1133 );
1134}
1135
1136void PrescribedGradientBCWeak :: giveTractionElArcPos(size_t iElInd, double &oXiStart, double &oXiEnd) const
1137{
1138 FloatArray xS, xE;
1139 giveTractionElCoord(iElInd, xS, xE);
1140
1141 FloatArray xC;
1142 xC.beScaled(0.5, xS);
1143 xC.add(0.5, xE);
1144 int sideIndex = giveSideIndex(xC);
1145
1146 const double nodeDistTol = 1.0e-15;
1147 ArcPosSortFunction3< bool >sortFunc(mLC, mUC, nodeDistTol, sideIndex);
1148
1149 oXiStart = sortFunc.calcArcPos(xS);
1150 oXiEnd = sortFunc.calcArcPos(xE);
1151}
1152
1153void PrescribedGradientBCWeak :: giveBoundaries(IntArray &oBoundaries)
1154{
1155 Set *setPointer = this->giveDomain()->giveSet(this->set);
1156 oBoundaries = setPointer->giveBoundaryList();
1157}
1158
1159void PrescribedGradientBCWeak :: giveTraction(size_t iElInd, FloatArray &oStartTraction, FloatArray &oEndTraction, ValueModeType mode, TimeStep *tStep)
1160{
1161 // For now, assuming piecewise constant traction
1162 mpTracElNew[iElInd].mFirstNode->giveUnknownVector(oStartTraction, giveTracDofIDs(), mode, tStep);
1163 oStartTraction.times(mTracDofScaling);
1164 mpTracElNew[iElInd].mFirstNode->giveUnknownVector(oEndTraction, giveTracDofIDs(), mode, tStep);
1165 oEndTraction.times(mTracDofScaling);
1166}
1167
1168void PrescribedGradientBCWeak :: recomputeTractionMesh()
1169{
1170 clear();
1172}
1173
1174void PrescribedGradientBCWeak :: createTractionMesh(bool iEnforceCornerPeriodicity, int iNumSides)
1175{
1176 bool split_at_holes = true;
1177
1178 const double l_s = mUC[0] - mLC[0];
1179 const double minPointDist = 1.0e-4*l_s;
1180
1181 // Find holes intersecting the RVE boundary so that these can be excluded
1182 std::vector<FloatArray> holeCoordUnsorted, allCoordUnsorted;
1183 findHoleCoord(holeCoordUnsorted, allCoordUnsorted);
1184
1185 // Add corner points
1186 holeCoordUnsorted.push_back( Vec2(mUC[0], mLC[1]) );
1187 allCoordUnsorted.push_back( Vec2(mUC[0], mLC[1]) );
1188
1189 holeCoordUnsorted.push_back( Vec2(mUC[0], mUC[1]) );
1190 allCoordUnsorted.push_back( Vec2(mUC[0], mUC[1]) );
1191
1192 holeCoordUnsorted.push_back( Vec2(mLC[0], mUC[1]) );
1193 allCoordUnsorted.push_back( Vec2(mLC[0], mUC[1]) );
1194
1195
1196 // Add crack-boundary intersections
1197 findCrackBndIntersecCoord(holeCoordUnsorted);
1198
1199 // Add periodicity points
1200 findPeriodicityCoord(holeCoordUnsorted);
1201
1202
1203 // Sort arrays in terms of arc length along the RVE boundary
1204 std :: sort( holeCoordUnsorted.begin(), holeCoordUnsorted.end(), ArcPosSortFunction4( mLC, mUC, 1.0e-4 ) );
1205 std :: sort( allCoordUnsorted.begin(), allCoordUnsorted.end(), ArcPosSortFunction4( mLC, mUC, 1.0e-4 ) );
1206
1207
1208 // Add refinement points
1209 int pointsPassed = 0;
1210 for ( const auto &x : allCoordUnsorted ) {
1211
1212 if ( pointsPassed >= mTractionNodeSpacing ) {
1213 holeCoordUnsorted.push_back(x);
1214 pointsPassed = 0;
1215 }
1216
1217 pointsPassed++;
1218 }
1219
1220 // Sort again
1221 std :: sort( holeCoordUnsorted.begin(), holeCoordUnsorted.end(), ArcPosSortFunction4( mLC, mUC, 1.0e-4 ) );
1222 std :: sort( allCoordUnsorted.begin(), allCoordUnsorted.end(), ArcPosSortFunction4( mLC, mUC, 1.0e-4 ) );
1223
1224 // Remove points that are too close to each other
1225 removeClosePoints(holeCoordUnsorted, minPointDist);
1226 removeClosePoints(allCoordUnsorted, minPointDist);
1227
1228 // Create two arrays of segments, where each array represents the coarsest possible traction
1229 // mesh on one side of the RVE
1230 ArcPosSortFunction4 arcPosFunc( mLC, mUC, 1.0e-4 );
1231
1232 std :: vector< TracSegArray > tracElNew0, tracElNew1;
1233 tracElNew0.emplace_back();
1234 //tracElNew1.emplace_back();
1235
1236 for (size_t i = 1; i < holeCoordUnsorted.size(); i++) {
1237
1238 FloatArray xS = holeCoordUnsorted[i-1];
1239 xS.resizeWithValues(2);
1240 FloatArray xE = holeCoordUnsorted[i];
1241 xE.resizeWithValues(2);
1242 const FloatArray xC = Vec2(0.5*(xS[0]+xE[0]), 0.5*(xS[1]+xE[1]));
1243
1244 if ( arcPosFunc.calcArcPos(xC) < 2.*l_s ) {
1245 tracElNew0[0].mInteriorSegments.emplace_back(xS, xE);
1246 } else {
1247 tracElNew1[0].mInteriorSegments.emplace_back(xS, xE);
1248 }
1249 }
1250
1251 // Remove segments located in holes
1252 removeSegOverHoles(tracElNew0[0], 1.0e-4);
1253 removeSegOverHoles(tracElNew1[0], 1.0e-4);
1254
1255 if ( split_at_holes ) {
1256 splitSegments(tracElNew0);
1257 splitSegments(tracElNew1);
1258 }
1259
1260 // Identify additional points that can be used to refine the traction mesh
1261
1262
1264 // Create traction dofs
1265 int numNodes = domain->giveNumberOfDofManagers();
1266 int totNodesCreated = 0;
1267
1268
1269 // For each side (0 and 1), loop over over elements
1270
1271 // We may always create the first node on the element.
1272 // For the linear approximation, it may need to be a slave node,
1273 // depending on which element it is.
1274
1275 // For now, consider only piecewise constant approximations. Then,
1276 // we can always create on node on each element.
1277
1278 // RVE side at x=L
1279 for ( auto &el : tracElNew0 ) {
1280
1282 // Create first node
1283 totNodesCreated++;
1284
1285 el.mFirstNode = std::make_unique<Node>(numNodes + 1, domain);
1286 el.mFirstNode->setGlobalNumber(numNodes + 1);
1287 for ( auto &dofId: giveTracDofIDs() ) {
1288 el.mFirstNode->appendDof( new MasterDof(el.mFirstNode.get(), ( DofIDItem ) dofId) );
1289 }
1290
1291 el.mFirstNode->setCoordinates( el.mInteriorSegments[0].giveVertex(1) );
1292 numNodes++;
1293 }
1294
1295
1296 // RVE side at y=L
1297 for ( auto &el : tracElNew1 ) {
1298
1300 // Create first node
1301 totNodesCreated++;
1302
1303 el.mFirstNode = std::make_unique<Node>(numNodes + 1, domain);
1304 el.mFirstNode->setGlobalNumber(numNodes + 1);
1305 for ( auto &dofId: giveTracDofIDs() ) {
1306 el.mFirstNode->appendDof( new MasterDof(el.mFirstNode.get(), ( DofIDItem ) dofId) );
1307 }
1308
1309 el.mFirstNode->setCoordinates( el.mInteriorSegments[0].giveVertex(1) );
1310 numNodes++;
1311 }
1312
1313 if ( mMeshIsPeriodic && false ) {
1314 // Lock displacement in one node if we use periodic BCs
1315
1316 int numNodes = domain->giveNumberOfDofManagers();
1317 mpDisplacementLock = std::make_unique<Node>(numNodes + 1, domain);
1318 mLockNodeInd = domain->giveElement(1)->giveNode(1)->giveGlobalNumber();
1319
1320
1321 for ( auto &dofid: giveDispLockDofIDs() ) {
1322 mpDisplacementLock->appendDof( new MasterDof(mpDisplacementLock.get(), ( DofIDItem ) dofid) );
1323 }
1324 }
1325
1326
1327 // Nodes to lock in order to prevent rigid body motion
1328 SpatialLocalizer *localizer = domain->giveSpatialLocalizer();
1329 FloatArray x1 = mLC;
1330// printf("x1: "); x1.printYourself();
1331 double maxDist = 1.0e10;
1332 Node *node1 = localizer->giveNodeClosestToPoint(x1, maxDist);
1334// printf("mSpringNodeInd1: %d\n", mSpringNodeInd1 );
1335
1336 FloatArray x2 = Vec2(mUC.at(1), mLC.at(2));
1337// FloatArray x2 = Vec2(mUC.at(1), mUC.at(2));
1338// printf("x2: "); x2.printYourself();
1339 Node *node2 = localizer->giveNodeClosestToPoint(x2, maxDist);
1341// printf("mSpringNodeInd2: %d\n", mSpringNodeInd2 );
1342
1343
1344 FloatArray x3 = Vec2(mLC.at(1), mUC.at(2));
1345// FloatArray x2 = Vec2(mUC.at(1), mUC.at(2));
1346// printf("x3: "); x3.printYourself();
1347 Node *node3 = localizer->giveNodeClosestToPoint(x3, maxDist);
1349// printf("mSpringNodeInd3: %d\n", mSpringNodeInd3 );
1350
1351
1352 mpTracElNew.reserve(mpTracElNew.size() + tracElNew0.size() + tracElNew1.size());
1353 std::move(tracElNew0.begin(), tracElNew0.end(), std::back_inserter(mpTracElNew));
1354 std::move(tracElNew1.begin(), tracElNew1.end(), std::back_inserter(mpTracElNew));
1355 tracElNew0.clear();
1356 tracElNew1.clear();
1357
1358
1360 // Segment arrays for Gauss quadrature
1361 size_t i = 0;
1362
1363 for ( auto & el : mpTracElNew ) {
1364
1365 const FloatArray &xS = el.mInteriorSegments[0].giveVertex(1);
1366 const double arcPosXS = arcPosFunc.calcArcPos(xS);
1367
1368 const FloatArray &xE = el.mInteriorSegments.back().giveVertex(2);
1369 const double arcPosXE = arcPosFunc.calcArcPos(xE);
1370
1371 while (i < allCoordUnsorted.size()) {
1372
1373 FloatArray x = allCoordUnsorted[i];
1374 x.resizeWithValues(2);
1375 const double arcPosX = arcPosFunc.calcArcPos(x);
1376
1377 if ( arcPosX > (arcPosXS+minPointDist) && arcPosX < (arcPosXE-minPointDist) ) {
1378 el.mInteriorSegmentsPointsFine.push_back(std::move(x));
1379 }
1380
1381 if ( arcPosX > arcPosXE ) {
1382 break;
1383 }
1384
1385 i++;
1386 }
1387 }
1388
1389 // Now we have the necessary points on each traction element.
1390 // The next step is to create splitted segments.
1391 for ( auto & el : mpTracElNew ) {
1392
1393 i = 0;
1394 for ( auto &line : el.mInteriorSegments ) {
1395 FloatArray xS = line.giveVertex(1);
1396 xS.resizeWithValues(2);
1397 const double arcPosXS = arcPosFunc.calcArcPos(xS);
1398
1399 FloatArray xE = line.giveVertex(2);
1400 xE.resizeWithValues(2);
1401 const double arcPosXE = arcPosFunc.calcArcPos(xE);
1402
1403 if ( el.mInteriorSegmentsPointsFine.size() == 0 ) {
1404 Line newLine(xS, xE);
1405 el.mInteriorSegmentsFine.push_back(newLine);
1406 } else {
1407 while ( i < el.mInteriorSegmentsPointsFine.size() ) {
1408
1409 const FloatArray &x = el.mInteriorSegmentsPointsFine[i];
1410 const double arcPosX = arcPosFunc.calcArcPos(x);
1411
1412 if ( arcPosX < arcPosXS ) {
1413 OOFEM_ERROR("Error in PrescribedGradientBCWeak :: createTractionMesh.")
1414 }
1415
1416 if ( arcPosX < arcPosXE ) {
1417 // Split from start pos to x
1418 Line newLine(xS, x);
1419 el.mInteriorSegmentsFine.push_back(newLine);
1420
1421 xS = x;
1422 } else {
1423 // Split from x to end pos
1424 Line newLine(xS, xE);
1425 el.mInteriorSegmentsFine.push_back(newLine);
1426
1427 break;
1428 }
1429
1430 if ( i == (el.mInteriorSegmentsPointsFine.size()-1) ) {
1431 // Split from x to end pos
1432 Line newLine(xS, xE);
1433 el.mInteriorSegmentsFine.push_back(newLine);
1434 }
1435
1436 i++;
1437 }
1438 }
1439 }
1440 }
1441
1442 // Create integration rules
1443 for ( auto & el : mpTracElNew ) {
1444 el.setupIntegrationRuleOnEl();
1445 }
1446
1447 // Write discontinuity points to debug vtk
1448 std :: vector< FloatArray > discPoints;
1449 for ( auto & el : mpTracElNew ) {
1450
1451 discPoints.push_back( el.mInteriorSegments[0].giveVertex(1) );
1452 discPoints.push_back( el.mInteriorSegments.back().giveVertex(2) );
1453 }
1454
1455// std :: string fileName("DiscontPoints.vtk");
1456// XFEMDebugTools :: WritePointsToVTK(fileName, discPoints);
1457
1458}
1459
1460void PrescribedGradientBCWeak :: splitSegments(std :: vector< TracSegArray > &ioElArray)
1461{
1462 std :: vector< TracSegArray > newArray;
1463
1464 for ( auto &el : ioElArray ) {
1465 for ( auto &line : el.mInteriorSegments ) {
1466 TracSegArray newEl;
1467 newEl.mInteriorSegments.push_back(line);
1468 newArray.push_back(std::move(newEl));
1469 }
1470 }
1471
1472 ioElArray = std::move(newArray);
1473}
1474
1475bool PrescribedGradientBCWeak :: damageExceedsTolerance(Element *el)
1476{
1477 TimeStep *tStep = this->giveDomain()->giveEngngModel()->giveCurrentStep();
1478
1479 double maxDamage = 0.0, damageTol = 0.01;
1480 for ( auto &gp: *el->giveDefaultIntegrationRulePtr() ) {
1481 FloatArray damage;
1482 el->giveIPValue(damage, gp, IST_DamageScalar, tStep);
1483// printf("damage: "); damage.printYourself();
1484 maxDamage = std::max(maxDamage, damage(0));
1485 }
1486
1487// printf("maxDamage: %e\n", maxDamage);
1488
1489 return maxDamage >= damageTol;
1490}
1491
1492
1493void PrescribedGradientBCWeak :: assembleTangentGPContributionNew(FloatMatrix &oTangent, TracSegArray &iEl, GaussPoint &iGP, const double &iScaleFactor, const FloatArray &iBndCoord)
1494{
1495 int dim = domain->giveNumberOfSpatialDimensions();
1496 double detJ = 0.5 * iEl.giveLength();
1497
1499 // Compute traction N-matrix
1500 // For now, assume piecewise constant approx
1501 FloatArray Ntrac = Vec1( 1.0*mTracDofScaling );
1502 FloatMatrix NtracMat;
1503 NtracMat.beNMatrixOf(Ntrac, dim);
1504
1506 // Compute displacement N-matrix
1507 // Identify the displacement element
1508 // we are currently standing in
1509 // and compute local coordinates on
1510 // the displacement element
1511 SpatialLocalizer *localizer = domain->giveSpatialLocalizer();
1512 FloatArray dispElLocCoord, closestPoint;
1513 Element *dispEl = localizer->giveElementClosestToPoint(dispElLocCoord, closestPoint, iBndCoord );
1514
1515 // Compute basis functions
1516 XfemElementInterface *xfemElInt = dynamic_cast< XfemElementInterface * >( dispEl );
1517 FloatMatrix NdispMat;
1518
1519 if ( xfemElInt && domain->hasXfemManager() ) {
1520 // If the element is an XFEM element, we use the XfemElementInterface to compute the N-matrix
1521 // of the enriched element.
1522 xfemElInt->XfemElementInterface_createEnrNmatrixAt(NdispMat, dispElLocCoord, * dispEl, false);
1523 } else {
1524 // Otherwise, use the usual N-matrix.
1525 FloatArray N;
1526
1527 int dim = dispEl->giveSpatialDimension();
1528
1529 dispEl->giveInterpolation()->evalN( N, dispElLocCoord, FEIElementGeometryWrapper(dispEl) );
1530
1531 NdispMat.beNMatrixOf(N, dim);
1532 }
1533
1534 oTangent.beTProductOf(NtracMat, NdispMat);
1535 oTangent.times( iScaleFactor * detJ * iGP.giveWeight() );
1536}
1537
1538bool PrescribedGradientBCWeak :: pointIsOnGammaPlus(const FloatArray &iPos) const
1539{
1540 const double distTol = 1.0e-12;
1541
1542 if ( iPos [ 0 ] > mUC [ 0 ] - distTol ) {
1543 return true;
1544 }
1545
1546 if ( iPos [ 1 ] > mUC [ 1 ] - distTol ) {
1547 return true;
1548 }
1549
1550 return false;
1551}
1552
1553void PrescribedGradientBCWeak :: giveMirroredPointOnGammaMinus(FloatArray &oPosMinus, const FloatArray &iPosPlus) const
1554{
1555//#if 0
1556 if ( mMirrorFunction == 0 ) {
1557 oPosMinus = iPosPlus;
1558 const double distTol = 1.0e-12;
1559
1560// if ( distance(iPosPlus, mUC) < distTol ) {
1561// printf("iPosPlus: %.12e %.12e\n", iPosPlus [ 0 ], iPosPlus [ 1 ]);
1562// OOFEM_ERROR("Unmappable point.")
1563// }
1564
1565 if ( iPosPlus [ 0 ] > mUC [ 0 ] - distTol ) {
1566 oPosMinus [ 0 ] = mLC [ 0 ];
1567 return;
1568 } else if ( iPosPlus [ 1 ] > mUC [ 1 ] - distTol ) {
1569 oPosMinus [ 1 ] = mLC [ 1 ];
1570 return;
1571 }
1572
1573 iPosPlus.printYourself();
1574 OOFEM_ERROR("Mapping failed.")
1575
1576 // printf("iPosPlus: "); iPosPlus.printYourself();
1577 // printf("oPosMinus: "); oPosMinus.printYourself();
1578 //#else
1579 } else {
1580
1581#if 1
1582
1583 const double distTol = 1.0e-12;
1584// bool mappingPerformed = false;
1585
1587 FloatArray t = Vec2(n(1),-n(0));
1588 t.normalize();
1589
1590 double l_s = mUC[0] - mLC[0];
1591
1592 // Compute angle
1593 double alpha = 0.0, a = 0.0;
1594 if ( fabs(t(0)) > 1.0e-6 && fabs(t(1)) > 1.0e-6 ) {
1595 alpha = atan(t(1)/t(0));
1596
1597 if ( alpha > 45.0*M_PI/180.0 ) {
1598 a = l_s/tan(alpha);
1599 } else {
1600 a = l_s*tan(alpha);
1601 }
1602 } else {
1603 // 90 degrees or 0 degrees
1604// alpha = 1.57079632679490e+00;
1605 a = 0.0;
1606 }
1607
1608 if ( alpha > 45.0*M_PI/180.0 ) {
1609
1610 // alpha > 45 degrees
1611
1612 if ( iPosPlus [ 0 ] > mUC [ 0 ] - distTol ) {
1613 // Gamma_1_plus
1614 oPosMinus = Vec2(0.0, iPosPlus[1]);
1615 return;
1616 }
1617
1618 if ( iPosPlus [ 1 ] > mUC [ 1 ] - distTol ) {
1619 // Gamma_2_plus
1620
1621 if ( iPosPlus[0] < a ) {
1622 oPosMinus = Vec2(l_s - a + iPosPlus[0], 0.0);
1623 return;
1624 } else {
1625 oPosMinus = Vec2(iPosPlus[0] - a, 0.0);
1626 return;
1627 }
1628
1629 }
1630
1631 } else {
1632
1633 // alpha <= 45 degrees
1634
1635 if ( iPosPlus [ 0 ] > mUC [ 0 ] - distTol ) {
1636 // Gamma_1_plus
1637 if ( iPosPlus[1] < a ) {
1638 oPosMinus = Vec2(0.0, l_s - a + iPosPlus[1]);
1639 return;
1640 } else {
1641 oPosMinus = Vec2(0.0, iPosPlus[1] - a);
1642 return;
1643 }
1644
1645 }
1646
1647 if ( iPosPlus [ 1 ] > mUC [ 1 ] - distTol ) {
1648 // Gamma_2_plus
1649
1650 oPosMinus = Vec2(iPosPlus[0], 0.0);
1651 return;
1652 }
1653
1654 }
1655
1656#else
1657
1658#endif
1659 }
1660 //#endif
1661}
1662
1663void PrescribedGradientBCWeak :: giveMirroredPointOnGammaPlus(FloatArray &oPosPlus, const FloatArray &iPosMinus) const
1664{
1665//#if 0
1666 if ( mMirrorFunction == 0 ) {
1667
1668 const double l_box = mUC(0) - mLC(0);
1669
1670 oPosPlus = iPosMinus;
1671// const double distTol = 1.0e-16;
1672 const double distTol = l_box*1.0e-10;
1673
1674// if ( distance(iPosMinus, mLC) < distTol ) {
1675// printf("iPosMinus: %.12e %.12e\n", iPosMinus [ 0 ], iPosMinus [ 1 ]);
1676// OOFEM_ERROR("Unmappable point.")
1677// }
1678
1679 if ( iPosMinus [ 0 ] < mLC [ 0 ] + distTol ) {
1680 oPosPlus [ 0 ] = mUC [ 0 ];
1681 return;
1682 } else if ( iPosMinus [ 1 ] < mLC [ 1 ] + distTol ) {
1683 oPosPlus [ 1 ] = mUC [ 1 ];
1684 return;
1685 }
1686
1687 iPosMinus.printYourself();
1688 OOFEM_ERROR("Mapping failed.")
1689//#else
1690 } else {
1691
1692#if 1
1693
1694 const double distTol = 1.0e-12;
1695
1697 FloatArray t = Vec2(n(1),-n(0));
1698 t.normalize();
1699
1700 double l_s = mUC[0] - mLC[0];
1701
1702 // Compute angle
1703 double alpha = 0.0, a = 0.0;
1704 if ( fabs(t(0)) > 1.0e-6 && fabs(t(1)) > 1.0e-6 ) {
1705 alpha = atan(t(1)/t(0));
1706
1707 if ( alpha > 45.0*M_PI/180.0 ) {
1708 a = l_s/tan(alpha);
1709 } else {
1710 a = l_s*tan(alpha);
1711 }
1712 } else {
1713 // 90 degrees
1714 a = 0.0;
1715 }
1716
1717// printf("t(1)/t(0): %e\n", t(1)/t(0));
1718// printf("a: %e\n", a);
1719
1720 if ( alpha > 45.0*M_PI/180.0 ) {
1721
1722 // alpha > 45 degrees
1723
1724 if ( iPosMinus [ 0 ] < mLC [ 0 ] + distTol ) {
1725 // Gamma_1_minus
1726 oPosPlus = Vec2(l_s, iPosMinus[1]);
1727 return;
1728 }
1729
1730 if ( iPosMinus [ 1 ] < mLC [ 1 ] + distTol ) {
1731 // Gamma_2_minus
1732
1733 if ( iPosMinus[0] < l_s - a) {
1734 oPosPlus = Vec2(iPosMinus[0] + a, l_s);
1735 return;
1736 }
1737 else {
1738 oPosPlus = Vec2(iPosMinus[0] - (l_s - a), l_s);
1739 return;
1740 }
1741
1742 }
1743
1744 } else {
1745 // alpha <= 45 degrees
1746
1747 if ( iPosMinus [ 0 ] < mLC [ 0 ] + distTol ) {
1748 // Gamma_1_minus
1749
1750 if ( iPosMinus[1] < l_s - a ) {
1751 oPosPlus = Vec2(l_s, iPosMinus[1] + a);
1752 return;
1753 } else {
1754 oPosPlus = Vec2(l_s, iPosMinus[1] - (l_s - a) );
1755 return;
1756 }
1757 }
1758
1759 if ( iPosMinus [ 1 ] < mLC [ 1 ] + distTol ) {
1760 // Gamma_2_minus
1761
1762 oPosPlus = Vec2(iPosMinus[0], l_s);
1763 return;
1764
1765 }
1766
1767 }
1768#endif
1769 }
1770//#endif
1771}
1772
1773
1774void PrescribedGradientBCWeak :: computeDomainBoundingBox(Domain &iDomain, FloatArray &oLC, FloatArray &oUC)
1775{
1776 // Compute LC and UC by assuming a rectangular domain.
1777 int numNodes = iDomain.giveNumberOfDofManagers();
1778 int nsd = iDomain.giveNumberOfSpatialDimensions();
1779
1780 FloatArray lc = iDomain.giveDofManager(1)->giveCoordinates();
1781 FloatArray uc = iDomain.giveDofManager(1)->giveCoordinates();
1782
1783 for ( int i = 1; i <= numNodes; i++ ) {
1784 DofManager *dMan = iDomain.giveDofManager(i);
1785 const auto &coord = dMan->giveCoordinates();
1786
1787 for ( int j = 0; j < nsd; j++ ) {
1788 if ( coord [ j ] < lc [ j ] ) {
1789 lc [ j ] = coord [ j ];
1790 }
1791
1792 if ( coord [ j ] > uc [ j ] ) {
1793 uc [ j ] = coord [ j ];
1794 }
1795 }
1796 }
1797
1798 oLC = std::move(lc);
1799 oUC = std::move(uc);
1800}
1801
1802int PrescribedGradientBCWeak :: giveSideIndex(const FloatArray &iPos) const
1803{
1804 const double distTol = 1.0e-12;
1805
1806 if ( iPos [ 0 ] > mUC [ 0 ] - distTol ) {
1807 return 0;
1808 }
1809
1810 if ( iPos [ 1 ] > mUC [ 1 ] - distTol ) {
1811 return 1;
1812 }
1813
1814 if ( iPos [ 0 ] < mLC [ 0 ] + distTol ) {
1815 return 2;
1816 }
1817
1818 if ( iPos [ 1 ] < mLC [ 1 ] + distTol ) {
1819 return 3;
1820 }
1821
1822 OOFEM_ERROR("Could not identify side index.")
1823
1824 //return -1;
1825}
1826
1827void PrescribedGradientBCWeak :: findHoleCoord(std::vector<FloatArray> &oHoleCoordUnsorted, std::vector<FloatArray> &oAllCoordUnsorted)
1828{
1829 Set *setPointer = this->giveDomain()->giveSet(this->set);
1830 const IntArray &boundaries = setPointer->giveBoundaryList();
1831
1832 // Loop over boundary nodes and check how many times they occur:
1833 // 1 -> at the edge of an inclusion, therefore must be retained
1834 // 2 -> connected to two segments, optional to keep
1835
1836 std::unordered_map<int,int> map_bnd_node_ind_to_num_occurences;
1837 for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) {
1838
1839 int elIndex = boundaries.at(pos * 2 - 1);
1840 Element *e = this->giveDomain()->giveElement( elIndex );
1841 int boundary = boundaries.at(pos * 2);
1842 const auto &bNodes = e->giveInterpolation()->boundaryGiveNodes(boundary, e->giveGeometryType());
1843 DofManager *startNode = e->giveDofManager(bNodes [ 0 ]);
1844 int startNodeInd = startNode->giveNumber();
1845 DofManager *endNode = e->giveDofManager(bNodes [ 1 ]);
1846 int endNodeInd = endNode->giveNumber();
1847
1848
1849 auto res = map_bnd_node_ind_to_num_occurences.find(startNodeInd);
1850 if ( res != map_bnd_node_ind_to_num_occurences.end() ) {
1851 map_bnd_node_ind_to_num_occurences[startNodeInd]++;
1852 } else {
1853 map_bnd_node_ind_to_num_occurences[startNodeInd] = 1;
1854 }
1855
1856 res = map_bnd_node_ind_to_num_occurences.find(endNodeInd);
1857 if ( res != map_bnd_node_ind_to_num_occurences.end() ) {
1858 map_bnd_node_ind_to_num_occurences[endNodeInd]++;
1859 } else {
1860 map_bnd_node_ind_to_num_occurences[endNodeInd] = 1;
1861 }
1862
1863 }
1864
1865
1866 for ( auto it = map_bnd_node_ind_to_num_occurences.begin(); it != map_bnd_node_ind_to_num_occurences.end(); ++it ) {
1867
1868 bool mandatory_to_keep = false;
1869 if ( it->second == 1 ) {
1870 mandatory_to_keep = true;
1871 }
1872
1873 DofManager *bndNode = domain->giveDofManager(it->first);
1874 const auto &x = bndNode->giveCoordinates();
1875 FloatArray xPlus = x;
1876
1879 }
1880
1881 if ( mandatory_to_keep ) {
1882 oHoleCoordUnsorted.push_back(xPlus);
1883 }
1884
1885 oAllCoordUnsorted.push_back(xPlus);
1886 }
1887}
1888
1889
1890void PrescribedGradientBCWeak :: findCrackBndIntersecCoord(std::vector<FloatArray> &oHoleCoordUnsorted)
1891{
1892 Set *setPointer = this->giveDomain()->giveSet(this->set);
1893 const IntArray &boundaries = setPointer->giveBoundaryList();
1894
1895 for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) {
1896 Element *e = this->giveDomain()->giveElement( boundaries.at(pos * 2 - 1) );
1897 int boundary = boundaries.at(pos * 2);
1898
1899 const auto &bNodes = e->giveInterpolation()->boundaryGiveNodes(boundary, e->giveGeometryType());
1900
1901 // Add the start and end nodes of the segment
1902 DofManager *startNode = e->giveDofManager(bNodes [ 0 ]);
1903 const auto &xS = startNode->giveCoordinates();
1904
1905 DofManager *endNode = e->giveDofManager(bNodes [ 1 ]);
1906 const auto &xE = endNode->giveCoordinates();
1907
1908 FloatArray xC;
1909 xC.beScaled(0.5, xS);
1910 xC.add(0.5, xE);
1911
1912
1913 // Add the points where cracks intersect the boundary
1914 XfemElementInterface *xfemElInt = dynamic_cast< XfemElementInterface * >( e );
1915
1916 if ( xfemElInt && domain->hasXfemManager() ) {
1917 std :: vector< Line >segments;
1918 std :: vector< FloatArray >intersecPoints;
1919 xfemElInt->partitionEdgeSegment(boundary, segments, intersecPoints, mTangDistPadding);
1920
1921 for ( auto x : intersecPoints ) {
1922
1923 if ( pointIsOnGammaPlus(x) ) {
1924 oHoleCoordUnsorted.push_back(x);
1925 } else {
1926 FloatArray xPlus;
1928 oHoleCoordUnsorted.push_back( std::move(xPlus) );
1929 }
1930 }
1931 }
1932 }
1933
1934 // Also add traction nodes where cohesive zone elements intersect the boundary
1935 // TODO: Check later, this should already be covered by the new approach for
1936 // identifying inclusions.
1937}
1938
1939void PrescribedGradientBCWeak :: findPeriodicityCoord(std::vector<FloatArray> &oHoleCoordUnsorted)
1940{
1941 const double l_s = mUC[0] - mLC[0];
1942
1944 FloatArray t = Vec2(n(1),-n(0));
1945
1946 if ( mMirrorFunction == 1 || mMirrorFunction == 2 ) {
1947
1948 if ( fabs(n(1)) <= fabs(n(0)) ) {
1949 // a <= l_s/2
1950 double a = 0.5*l_s*( 1.0 + n(1)/n(0) );
1951
1952 FloatArray p1 = Vec2(2.0*a, 0.0);
1953 FloatArray p1Plus;
1954 giveMirroredPointOnGammaPlus(p1Plus, p1);
1955 oHoleCoordUnsorted.push_back(std::move(p1Plus));
1956 } else {
1957 // a > l_s/2
1958 double c = l_s - 0.5*l_s*( 1.0 + t(1)/t(0) );
1959
1960 FloatArray p1 = Vec2(l_s, l_s-2.0*c);
1961 oHoleCoordUnsorted.push_back(std::move(p1));
1962
1963 FloatArray p2 = Vec2(0, 2.0*c);
1964 FloatArray p2Plus;
1965 giveMirroredPointOnGammaPlus(p2Plus, p2);
1966 oHoleCoordUnsorted.push_back(std::move(p2Plus));
1967 }
1968 }
1969}
1970
1971
1972void PrescribedGradientBCWeak :: removeClosePoints(std::vector<FloatArray> &ioCoords, const double &iAbsTol)
1973{
1974 if ( ioCoords.size() == 0 ) {
1975 return;
1976 }
1977
1978 const double tol2 = iAbsTol*iAbsTol;
1979
1980 std::vector<FloatArray> tmp = { ioCoords[0] };
1981 size_t j = 0;
1982
1983 for ( size_t i = 1; i < ioCoords.size(); i++ ) {
1984 if ( distance_square(ioCoords[i], tmp[j]) > tol2 ) {
1985 tmp.push_back(ioCoords[i]);
1986 j++;
1987 }
1988 }
1989
1990 ioCoords = std::move(tmp);
1991}
1992
1993
1994void PrescribedGradientBCWeak :: removeSegOverHoles(TracSegArray &ioTSeg, const double &iAbsTol)
1995{
1996 // Idea: Loop over segments and check if the center point of each
1997 // segment is located on an element. If not, the segment is
1998 // located over a hole and needs to be removed.
1999
2000 std :: vector< Line > tmp;
2001
2002 SpatialLocalizer *localizer = domain->giveSpatialLocalizer();
2003 const double tol2 = iAbsTol*iAbsTol;
2004
2005 for ( auto &l : ioTSeg.mInteriorSegments ) {
2006 const auto &xS = l.giveVertex(1);
2007 const auto &xE = l.giveVertex(2);
2008 FloatArray xPlus = Vec2(0.5*(xS[0]+xE[0]), 0.5*(xS[1]+xE[1]));
2009
2010 FloatArray lcoordsPlus, closestPlus;
2011 localizer->giveElementClosestToPoint(lcoordsPlus, closestPlus, xPlus);
2012
2013 FloatArray xMinus;
2014 giveMirroredPointOnGammaMinus(xMinus, xPlus);
2015 FloatArray lcoordsMinus, closestMinus;
2016 localizer->giveElementClosestToPoint(lcoordsMinus, closestMinus, xMinus);
2017
2018 if ( !(distance_square(xPlus, closestPlus) > tol2 || distance_square(xMinus, closestMinus) > tol2) ) {
2019 tmp.push_back(l);
2020 }
2021 }
2022
2023 ioTSeg.mInteriorSegments = std::move(tmp);
2024}
2025
2026} /* namespace oofem */
#define N(a, b)
#define E(a, b)
ActiveBoundaryCondition(int n, Domain *d)
Definition activebc.h:71
double calcArcPos(const FloatArray &iPos) const
double calcArcPos(const FloatArray &iPos) const
int giveGlobalNumber() const
Definition dofmanager.h:515
void giveLocationArray(const IntArray &dofIDArry, IntArray &locationArray, const UnknownNumberingScheme &s) const
Definition dofmanager.C:185
const FloatArray & giveCoordinates() const
Definition dofmanager.h:390
void giveUnknownVector(FloatArray &answer, const IntArray &dofMask, ValueModeType mode, TimeStep *tStep, bool padding=false)
Definition dofmanager.C:657
int giveNumberOfDofManagers() const
Returns number of dof managers in domain.
Definition domain.h:461
DofManager * giveDofManager(int n)
Definition domain.C:317
int giveNumberOfSpatialDimensions()
Returns number of spatial dimensions.
Definition domain.C:1137
void setField(int item, InputFieldType id)
virtual FEInterpolation * giveInterpolation() const
Definition element.h:648
virtual int giveSpatialDimension()
Definition element.C:1391
void giveLocationArray(IntArray &locationArray, const UnknownNumberingScheme &s, IntArray *dofIds=NULL) const
Definition element.C:429
virtual int giveNumberOfDofManagers() const
Definition element.h:695
DofManager * giveDofManager(int i) const
Definition element.C:553
virtual IntegrationRule * giveDefaultIntegrationRulePtr()
Definition element.h:886
virtual int giveIPValue(FloatArray &answer, GaussPoint *gp, InternalStateType type, TimeStep *tStep)
Definition element.C:1298
virtual Element_Geometry_Type giveGeometryType() const =0
virtual void assemble(SparseMtrx &answer, TimeStep *tStep, const MatrixAssembler &ma, const UnknownNumberingScheme &s, Domain *domain)
Definition engngm.C:889
virtual IntArray boundaryGiveNodes(int boundary, const Element_Geometry_Type) const =0
virtual void evalN(FloatArray &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const =0
Domain * giveDomain() const
Definition femcmpnn.h:97
Domain * domain
Link to domain object, useful for communicating with other FEM components.
Definition femcmpnn.h:79
int giveNumber() const
Definition femcmpnn.h:104
void assemble(const FloatArray &fe, const IntArray &loc)
Definition floatarray.C:616
double & at(Index i)
Definition floatarray.h:202
std::vector< double >::iterator begin()
Definition floatarray.h:107
void resizeWithValues(Index s, std::size_t allocChunk=0)
Definition floatarray.C:103
static FloatArray fromVector(const std::vector< double > &v)
Definition floatarray.C:131
virtual void printYourself() const
Definition floatarray.C:762
void beDifferenceOf(const FloatArray &a, const FloatArray &b)
Definition floatarray.C:403
void beProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:689
void beScaled(double s, const FloatArray &b)
Definition floatarray.C:208
void beTProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:721
void beVectorForm(const FloatMatrix &aMatrix)
void add(const FloatArray &src)
Definition floatarray.C:218
std::vector< double >::iterator end()
Definition floatarray.h:108
void times(double s)
Definition floatarray.C:834
void times(double f)
void resizeWithData(Index, Index)
Definition floatmatrix.C:91
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
*Sets size of receiver to be an empty matrix It will have zero rows and zero columns size void clear()
void beProductOf(const FloatMatrix &a, const FloatMatrix &b)
void beNMatrixOf(const FloatArray &n, int nsd)
void beTranspositionOf(const FloatMatrix &src)
void zero()
Zeroes all coefficient of receiver.
void beDyadicProductOf(const FloatArray &vec1, const FloatArray &vec2)
int giveNumberOfRows() const
Returns number of rows of receiver.
void assemble(const FloatMatrix &src, const IntArray &loc)
double at(std::size_t i, std::size_t j) const
void beTProductOf(const FloatMatrix &a, const FloatMatrix &b)
void beUnitMatrix()
Sets receiver to unity matrix.
const FloatArray & giveGlobalCoordinates()
Definition gausspoint.h:159
double giveWeight()
Returns integration weight of receiver.
Definition gausspoint.h:180
int set
Set number for boundary condition to be applied to.
void followedBy(const IntArray &b, int allocChunk=0)
Definition intarray.C:94
void enumerate(int maxVal)
Definition intarray.C:85
void resize(int n)
Definition intarray.C:73
bool contains(int value) const
Definition intarray.h:292
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
virtual void assembleExtraDisplock(SparseMtrx &answer, TimeStep *tStep, CharType type, const UnknownNumberingScheme &r_s, const UnknownNumberingScheme &c_s)
virtual void giveTractionLocationArray(IntArray &rows, const UnknownNumberingScheme &s)
void giveMirroredPointOnGammaMinus(FloatArray &oPosMinus, const FloatArray &iPosPlus) const
void removeSegOverHoles(TracSegArray &ioTSeg, const double &iAbsTol)
virtual void giveBoundaryCoordVector(FloatArray &oX, const FloatArray &iPos) const =0
void findPeriodicityCoord(std::vector< FloatArray > &oHoleCoordUnsorted)
const IntArray & giveDispLockDofIDs() const
void postInitialize() override
Performs post initialization steps. Called after all components are created and initialized.
virtual void assembleGPContrib(SparseMtrx &answer, TimeStep *tStep, CharType type, const UnknownNumberingScheme &r_s, const UnknownNumberingScheme &c_s, TracSegArray &iEl, GaussPoint &iGP, double k, void *lock=nullptr)
void splitSegments(std ::vector< TracSegArray > &ioElArray)
void findCrackBndIntersecCoord(std::vector< FloatArray > &oHoleCoordUnsorted)
void computeIntForceGPContrib(FloatArray &oContrib_disp, IntArray &oDisp_loc_array, FloatArray &oContrib_trac, IntArray &oTrac_loc_array, TracSegArray &iEl, GaussPoint &iGP, int iDim, TimeStep *tStep, const FloatArray &iBndCoord, const double &iScaleFac, ValueModeType mode, CharType type, const UnknownNumberingScheme &s)
const IntArray & giveRegularDispDofIDs() const
void compute_x_times_N_1(FloatMatrix &o_x_times_N)
void removeClosePoints(std::vector< FloatArray > &ioCoords, const double &iAbsTol)
std ::vector< TracSegArray > mpTracElNew
Elements for the independent traction discretization.
void giveTractionElCoord(size_t iElInd, FloatArray &oStartCoord, FloatArray &oEndCoord) const
void assembleTangentGPContributionNew(FloatMatrix &oTangent, TracSegArray &iEl, GaussPoint &iGP, const double &iScaleFactor, const FloatArray &iBndCoord)
FloatArray mUC
Upper corner of domain (assuming a rectangular RVE).
bool pointIsOnGammaPlus(const FloatArray &iPos) const
FloatArray mLC
Lower corner of domain (assuming a rectangular RVE).
int giveSideIndex(const FloatArray &iPos) const
virtual bool boundaryPointIsOnActiveBoundary(const FloatArray &iPos) const =0
std::unique_ptr< Node > mpDisplacementLock
Lock displacements in one node if periodic.
int mTractionInterpOrder
Order of interpolation for traction (0->piecewise constant, 1->piecewise linear).
void giveMirroredPointOnGammaPlus(FloatArray &oPosPlus, const FloatArray &iPosMinus) const
void computeExtForceElContrib(FloatArray &oContrib, TracSegArray &iEl, int iDim, TimeStep *tStep)
void findHoleCoord(std::vector< FloatArray > &oHoleCoordUnsorted, std::vector< FloatArray > &oAllCoordUnsorted)
const IntArray & giveBoundaryList()
Definition set.C:160
virtual int assemble(const IntArray &loc, const FloatMatrix &mat)=0
virtual Node * giveNodeClosestToPoint(const FloatArray &coords, double maxDist)=0
virtual Element * giveElementClosestToPoint(FloatArray &lcoords, FloatArray &closest, const FloatArray &coords, int region=0)=0
std ::unique_ptr< SparseMtrx > stiffnessMatrix
double giveTargetTime()
Returns target time.
Definition timestep.h:164
double getUtime()
Returns total user time elapsed in seconds.
Definition timer.C:105
void startTimer()
Definition timer.C:69
void stopTimer()
Definition timer.C:77
std ::unique_ptr< IntegrationRule > mIntRule
std ::vector< Line > mInteriorSegments
std ::vector< Line > mInteriorSegmentsFine
std ::unique_ptr< Node > mFirstNode
void giveTractionLocationArray(IntArray &rows, CharType type, const UnknownNumberingScheme &s)
void XfemElementInterface_createEnrNmatrixAt(FloatMatrix &oAnswer, const FloatArray &iLocCoord, Element &iEl, bool iSetDiscontContribToZero)
Creates enriched N-matrix.
void partitionEdgeSegment(int iBndIndex, std ::vector< Line > &oSegments, std ::vector< FloatArray > &oIntersectionPoints, const double &iTangDistPadding=0.0)
const IntArray & giveEnrichedDofIDs() const
#define OOFEM_ERROR(...)
Definition error.h:79
#define IR_GIVE_OPTIONAL_FIELD(__ir, __value, __id)
Definition inputrecord.h:75
#define IR_GIVE_FIELD(__ir, __value, __id)
Definition inputrecord.h:67
#define M_PI
Definition mathfem.h:52
#define S(p)
Definition mdm.C:469
static FloatArray Vec2(const double &a, const double &b)
Definition floatarray.h:606
static FloatArray Vec6(const double &a, const double &b, const double &c, const double &d, const double &e, const double &f)
Definition floatarray.h:610
ClassFactory & classFactory
double distance_square(const FloatArray &x, const FloatArray &y)
static FloatArray Vec1(const double &a)
Definition floatarray.h:605
#define _IFT_PrescribedGradientBCWeak_PeriodicityNormal
#define _IFT_PrescribedGradientBCWeak_DuplicateCornerNodes
#define _IFT_PrescribedGradientBCWeak_MirrorFunction
#define _IFT_PrescribedGradientBCWeak_TangDistPadding
#define _IFT_PrescribedGradientBCWeak_NumTractionNodeSpacing
#define _IFT_PrescribedGradientBCWeak_TracDofScaling
#define _IFT_PrescribedGradientBCWeak_NumTractionNodesAtIntersections
#define _IFT_PrescribedGradientBCWeak_TractionInterpOrder

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011