OOFEM 3.0
Loading...
Searching...
No Matches
xfemstructuralelementinterface.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
41#include "gausspoint.h"
42#include "dynamicinputrecord.h"
43#include "feinterpol.h"
44#include "spatiallocalizer.h"
45#include "engngm.h"
47#include "mathfem.h"
48
51
54#include "xfem/XFEMDebugTools.h"
55#include "xfem/xfemtolerances.h"
56
59
60#include "vtkxmlexportmodule.h"
61
63#include "mathfem.h"
64#include <cmath>
65
66#include <string>
67#include <sstream>
68
69
71//
72// Alt. I : include_bulk_jump = 1 and include_bulk_corr = 1
73//
74// Alt. II : include_bulk_jump = 1 and include_bulk_corr = 0
75//
76// Alt. III: include_bulk_jump = 0 and include_bulk_corr = 0
77
78
79namespace oofem {
80XfemStructuralElementInterface :: XfemStructuralElementInterface(Element *e) :
82{
84 mUsePlaneStrain = false;
85}
86
87bool XfemStructuralElementInterface :: XfemElementInterface_updateIntegrationRule()
88{
89 const double tol2 = 1.0e-18;
90
91 bool partitionSucceeded = false;
92
93
94 if ( mpCZMat != nullptr ) {
97 mIntRule_tmp.clear();
98 mCZEnrItemIndices.clear();
100 }
101
102 XfemManager *xMan = this->element->giveDomain()->giveXfemManager();
103 if ( xMan->isElementEnriched(element) ) {
104 if ( mpCZMat == nullptr && mCZMaterialNum > 0 ) {
106 }
107
108
109 MaterialMode matMode = element->giveMaterialMode();
110
111 bool firstIntersection = true;
112
113 std :: vector< std :: vector< FloatArray > >pointPartitions;
114 mSubTri.clear();
115
116 std :: vector< int >enrichingEIs;
117 int elPlaceInArray = xMan->giveDomain()->giveElementPlaceInArray( element->giveGlobalNumber() );
118 xMan->giveElementEnrichmentItemIndices(enrichingEIs, elPlaceInArray);
119
120
121 for ( size_t p = 0; p < enrichingEIs.size(); p++ ) {
122 // Index of current ei
123 int eiIndex = enrichingEIs [ p ];
124
125 // Indices of other ei interaction with this ei through intersection enrichment fronts.
126 std :: vector< int >touchingEiIndices;
127 giveIntersectionsTouchingCrack(touchingEiIndices, enrichingEIs, eiIndex, * xMan);
128
129 if ( firstIntersection ) {
130
131 // Get the points describing each subdivision of the element
132 double startXi, endXi;
133 bool intersection = false;
134 this->XfemElementInterface_prepareNodesForDelaunay(pointPartitions, startXi, endXi, eiIndex, intersection);
135
136 if ( intersection ) {
137 firstIntersection = false;
138
139 // Use XfemElementInterface_partitionElement to subdivide the element
140 for ( auto &partition : pointPartitions ) {
141 // Triangulate the subdivisions
143 }
144
145
146 if ( mpCZMat != nullptr ) {
147 Crack *crack = dynamic_cast< Crack * >( xMan->giveEnrichmentItem(eiIndex) );
148 if ( crack == nullptr ) {
149 OOFEM_ERROR("Cohesive zones are only available for cracks.")
150 }
151
152 // We have xi_s and xi_e. Fetch sub polygon.
153 std :: vector< FloatArray >crackPolygon;
154 crack->giveSubPolygon(crackPolygon, startXi, endXi);
155
157 // Add cohesive zone Gauss points
158 size_t numSeg = crackPolygon.size() - 1;
159
160 for ( size_t segIndex = 0; segIndex < numSeg; segIndex++ ) {
161 int czRuleNum = 1;
162 mpCZIntegrationRules_tmp.push_back( std::make_unique<GaussIntegrationRule>(czRuleNum, element) );
163
164 if ( mIncludeBulkCorr ) {
165 mpCZExtraIntegrationRules_tmp.push_back( std::make_unique<GaussIntegrationRule>(czRuleNum, element) );
166 }
167
168 size_t cz_rule_ind = mpCZIntegrationRules_tmp.size() - 1;
169
170 // Add index of current ei
171 mCZEnrItemIndices.push_back(eiIndex);
172
173 // Add indices of other ei, that cause interaction through
174 // intersection enrichment fronts
175 mCZTouchingEnrItemIndices.push_back(touchingEiIndices);
176
177 // Compute crack normal
178 FloatArray crackTang;
179 crackTang.beDifferenceOf(crackPolygon [ segIndex + 1 ], crackPolygon [ segIndex ]);
180
181 if ( crackTang.computeSquaredNorm() > tol2 ) {
182 crackTang.normalize();
183 } else {
184 // Oops, we got a segment of length zero.
185 // These Gauss weights will be zero, so we can
186 // set the tangent to anything reasonable
187 crackTang = Vec2(0.0, 1.0);
188 }
189
190 FloatArray crackNormal = Vec3(
191 -crackTang.at(2), crackTang.at(1), 0.
192 );
193
194 mpCZIntegrationRules_tmp [ cz_rule_ind ]->SetUpPointsOn2DEmbeddedLine(mCSNumGaussPoints, matMode,
195 crackPolygon [ segIndex ], crackPolygon [ segIndex + 1 ]);
196
197 if ( mIncludeBulkCorr ) {
198 mpCZExtraIntegrationRules_tmp [ cz_rule_ind ]->SetUpPointsOn2DEmbeddedLine(mCSNumGaussPoints, matMode,
199 crackPolygon [ segIndex ], crackPolygon [ segIndex + 1 ]);
200 }
201
202 for ( auto &gp: *mpCZIntegrationRules_tmp [ cz_rule_ind ] ) {
203 double gw = gp->giveWeight();
204 double segLength = distance(crackPolygon [ segIndex ], crackPolygon [ segIndex + 1 ]);
205 gw *= 0.5 * segLength;
206 gp->setWeight(gw);
207
208 // Fetch material status and set normal
209 StructuralInterfaceMaterialStatus *ms = dynamic_cast< StructuralInterfaceMaterialStatus * >( mpCZMat->giveStatus(gp) );
210 if ( ms ) {
211 ms->letNormalBe(crackNormal);
212 } else {
213 StructuralFE2MaterialStatus *fe2ms = dynamic_cast<StructuralFE2MaterialStatus*>( mpCZMat->giveStatus(gp) );
214
215 if ( fe2ms ) {
216 fe2ms->letNormalBe(crackNormal);
217
218 PrescribedGradientBCWeak *bc = dynamic_cast<PrescribedGradientBCWeak*>( fe2ms->giveBC() );
219
220 if ( bc ) {
221 FloatArray periodicityNormal = crackNormal;
222
223 periodicityNormal.normalize();
224
225 if ( periodicityNormal(0) < 0.0 && periodicityNormal(1) < 0.0 ) {
226 // Rotate 90 degrees (works equally well for periodicity)
227 periodicityNormal = Vec2(periodicityNormal(1), -periodicityNormal(0));
228 }
229
230 bc->setPeriodicityNormal(periodicityNormal);
232 }
233 } else {
234 OOFEM_ERROR("Failed to fetch material status.");
235 }
236 }
237
238 // Give Gauss point reference to the enrichment item
239 // to simplify post processing.
241 }
242
243
244 if ( mIncludeBulkCorr ) {
245 for ( auto &gp: *mpCZExtraIntegrationRules_tmp [ cz_rule_ind ] ) {
246 double gw = gp->giveWeight();
247 double segLength = distance(crackPolygon [ segIndex ], crackPolygon [ segIndex + 1 ]);
248 gw *= 0.5 * segLength;
249 gp->setWeight(gw);
250
251 // Fetch material status and set normal
252 StructuralInterfaceMaterialStatus *ms = dynamic_cast< StructuralInterfaceMaterialStatus * >( mpCZMat->giveStatus(gp) );
253 if ( ms ) {
254 ms->letNormalBe(crackNormal);
255 } else {
256 StructuralFE2MaterialStatus *fe2ms = dynamic_cast<StructuralFE2MaterialStatus*>( mpCZMat->giveStatus(gp) );
257
258 if ( fe2ms ) {
259 fe2ms->letNormalBe(crackNormal);
260
261 PrescribedGradientBCWeak *bc = dynamic_cast<PrescribedGradientBCWeak*>( fe2ms->giveBC() );
262
263 if ( bc) {
264 FloatArray periodicityNormal = crackNormal;
265 periodicityNormal.normalize();
266
267 if ( periodicityNormal(0) < 0.0 && periodicityNormal(1) < 0.0 ) {
268 // Rotate 90 degrees (works equally well for periodicity)
269 periodicityNormal = Vec2(periodicityNormal(1), -periodicityNormal(0));
270 }
271
272 bc->setPeriodicityNormal(periodicityNormal);
274
275 }
276 } else {
277 // Macroscale material model: nothing needs to be done.
278 }
279 }
280 }
281 }
282 }
283 }
284
285 partitionSucceeded = true;
286 }
287 } else { // if ( firstIntersection )
288 // Loop over triangles
289 std :: vector< Triangle >allTriCopy;
290 for ( size_t triIndex = 0; triIndex < mSubTri.size(); triIndex++ ) {
291 // Call alternative version of XfemElementInterface_prepareNodesForDelaunay
292 std :: vector< std :: vector< FloatArray > >pointPartitionsTri;
293 double startXi, endXi;
294 bool intersection = false;
295 XfemElementInterface_prepareNodesForDelaunay(pointPartitionsTri, startXi, endXi, mSubTri [ triIndex ], eiIndex, intersection);
296
297 if ( intersection ) {
298 // Use XfemElementInterface_partitionElement to subdivide triangle j
299 for ( int i = 0; i < int ( pointPartitionsTri.size() ); i++ ) {
300 this->XfemElementInterface_partitionElement(allTriCopy, pointPartitionsTri [ i ]);
301 }
302
303
304 // Add cohesive zone Gauss points
305
306 if ( mpCZMat != nullptr ) {
307 Crack *crack = dynamic_cast< Crack * >( xMan->giveEnrichmentItem(eiIndex) );
308 if ( crack == nullptr ) {
309 OOFEM_ERROR("Cohesive zones are only available for cracks.")
310 }
311
312 // We have xi_s and xi_e. Fetch sub polygon.
313 std :: vector< FloatArray >crackPolygon;
314 crack->giveSubPolygon(crackPolygon, startXi, endXi);
315
316 int numSeg = crackPolygon.size() - 1;
317
318 for ( int segIndex = 0; segIndex < numSeg; segIndex++ ) {
319 int czRuleNum = 1;
320 mpCZIntegrationRules_tmp.emplace_back( std::make_unique<GaussIntegrationRule>(czRuleNum, element) );
321
322 if ( mIncludeBulkCorr ) {
323 mpCZExtraIntegrationRules_tmp.emplace_back( std::make_unique<GaussIntegrationRule>(czRuleNum, element) );
324 }
325
326 size_t newRuleInd = mpCZIntegrationRules_tmp.size() - 1;
327 mCZEnrItemIndices.push_back(eiIndex);
328
329 mCZTouchingEnrItemIndices.push_back(touchingEiIndices);
330
331 // Compute crack normal
332 FloatArray crackTang;
333 crackTang.beDifferenceOf(crackPolygon [ segIndex + 1 ], crackPolygon [ segIndex ]);
334
335 if ( crackTang.computeSquaredNorm() > tol2 ) {
336 crackTang.normalize();
337 } else {
338 // Oops, we got a segment of length zero.
339 // These Gauss weights will be zero, so we can
340 // set the tangent to anything reasonable
341 crackTang = Vec2(0.0, 1.0);
342 }
343
344 FloatArrayF<3> crackNormal = { -crackTang.at(2), crackTang.at(1), 0.};
345
346 mpCZIntegrationRules_tmp [ newRuleInd ]->SetUpPointsOn2DEmbeddedLine(mCSNumGaussPoints, matMode,
347 crackPolygon [ segIndex ], crackPolygon [ segIndex + 1 ]);
348
349 if ( mIncludeBulkCorr ) {
350 mpCZExtraIntegrationRules_tmp [ newRuleInd ]->SetUpPointsOn2DEmbeddedLine(mCSNumGaussPoints, matMode,
351 crackPolygon [ segIndex ], crackPolygon [ segIndex + 1 ]);
352 }
353
354 for ( auto &gp: *mpCZIntegrationRules_tmp [ newRuleInd ] ) {
355 double gw = gp->giveWeight();
356 double segLength = distance(crackPolygon [ segIndex ], crackPolygon [ segIndex + 1 ]);
357 gw *= 0.5 * segLength;
358 gp->setWeight(gw);
359
360 // Fetch material status and set normal
361 StructuralInterfaceMaterialStatus *ms = dynamic_cast< StructuralInterfaceMaterialStatus * >( mpCZMat->giveStatus(gp) );
362 if ( ms ) {
363 ms->letNormalBe(crackNormal);
364 } else {
365 StructuralFE2MaterialStatus *fe2ms = dynamic_cast<StructuralFE2MaterialStatus*>( mpCZMat->giveStatus(gp) );
366
367 if ( fe2ms ) {
368 fe2ms->letNormalBe(crackNormal);
369
370 PrescribedGradientBCWeak *bc = dynamic_cast<PrescribedGradientBCWeak*>( fe2ms->giveBC() );
371
372 if ( bc ) {
373 FloatArray periodicityNormal = crackNormal;
374
375 periodicityNormal.normalize();
376
377 if ( periodicityNormal(0) < 0.0 && periodicityNormal(1) < 0.0 ) {
378 // Rotate 90 degrees (works equally well for periodicity)
379 periodicityNormal = Vec2(periodicityNormal(1), -periodicityNormal(0));
380 }
381
382 bc->setPeriodicityNormal(periodicityNormal);
384 }
385 } else {
386 OOFEM_ERROR("Failed to fetch material status.");
387 }
388 }
389
390 // Give Gauss point reference to the enrichment item
391 // to simplify post processing.
393 }
394
395 if ( mIncludeBulkCorr ) {
396
397 for ( auto &gp: *mpCZExtraIntegrationRules_tmp [ newRuleInd ] ) {
398 double gw = gp->giveWeight();
399 double segLength = distance(crackPolygon [ segIndex ], crackPolygon [ segIndex + 1 ]);
400 gw *= 0.5 * segLength;
401 gp->setWeight(gw);
402
403
404 // Fetch material status and set normal
405 StructuralInterfaceMaterialStatus *ms = dynamic_cast< StructuralInterfaceMaterialStatus * >( mpCZMat->giveStatus(gp) );
406 if ( ms ) {
407 ms->letNormalBe(crackNormal);
408 } else {
409 StructuralFE2MaterialStatus *fe2ms = dynamic_cast<StructuralFE2MaterialStatus*>( mpCZMat->giveStatus(gp) );
410
411 if ( fe2ms ) {
412 fe2ms->letNormalBe(crackNormal);
413
414 PrescribedGradientBCWeak *bc = dynamic_cast<PrescribedGradientBCWeak*>( fe2ms->giveBC() );
415
416 if ( bc ) {
417 FloatArray periodicityNormal = crackNormal;
418
419 periodicityNormal.normalize();
420
421 if ( periodicityNormal(0) < 0.0 && periodicityNormal(1) < 0.0 ) {
422 // Rotate 90 degrees (works equally well for periodicity)
423 periodicityNormal = Vec2(periodicityNormal(1), -periodicityNormal(0));
424 }
425
426 bc->setPeriodicityNormal(periodicityNormal);
428 }
429 } else {
430 OOFEM_ERROR("Failed to fetch material status.");
431 }
432 }
433
434 // Give Gauss point reference to the enrichment item
435 // to simplify post processing.
437 }
438 }
439 }
440 }
441 } else {
442 allTriCopy.push_back(mSubTri [ triIndex ]);
443 }
444 }
445
446 mSubTri = allTriCopy;
447 }
448 }
449
450 // Refine triangles if desired
451 int numRefs = xMan->giveNumTriRefs();
452
453 for ( int i = 0; i < numRefs; i++ ) {
454 std :: vector< Triangle > triRef;
455 for ( const auto &tri : mSubTri ) {
456 Triangle::refineTriangle(triRef, tri);
457 }
458 mSubTri = triRef;
459 }
460
462 // When we reach this point, we have a
463 // triangulation that is adapted to all
464 // cracks passing through the element.
465 // Therefore, we can set up integration
466 // points on each triangle.
467
468// printf("totalCrackLengthInEl: %e\n", totalCrackLengthInEl);
469
470 if ( xMan->giveVtkDebug() ) {
471 std :: stringstream str3;
472 int elIndex = this->element->giveGlobalNumber();
473 str3 << "TriEl" << elIndex << ".vtk";
474 std :: string name3 = str3.str();
475
476 if ( mSubTri.size() > 0 ) {
477 XFEMDebugTools :: WriteTrianglesToVTK(name3, mSubTri);
478 }
479 }
480
481
482 int ruleNum = 1;
483
484 if ( partitionSucceeded ) {
485 std :: vector< std :: unique_ptr< IntegrationRule > >intRule;
486 mIntRule_tmp.push_back( std::make_unique<PatchIntegrationRule>(ruleNum, element, mSubTri) );
487 mIntRule_tmp [ 0 ]->SetUpPointsOnTriangle(xMan->giveNumGpPerTri(), matMode);
488 }
489
490
491 if ( xMan->giveVtkDebug() ) {
493 // Write CZ GP to VTK
494
495 std :: vector< FloatArray >czGPCoord;
496
497 for ( size_t czRulInd = 0; czRulInd < mpCZIntegrationRules_tmp.size(); czRulInd++ ) {
498 for ( auto &gp: *mpCZIntegrationRules_tmp [ czRulInd ] ) {
499 czGPCoord.push_back( gp->giveGlobalCoordinates() );
500 }
501 }
502
503 double time = 0.0;
504
505 Domain *dom = element->giveDomain();
506 if ( dom != nullptr ) {
507 EngngModel *em = dom->giveEngngModel();
508 if ( em != nullptr ) {
509 TimeStep *ts = em->giveCurrentStep();
510 if ( ts != nullptr ) {
511 time = ts->giveTargetTime();
512 }
513 }
514 }
515
516 std :: stringstream str;
517 int elIndex = this->element->giveGlobalNumber();
518 str << "CZGaussPointsTime" << time << "El" << elIndex << ".vtk";
519 std :: string name = str.str();
520
521 XFEMDebugTools :: WritePointsToVTK(name, czGPCoord);
523 }
524
525
526 bool map_state_variables = true;
527 if ( map_state_variables ) {
528
530 // Copy bulk GPs
531 int num_ir_new = mIntRule_tmp.size();
532 for ( int i = 0; i < num_ir_new; i++ ) {
533
534 for ( auto &gp_new : *mIntRule_tmp[i] ) {
535
536
537 // Fetch new material status. Create it if it does not exist.
538 if (gp_new->hasMaterialStatus() == false) {
539 StructuralElement *s_el = dynamic_cast<StructuralElement*>(element);
541 cs->createMaterialStatus(*gp_new);
542 }
543 MaterialStatus *ms_new = dynamic_cast<MaterialStatus*>( element->giveCrossSection()->giveMaterial(gp_new)->giveStatus(gp_new) );
544
545 // Find closest old GP.
546 double closest_dist = 0.0;
547 MaterialStatus *ms_old = giveClosestGP_MatStat( closest_dist, element->giveIntegrationRulesArray() , gp_new->giveGlobalCoordinates());
548
549 if ( ms_old ) {
550 // Copy state variables.
551 MaterialStatusMapperInterface *mapper_interface = dynamic_cast<MaterialStatusMapperInterface*>( ms_new );
552
553 if ( mapper_interface ) {
554 //printf("Successfully casted to MaterialStatusMapperInterface.\n");
555 mapper_interface->copyStateVariables(*ms_old);
556 } else {
557 OOFEM_ERROR("Failed casting to MaterialStatusMapperInterface.")
558 }
559 }
560
561 }
562
563 }
564
566 // Copy CZ GPs
567 if ( mCZMaterialNum > 0 ) {
568
569 num_ir_new = mpCZIntegrationRules_tmp.size();
570 for ( int i = 0; i < num_ir_new; i++ ) {
571
572 for ( auto &gp_new : *(mpCZIntegrationRules_tmp[i]) ) {
573
574 // Fetch new material status. Create it if it does not exist.
575 MaterialStatus *ms_new = mpCZMat->giveStatus(gp_new);
576
577 // Find closest old GP.
578 double closest_dist_cz = 0.0;
579 MaterialStatus *ms_old = giveClosestGP_MatStat(closest_dist_cz, mpCZIntegrationRules , gp_new->giveGlobalCoordinates());
580
581 // If we are using the nonstandard cz formulation, we
582 // also consider mapping from bulk GPs.
583 XfemStructureManager *xsMan = dynamic_cast<XfemStructureManager*>( element->giveDomain()->giveXfemManager() );
584 bool non_std_cz = false;
585 if ( xsMan ) {
586 non_std_cz = xsMan->giveUseNonStdCz();
587 }
588
589 if ( non_std_cz ) {
590 double closest_dist_bulk = 0.0;
591 MaterialStatus *ms_old_bulk = giveClosestGP_MatStat(closest_dist_bulk, element->giveIntegrationRulesArray() , gp_new->giveGlobalCoordinates());
592 if ( closest_dist_bulk < closest_dist_cz ) {
593 printf("Bulk is closest. Dist: %e\n", closest_dist_bulk);
594 ms_old = ms_old_bulk;
595 }
596 }
597
598 if ( ms_old ) {
599
600 // Copy state variables.
601 MaterialStatusMapperInterface *mapper_interface = dynamic_cast<MaterialStatusMapperInterface*>( ms_new );
602
603 if ( mapper_interface ) {
604 mapper_interface->copyStateVariables(*ms_old);
605 } else {
606 OOFEM_ERROR("Failed casting to MaterialStatusMapperInterface.")
607 }
608 }
609
610 }
611 }
612 }
613
615 // Copy "extra" CZ GPs (Used for non-standard CZ model)
616 if ( mCZMaterialNum > 0 && mIncludeBulkCorr ) {
617
618 num_ir_new = mpCZExtraIntegrationRules_tmp.size();
619 for ( int i = 0; i < num_ir_new; i++ ) {
620
621 for ( auto &gp_new : *(mpCZExtraIntegrationRules_tmp[i]) ) {
622
623 // Fetch new material status. Create it if it does not exist.
624 MaterialStatus *ms_new = mpCZMat->giveStatus(gp_new);
625
626 // Find closest old GP.
627 double closest_dist_cz = 0.0;
628 MaterialStatus *ms_old = giveClosestGP_MatStat(closest_dist_cz, mpCZExtraIntegrationRules , gp_new->giveGlobalCoordinates());
629
630 // If we are using the nonstandard cz formulation, we
631 // also consider mapping from bulk GPs.
632 XfemStructureManager *xsMan = dynamic_cast<XfemStructureManager*>( element->giveDomain()->giveXfemManager() );
633 bool non_std_cz = false;
634 if ( xsMan ) {
635 non_std_cz = xsMan->giveUseNonStdCz();
636 }
637
638 if ( non_std_cz ) {
639 double closest_dist_bulk = 0.0;
640 MaterialStatus *ms_old_bulk = giveClosestGP_MatStat(closest_dist_bulk, element->giveIntegrationRulesArray() , gp_new->giveGlobalCoordinates());
641 if ( closest_dist_bulk < closest_dist_cz ) {
642 printf("Bulk is closest. Dist: %e\n", closest_dist_bulk);
643 ms_old = ms_old_bulk;
644 }
645 }
646
647 if ( ms_old ) {
648
649 // Copy state variables.
650 MaterialStatusMapperInterface *mapper_interface = dynamic_cast<MaterialStatusMapperInterface*>( ms_new );
651
652 if ( mapper_interface ) {
653 mapper_interface->copyStateVariables(*ms_old);
654 } else {
655 OOFEM_ERROR("Failed casting to MaterialStatusMapperInterface.")
656 }
657 }
658
659 }
660 }
661 } else {
662 //printf("No extra CZ GPs to map.\n");
663 }
664 }
665 }
666
667 if ( partitionSucceeded ) {
669
670 if ( mIncludeBulkCorr ) {
672 }
673
674 element->setIntegrationRules( std :: move(mIntRule_tmp) );
675 }
676
677 return partitionSucceeded;
678}
679
680MaterialStatus* XfemStructuralElementInterface :: giveClosestGP_MatStat(double &oClosestDist, std :: vector< std :: unique_ptr< IntegrationRule > > &iRules, const FloatArray &iCoord)
681{
682 double min_dist2 = std::numeric_limits<double>::max();
683 MaterialStatus *closest_ms = nullptr;
684
685 for ( size_t i = 0; i < iRules.size(); i++ ) {
686 for ( auto &gp : *(iRules[i]) ) {
687
688 const FloatArray &x = gp->giveGlobalCoordinates();
689 double d2 = distance_square(x, iCoord);
690 if ( d2 < min_dist2 ) {
691 min_dist2 = d2;
692 closest_ms = dynamic_cast<MaterialStatus*>( gp->giveMaterialStatus() );
693 }
694
695 }
696 }
697
698 oClosestDist = sqrt(min_dist2);
699 return closest_ms;
700}
701
702double XfemStructuralElementInterface :: computeEffectiveSveSize(StructuralFE2MaterialStatus *iFe2Ms)
703{
704
705#if 0
706 //return 1.0*sqrt( iFe2Ms->giveBC()->domainSize() );
707 //return 2.0*sqrt( iFe2Ms->giveBC()->domainSize() );
708
709#else
710 // TODO: Cover also angle < 0 and angle > 90.
711
712 const FloatArray &n = iFe2Ms->giveNormal();
713 double l_box = sqrt( iFe2Ms->giveBC()->domainSize() );
714
715 const FloatArray t = Vec2(n(1), -n(0));
716 double angle = atan2( t(1), t(0) );
717
718 if ( angle < 0.25*M_PI ) {
719 // angle < 45 degrees
720
721 double l_s = l_box*(cos(angle));
722 return l_s;
723 } else {
724 // angle >= 45 degrees
725
726 double l_s = l_box*(sin(angle));
727 return l_s;
728 }
729#endif
730}
731
732void XfemStructuralElementInterface :: XfemElementInterface_computeConstitutiveMatrixAt(FloatMatrix &answer, MatResponseMode rMode, GaussPoint *gp, TimeStep *tStep)
733{
734 if ( element->giveDomain()->hasXfemManager() ) {
735 XfemManager *xMan = element->giveDomain()->giveXfemManager();
736 CrossSection *cs = nullptr;
737
738 const std :: vector< int > &materialModifyingEnrItemIndices = xMan->giveMaterialModifyingEnrItemIndices();
739 for ( size_t i = 0; i < materialModifyingEnrItemIndices.size(); i++ ) {
740 EnrichmentItem &ei = * ( xMan->giveEnrichmentItem(materialModifyingEnrItemIndices [ i ]) );
741
742 if ( ei.isMaterialModified(* gp, * element, cs) ) {
743 StructuralCrossSection *structCS = dynamic_cast< StructuralCrossSection * >( cs );
744
745 if ( structCS != nullptr ) {
746 if ( mUsePlaneStrain ) {
747 answer = structCS->giveStiffnessMatrix_PlaneStrain(rMode, gp, tStep);
748 } else {
749 answer = structCS->giveStiffnessMatrix_PlaneStress(rMode, gp, tStep);
750 }
751 return;
752 } else {
753 OOFEM_ERROR("failed to fetch StructuralMaterial");
754 }
755 }
756 }
757 }
758
759 // If no enrichment modifies the material,
760 // compute stiffness based on the bulk material.
761 auto cs = dynamic_cast< StructuralCrossSection * >( element->giveCrossSection() );
762 if ( mUsePlaneStrain ) {
763 answer = cs->giveStiffnessMatrix_PlaneStrain(rMode, gp, tStep);
764 } else {
765 answer = cs->giveStiffnessMatrix_PlaneStress(rMode, gp, tStep);
766 }
767}
768
769void XfemStructuralElementInterface :: XfemElementInterface_computeStressVector(FloatArray &answer, const FloatArray &strain, GaussPoint *gp, TimeStep *tStep)
770{
771 auto cs = dynamic_cast< StructuralCrossSection * >( element->giveCrossSection() );
772 if ( cs == nullptr ) {
773 OOFEM_ERROR("cs == nullptr.");
774 }
775
776 if ( element->giveDomain()->hasXfemManager() ) {
777 XfemManager *xMan = element->giveDomain()->giveXfemManager();
778
779
780 CrossSection *csInclusion = nullptr;
781 const std :: vector< int > &materialModifyingEnrItemIndices = xMan->giveMaterialModifyingEnrItemIndices();
782 for ( size_t i = 0; i < materialModifyingEnrItemIndices.size(); i++ ) {
783 EnrichmentItem &ei = * ( xMan->giveEnrichmentItem(materialModifyingEnrItemIndices [ i ]) );
784
785 if ( ei.isMaterialModified(* gp, * element, csInclusion) ) {
786 auto structCSInclusion = dynamic_cast< StructuralCrossSection * >( csInclusion );
787
788 if ( structCSInclusion != nullptr ) {
789 if ( mUsePlaneStrain ) {
790 answer = structCSInclusion->giveRealStress_PlaneStrain(strain, gp, tStep);
791 } else {
792 answer = structCSInclusion->giveRealStress_PlaneStress(strain, gp, tStep);
793 }
794
795 return;
796 } else {
797 OOFEM_ERROR("failed to fetch StructuralCrossSection");
798 }
799 }
800 }
801 }
802
803 // If no enrichment modifies the material:
804 if ( mUsePlaneStrain ) {
805 answer = cs->giveRealStress_PlaneStrain(strain, gp, tStep);
806 } else {
807 answer = cs->giveRealStress_PlaneStress(strain, gp, tStep);
808 }
809}
810
811void XfemStructuralElementInterface :: computeCohesiveForces(FloatArray &answer, TimeStep *tStep)
812{
813 if ( !useNonStdCz() ) {
814
815 if ( hasCohesiveZone() ) {
816 FloatArray solVec;
817 element->computeVectorOf(VM_Total, tStep, solVec);
818
819 size_t numSeg = mpCZIntegrationRules.size();
820 for ( size_t segIndex = 0; segIndex < numSeg; segIndex++ ) {
821 for ( auto &gp: *mpCZIntegrationRules [ segIndex ] ) {
823 // Compute a (slightly modified) N-matrix
824
825 FloatMatrix NMatrix;
826 computeNCohesive(NMatrix, * gp, mCZEnrItemIndices [ segIndex ], mCZTouchingEnrItemIndices [ segIndex ]);
828
829
830 // Traction
831 FloatArray T2D;
832
833
834 // Fetch material status and get normal
835 StructuralInterfaceMaterialStatus *ms = dynamic_cast< StructuralInterfaceMaterialStatus * >( mpCZMat->giveStatus(gp) );
836 if ( ms == nullptr ) {
837 OOFEM_ERROR("Failed to fetch material status.");
838 }
839
840 ms->setNewlyInserted(false); //TODO: Do this in a better place. /ES
841
842 FloatArray crackNormal( ms->giveNormal() );
843
844 // Compute jump vector
845 FloatArray jump2D;
846 computeDisplacementJump(* gp, jump2D, solVec, NMatrix);
847
848
849 computeGlobalCohesiveTractionVector(T2D, jump2D, crackNormal, NMatrix, * gp, tStep);
850
851 // Add to internal force
852 FloatArray NTimesT;
853
854 NTimesT.beTProductOf(NMatrix, T2D);
855 CrossSection *cs = element->giveCrossSection();
856 double thickness = cs->give(CS_Thickness, gp);
857 double dA = thickness * gp->giveWeight();
858 answer.add(dA, NTimesT);
859 }
860 }
861 }
862 } else {
863 // Non-standard cz formulation.
864 //printf("Using non-standard cz formulation.\n");
865
866 if ( hasCohesiveZone() ) {
867 FloatArray solVec;
868 element->computeVectorOf(VM_Total, tStep, solVec);
869
870 StructuralFE2Material *fe2Mat = dynamic_cast<StructuralFE2Material*>(mpCZMat);
871 if ( !fe2Mat ) {
872 OOFEM_ERROR("Failed to cast StructuralFE2Material*.")
873 }
874
875 size_t numSeg = mpCZIntegrationRules.size();
876 for ( size_t segIndex = 0; segIndex < numSeg; segIndex++ ) {
877 for ( int gpInd = 0; gpInd < mpCZIntegrationRules[ segIndex ]->giveNumberOfIntegrationPoints(); gpInd++ ) {
878
879 GaussPoint *gp = mpCZIntegrationRules[ segIndex ]->getIntegrationPoint(gpInd);
880
881 GaussPoint *bulk_gp = nullptr;
882 if ( mIncludeBulkCorr ) {
883 bulk_gp = mpCZExtraIntegrationRules[ segIndex ]->getIntegrationPoint(gpInd);
884 }
885
886 StructuralMaterial *bulkMat = dynamic_cast<StructuralMaterial*>( element->giveCrossSection()->giveMaterial(bulk_gp) );
887 if ( !bulkMat ) {
888 OOFEM_ERROR("Failed to fetch bulk material.")
889 }
890
892
893 if ( fe2ms == nullptr ) {
894 OOFEM_ERROR("The material status is not of an allowed type.")
895 }
896
898 // Compute jump
899
900 // Compute a (slightly modified) N-matrix
901 FloatMatrix NMatrix;
902 computeNCohesive(NMatrix, * gp, mCZEnrItemIndices [ segIndex ], mCZTouchingEnrItemIndices [ segIndex ]);
903
904 FloatArray jump2D;
905 computeDisplacementJump(* gp, jump2D, solVec, NMatrix);
906
908 // Fetch normal
909 FloatArray crackNormal( fe2ms->giveNormal() );
910
911
913 // Fetch L_s
914 double l_s = computeEffectiveSveSize( fe2ms );
915
916
918 // Construct strain (only consider the smeared jump for now)
919 FloatArray smearedJumpStrain = Vec6(jump2D(0)*crackNormal(0)/l_s, jump2D(1)*crackNormal(1)/l_s, 0.0, 0.0, 0.0, (1.0/l_s)*( jump2D(0)*crackNormal(1) + jump2D(1)*crackNormal(0) ));
920
921 FloatArray smearedBulkStrain(6);
922 smearedBulkStrain.zero();
923 FloatMatrix BAvg;
924
925 if ( mIncludeBulkJump ) {
927 // Bulk contribution to SVE strain
928
929 // Crack gp coordinates
930 const FloatArray &xC = gp->giveGlobalCoordinates();
931
932 // For now, we will just perturb the coordinates of the GP to compute B^- and B^+ numerically.
933 double eps = 1.0e-6;
934 FloatArray xPert = xC;
935
936 xPert.add(eps, crackNormal);
937 FloatArray locCoordPert;
938 element->computeLocalCoordinates(locCoordPert, xPert);
939
940 FloatMatrix BPlus;
941 this->ComputeBOrBHMatrix(BPlus, *gp, *element, false, locCoordPert);
942
943 xPert = xC;
944 xPert.add(-eps, crackNormal);
945 element->computeLocalCoordinates(locCoordPert, xPert);
946
947 FloatMatrix BMinus;
948 this->ComputeBOrBHMatrix(BMinus, *gp, *element, false, locCoordPert);
949
950 BAvg = BPlus;
951 BAvg.add(1.0, BMinus);
952 BAvg.times(0.5);
953
954 smearedBulkStrain.beProductOf(BAvg, solVec);
955
956 if ( smearedBulkStrain.giveSize() == 4 ) {
957 smearedBulkStrain = Vec6(smearedBulkStrain(0), smearedBulkStrain(1), smearedBulkStrain(2), 0.0, 0.0, smearedBulkStrain(3));
958 }
959
960 FloatArray smearedJumpStrainTemp = smearedJumpStrain;
961
962 smearedJumpStrain.add(smearedBulkStrain);
963 }
964
965
967 // Compute homogenized stress
968 StructuralElement *se = dynamic_cast<StructuralElement*>(this->element);
969 if ( !se ) {
970 OOFEM_ERROR("Failed to cast StructuralElement.")
971 }
972
973 auto stressVec = fe2Mat->giveRealStressVector_3d(smearedJumpStrain, gp, tStep);
974 //printf("stressVec: "); stressVec.printYourself();
975
976 FloatArray trac = Vec2(stressVec[0]*crackNormal[0]+stressVec[5]*crackNormal[1], stressVec[5]*crackNormal[0]+stressVec[1]*crackNormal[1]);
977
979 // Standard part
980
981 // Add to internal force
982 FloatArray NTimesT;
983
984 NTimesT.beTProductOf(NMatrix, trac);
985 CrossSection *cs = element->giveCrossSection();
986 double thickness = cs->give(CS_Thickness, gp);
987 double dA = thickness * gp->giveWeight();
988 answer.add(dA, NTimesT);
989
990 if ( mIncludeBulkCorr ) {
991 auto stressVecBulk = bulkMat->giveRealStressVector_3d(smearedBulkStrain, bulk_gp, tStep);
992
994 // Non-standard jump part
995 FloatArray stressV4 = Vec4(stressVec[0]-stressVecBulk[0], stressVec[1]-stressVecBulk[1], stressVec[2]-stressVecBulk[2], stressVec[5]-stressVecBulk[5]);
996 FloatArray BTimesT;
997 BTimesT.beTProductOf(BAvg, stressV4);
998 answer.add(1.0*dA*l_s, BTimesT);
999 }
1000 }
1001 }
1002 }
1003 }
1004}
1005
1006void XfemStructuralElementInterface :: computeGlobalCohesiveTractionVector(FloatArray &oT, const FloatArray &iJump, const FloatArray &iCrackNormal, const FloatMatrix &iNMatrix, GaussPoint &iGP, TimeStep *tStep)
1007{
1008 auto F = eye<3>(); // TODO: Compute properly
1009
1010 FloatArrayF<3> jump3D = {iJump.at(1), iJump.at(2), 0.0};
1011
1012 FloatArrayF<3> crackNormal3D = {iCrackNormal.at(1), iCrackNormal.at(2), 0.0};
1013
1014 FloatArrayF<3> ez = {0.0, 0.0, 1.0};
1015 auto crackTangent3D = cross(crackNormal3D, ez);
1016
1017 FloatMatrixF<3,3> locToGlob;
1018 locToGlob.setColumn(crackTangent3D, 0);
1019 locToGlob.setColumn(crackNormal3D, 1);
1020 locToGlob.setColumn(ez, 2);
1021
1022 FloatArrayF<3> jump3DLoc = Tdot(locToGlob, jump3D);
1023
1024 FloatArrayF<3> jump3DLocRenumbered = {jump3DLoc.at(3), jump3DLoc.at(1), jump3DLoc.at(2)};
1025
1027 if ( intMat == nullptr ) {
1028 OOFEM_ERROR("Failed to cast StructuralInterfaceMaterial*.")
1029 }
1030 auto TLocRenumbered = intMat->giveFirstPKTraction_3d(jump3DLocRenumbered, F, & iGP, tStep);
1031
1032 FloatArrayF<3> TLoc = {TLocRenumbered.at(2), TLocRenumbered.at(3), TLocRenumbered.at(1)};
1033
1034 auto T = dot(locToGlob, TLoc);
1035
1036 oT = Vec2(T.at(1), T.at(2));
1037}
1038
1039void XfemStructuralElementInterface :: computeCohesiveTangent(FloatMatrix &answer, TimeStep *tStep)
1040{
1041 if ( !useNonStdCz() ) {
1042
1043 if ( hasCohesiveZone() ) {
1044 FloatArray solVec;
1045 element->computeVectorOf(VM_Total, tStep, solVec);
1046
1047 size_t numSeg = mpCZIntegrationRules.size();
1048
1050 if ( !intMat ) {
1051 OOFEM_ERROR("Failed to cast StructuralInterfaceMaterial*.")
1052 }
1053
1054 for ( size_t segIndex = 0; segIndex < numSeg; segIndex++ ) {
1055 for ( auto &gp: *mpCZIntegrationRules [ segIndex ] ) {
1057 // Compute a (slightly modified) N-matrix
1058
1059 FloatMatrix NMatrix;
1060 computeNCohesive(NMatrix, * gp, mCZEnrItemIndices [ segIndex ], mCZTouchingEnrItemIndices [ segIndex ]);
1061
1063 // Compute jump vector
1064 FloatArray jump2D;
1065 computeDisplacementJump(* gp, jump2D, solVec, NMatrix);
1066
1067 FloatArray jump3D = Vec3(
1068 0.0, jump2D.at(1), jump2D.at(2)
1069 );
1070
1071 // Compute traction
1072 FloatMatrix F;
1073 F.resize(3, 3);
1074 F.beUnitMatrix(); // TODO: Compute properly
1075
1076 FloatMatrix K3DGlob;
1077
1078 FloatMatrix K2D;
1079 K2D.resize(2, 2);
1080 K2D.zero();
1081
1082 if ( intMat->hasAnalyticalTangentStiffness() ) {
1084 // Analytical tangent
1085
1086 auto K3DRenumbered = intMat->give3dStiffnessMatrix_dTdj(TangentStiffness, gp, tStep);
1087
1088 FloatMatrix K3D(3,3);
1089 K3D.at(1, 1) = K3DRenumbered.at(2, 2);
1090 K3D.at(1, 2) = K3DRenumbered.at(2, 3);
1091 K3D.at(1, 3) = K3DRenumbered.at(2, 1);
1092
1093 K3D.at(2, 1) = K3DRenumbered.at(3, 2);
1094 K3D.at(2, 2) = K3DRenumbered.at(3, 3);
1095 K3D.at(2, 3) = K3DRenumbered.at(3, 1);
1096
1097 K3D.at(3, 1) = K3DRenumbered.at(1, 2);
1098 K3D.at(3, 2) = K3DRenumbered.at(1, 3);
1099 K3D.at(3, 3) = K3DRenumbered.at(1, 1);
1100
1101
1102 // Fetch material status and get normal
1103 StructuralInterfaceMaterialStatus *ms = dynamic_cast< StructuralInterfaceMaterialStatus * >( mpCZMat->giveStatus(gp) );
1104 if ( ms == nullptr ) {
1105 OOFEM_ERROR("Failed to fetch material status.");
1106 }
1107
1108 FloatArray crackNormal( ms->giveNormal() );
1109
1110 FloatArray crackNormal3D = Vec3(
1111 crackNormal.at(1), crackNormal.at(2), 0.0
1112 );
1113
1114 FloatArray ez = Vec3(
1115 0.0, 0.0, 1.0
1116 );
1117 FloatArray crackTangent3D;
1118 crackTangent3D.beVectorProductOf(crackNormal3D, ez);
1119
1120 FloatMatrix locToGlob(3, 3);
1121 locToGlob.setColumn(crackTangent3D, 1);
1122 locToGlob.setColumn(crackNormal3D, 2);
1123 locToGlob.setColumn(ez, 3);
1124
1125
1126 FloatMatrix tmp3(3, 3);
1127 tmp3.beProductTOf(K3D, locToGlob);
1128 K3DGlob.beProductOf(locToGlob, tmp3);
1129
1130 K2D.at(1, 1) = K3DGlob.at(1, 1);
1131 K2D.at(1, 2) = K3DGlob.at(1, 2);
1132 K2D.at(2, 1) = K3DGlob.at(2, 1);
1133 K2D.at(2, 2) = K3DGlob.at(2, 2);
1134 } else {
1136 // Numerical tangent
1137 double eps = 1.0e-9;
1138
1139 FloatArray T, TPert;
1140
1141 // Fetch material status and get normal
1142 StructuralInterfaceMaterialStatus *ms = dynamic_cast< StructuralInterfaceMaterialStatus * >( mpCZMat->giveStatus(gp) );
1143 if ( ms == nullptr ) {
1144 OOFEM_ERROR("Failed to fetch material status.");
1145 }
1146
1147 FloatArray crackNormal( ms->giveNormal() );
1148
1149 computeGlobalCohesiveTractionVector(T, jump2D, crackNormal, NMatrix, * gp, tStep);
1150
1151
1152 FloatArray jump2DPert;
1153
1154
1155 jump2DPert = jump2D;
1156 jump2DPert.at(1) += eps;
1157 computeGlobalCohesiveTractionVector(TPert, jump2DPert, crackNormal, NMatrix, * gp, tStep);
1158
1159 K2D.at(1, 1) = ( TPert.at(1) - T.at(1) ) / eps;
1160 K2D.at(2, 1) = ( TPert.at(2) - T.at(2) ) / eps;
1161
1162 jump2DPert = jump2D;
1163 jump2DPert.at(2) += eps;
1164 computeGlobalCohesiveTractionVector(TPert, jump2DPert, crackNormal, NMatrix, * gp, tStep);
1165
1166 K2D.at(1, 2) = ( TPert.at(1) - T.at(1) ) / eps;
1167 K2D.at(2, 2) = ( TPert.at(2) - T.at(2) ) / eps;
1168
1169 computeGlobalCohesiveTractionVector(T, jump2D, crackNormal, NMatrix, * gp, tStep);
1170 }
1171
1172 FloatMatrix tmp, tmp2;
1173 tmp.beProductOf(K2D, NMatrix);
1174 tmp2.beTProductOf(NMatrix, tmp);
1175
1176 CrossSection *cs = element->giveCrossSection();
1177 double thickness = cs->give(CS_Thickness, gp);
1178 double dA = thickness * gp->giveWeight();
1179 answer.add(dA, tmp2);
1180 }
1181 }
1182 }
1183 } else {
1184 // Non-standard cz formulation.
1185
1186
1187 FloatArray solVec;
1188 element->computeVectorOf(VM_Total, tStep, solVec);
1189
1190 size_t numSeg = mpCZIntegrationRules.size();
1191
1192 StructuralFE2Material *fe2Mat = dynamic_cast<StructuralFE2Material*>(mpCZMat);
1193 if ( !fe2Mat ) {
1194 OOFEM_ERROR("Failed to cast StructuralFE2Material*.")
1195 }
1196
1197 for ( size_t segIndex = 0; segIndex < numSeg; segIndex++ ) {
1198 //for ( auto &gp: *mpCZIntegrationRules [ segIndex ] ) {
1199 for ( int gpInd = 0; gpInd < mpCZIntegrationRules[ segIndex ]->giveNumberOfIntegrationPoints(); gpInd++ ) {
1200
1201 GaussPoint *gp = mpCZIntegrationRules[ segIndex ]->getIntegrationPoint(gpInd);
1202
1203 GaussPoint *bulk_gp = nullptr;
1204 StructuralMaterial *bulkMat = nullptr;
1205 if ( mIncludeBulkCorr ) {
1206 bulk_gp = mpCZExtraIntegrationRules[ segIndex ]->getIntegrationPoint(gpInd);
1207 bulkMat = dynamic_cast<StructuralMaterial*>( element->giveCrossSection()->giveMaterial(bulk_gp) );
1208
1209 if ( !bulkMat ) {
1210 OOFEM_ERROR("Failed to fetch bulk material.")
1211 }
1212
1213 }
1214
1215
1217
1218 if ( fe2ms == nullptr ) {
1219 OOFEM_ERROR("The material status is not of an allowed type.")
1220 }
1221
1223 // Compute a (slightly modified) N-matrix
1224
1225 FloatMatrix NMatrix;
1226 computeNCohesive(NMatrix, * gp, mCZEnrItemIndices [ segIndex ], mCZTouchingEnrItemIndices [ segIndex ]);
1227
1228
1230 // Fetch normal
1231 FloatArray n( fe2ms->giveNormal() );
1232
1233 // Traction part of tangent
1234 auto C = fe2Mat->give3dMaterialStiffnessMatrix(TangentStiffness, gp, tStep);
1235
1237 // Fetch L_s
1238 double l_s = computeEffectiveSveSize( fe2ms );
1239
1240 FloatMatrix Ka(2,2);
1241 double a1 = 1.0;
1242 double a2 = 1.0;
1243 double a3 = 1.0;
1244 Ka(0,0) = (0.5/l_s)*( C(0,0)*n(0)*n(0) + a2*C(0,5)*n(0)*n(1) + a1*C(5,0)*n(1)*n(0) + a3*C(5,5)*n(1)*n(1) ) +
1245 (0.5/l_s)*( C(0,0)*n(0)*n(0) + a2*C(0,5)*n(0)*n(1) + a1*C(5,0)*n(1)*n(0) + a3*C(5,5)*n(1)*n(1) );
1246
1247 Ka(0,1) = (0.5/l_s)*( a2*C(0,5)*n(0)*n(0) + C(0,1)*n(0)*n(1) + a3*C(5,5)*n(1)*n(0) + a1*C(5,1)*n(1)*n(1) ) +
1248 (0.5/l_s)*( a2*C(0,5)*n(0)*n(0) + C(0,1)*n(0)*n(1) + a3*C(5,5)*n(1)*n(0) + a1*C(5,1)*n(1)*n(1) );
1249
1250
1251 Ka(1,0) = (0.5/l_s)*( a1*C(5,0)*n(0)*n(0) + a3*C(5,5)*n(0)*n(1) + C(1,0)*n(1)*n(0) + a2*C(1,5)*n(1)*n(1) ) +
1252 (0.5/l_s)*( a1*C(5,0)*n(0)*n(0) + a3*C(5,5)*n(0)*n(1) + C(1,0)*n(1)*n(0) + a2*C(1,5)*n(1)*n(1) );
1253
1254
1255 Ka(1,1) = (0.5/l_s)*( a3*C(5,5)*n(0)*n(0) + a1*C(5,1)*n(0)*n(1) + a2*C(1,5)*n(1)*n(0) + C(1,1)*n(1)*n(1) ) +
1256 (0.5/l_s)*( a3*C(5,5)*n(0)*n(0) + a1*C(5,1)*n(0)*n(1) + a2*C(1,5)*n(1)*n(0) + C(1,1)*n(1)*n(1) );
1257
1258
1259 FloatMatrix tmp, tmp2;
1260 tmp.beProductOf(Ka, NMatrix);
1261 tmp2.beTProductOf(NMatrix, tmp);
1262
1263 CrossSection *cs = element->giveCrossSection();
1264 double thickness = cs->give(CS_Thickness, gp);
1265 double dA = thickness * gp->giveWeight();
1266 answer.add(dA, tmp2);
1267
1268
1269
1270 FloatMatrix BAvg;
1271
1272 if ( mIncludeBulkJump ) {
1274 // Bulk contribution to SVE strain
1275
1276 // Crack gp coordinates
1277 const FloatArray &xC = gp->giveGlobalCoordinates();
1278
1279 // For now, we will just perturb the coordinates of the GP to compute B^- and B^+ numerically.
1280 double eps = 1.0e-6;
1281 FloatArray xPert = xC;
1282
1283 xPert.add(eps, n);
1284 FloatArray locCoordPert;
1285 element->computeLocalCoordinates(locCoordPert, xPert);
1286
1287 FloatMatrix BPlus;
1288 this->ComputeBOrBHMatrix(BPlus, *gp, *element, false, locCoordPert);
1289
1290 xPert = xC;
1291 xPert.add(-eps, n);
1292 element->computeLocalCoordinates(locCoordPert, xPert);
1293
1294 FloatMatrix BMinus;
1295 this->ComputeBOrBHMatrix(BMinus, *gp, *element, false, locCoordPert);
1296
1297 BAvg = BPlus;
1298 BAvg.add(1.0, BMinus);
1299 BAvg.times(0.5);
1300
1301
1302 FloatMatrix Kb(2,4); // Implicitly assumes plane strain. Fix later.
1303
1304 Kb(0,0) = C(0,0)*n(0) + C(5,0)*n(1);
1305 Kb(0,1) = C(0,1)*n(0) + C(5,1)*n(1);
1306 Kb(0,3) = C(0,5)*n(0) + C(5,5)*n(1);
1307
1308 Kb(1,0) = C(5,0)*n(0) + C(1,0)*n(1);
1309 Kb(1,1) = C(5,1)*n(0) + C(1,1)*n(1);
1310 Kb(1,3) = C(5,5)*n(0) + C(1,5)*n(1);
1311
1312 tmp.beProductOf(Kb, BAvg);
1313 tmp2.beTProductOf(NMatrix, tmp);
1314 answer.add(dA, tmp2);
1315 }
1316
1318 // Non-standard bulk contribution
1319
1320 if ( mIncludeBulkCorr ) {
1321
1322 auto CBulk = bulkMat->give3dMaterialStiffnessMatrix(TangentStiffness, bulk_gp, tStep);
1323
1324 tmp.beTranspositionOf(tmp2);
1325 answer.add(1.0*dA, tmp);
1326
1327
1328 FloatMatrix C4(4,4);
1329 C4(0,0) = C(0,0);
1330 C4(0,1) = C(0,1);
1331 C4(0,2) = C(0,2);
1332 C4(0,3) = C(0,5);
1333
1334 C4(1,0) = C(1,0);
1335 C4(1,1) = C(1,1);
1336 C4(1,2) = C(1,2);
1337 C4(1,3) = C(1,5);
1338
1339 C4(2,0) = C(2,0);
1340 C4(2,1) = C(2,1);
1341 C4(2,2) = C(2,2);
1342 C4(2,3) = C(2,5);
1343
1344 C4(3,0) = C(5,0);
1345 C4(3,1) = C(5,1);
1346 C4(3,2) = C(5,2);
1347 C4(3,3) = C(5,5);
1348
1349 tmp.beProductOf(C4, BAvg);
1350 tmp2.beTProductOf(BAvg, tmp);
1351 answer.add(1.0*dA*l_s, tmp2);
1352
1353 FloatMatrix C4Bulk(4,4);
1354 C4Bulk(0,0) = CBulk(0,0);
1355 C4Bulk(0,1) = CBulk(0,1);
1356 C4Bulk(0,2) = CBulk(0,2);
1357 C4Bulk(0,3) = CBulk(0,5);
1358
1359 C4Bulk(1,0) = CBulk(1,0);
1360 C4Bulk(1,1) = CBulk(1,1);
1361 C4Bulk(1,2) = CBulk(1,2);
1362 C4Bulk(1,3) = CBulk(1,5);
1363
1364 C4Bulk(2,0) = CBulk(2,0);
1365 C4Bulk(2,1) = CBulk(2,1);
1366 C4Bulk(2,2) = CBulk(2,2);
1367 C4Bulk(2,3) = CBulk(2,5);
1368
1369 C4Bulk(3,0) = CBulk(5,0);
1370 C4Bulk(3,1) = CBulk(5,1);
1371 C4Bulk(3,2) = CBulk(5,2);
1372 C4Bulk(3,3) = CBulk(5,5);
1373
1374 tmp.beProductOf(C4Bulk, BAvg);
1375 tmp2.beTProductOf(BAvg, tmp);
1376 answer.add(-1.0*dA*l_s, tmp2);
1377 }
1378
1379 }
1380 }
1381
1382 }
1383}
1384
1385void XfemStructuralElementInterface :: computeCohesiveTangentAt(FloatMatrix &answer, TimeStep *tStep)
1386{
1387 if ( hasCohesiveZone() ) {
1388 printf("Entering XfemElementInterface :: computeCohesiveTangentAt().\n");
1389 }
1390}
1391
1392void XfemStructuralElementInterface :: XfemElementInterface_computeConsistentMassMatrix(FloatMatrix &answer, TimeStep *tStep, double &mass, const double *ipDensity)
1393{
1394 StructuralElement *structEl = dynamic_cast< StructuralElement * >( element );
1395 if ( structEl == nullptr ) {
1396 OOFEM_ERROR("Not a structural element");
1397 }
1398
1399 int ndofs = structEl->computeNumberOfDofs();
1400 double density, dV;
1401 FloatMatrix n;
1402 IntArray mask;
1403
1404 answer.resize(ndofs, ndofs);
1405 answer.zero();
1406 if ( !structEl->isActivated(tStep) ) {
1407 return;
1408 }
1409
1410 structEl->giveMassMtrxIntegrationgMask(mask);
1411
1412 mass = 0.;
1413
1414 for ( auto &gp: *element->giveIntegrationRule(0) ) {
1415 structEl->computeNmatrixAt(gp->giveNaturalCoordinates(), n);
1416 density = structEl->giveStructuralCrossSection()->give('d', gp);
1417
1418 if ( ipDensity != nullptr ) {
1419 // Override density if desired
1420 density = * ipDensity;
1421 }
1422
1423 dV = structEl->computeVolumeAround(gp);
1424 mass += density * dV;
1425
1426 if ( mask.isEmpty() ) {
1427 answer.plusProductSymmUpper(n, n, density * dV);
1428 } else {
1429 for ( int i = 1; i <= ndofs; i++ ) {
1430 for ( int j = i; j <= ndofs; j++ ) {
1431 double summ = 0.;
1432 for ( int k = 1; k <= n.giveNumberOfRows(); k++ ) {
1433 if ( mask.at(k) == 0 ) {
1434 continue;
1435 }
1436
1437 summ += n.at(k, i) * n.at(k, j);
1438 }
1439
1440 answer.at(i, j) += summ * density * dV;
1441 }
1442 }
1443 }
1444 }
1445
1446 answer.symmetrized();
1447
1448 const double tol = 1.0e-9;
1449 const double regularizationCoeff = 1.0e-6;
1450 int numRows = answer.giveNumberOfRows();
1451 for ( int i = 0; i < numRows; i++ ) {
1452 if ( fabs( answer(i, i) ) < tol ) {
1453 answer(i, i) += regularizationCoeff;
1454 // printf("Found zero on diagonal.\n");
1455 }
1456 }
1457}
1458
1459void
1460XfemStructuralElementInterface :: initializeCZFrom(InputRecord &ir, int priority)
1461{
1462 ParameterManager &pm = this->element->giveDomain()->elementPPM;
1466}
1467
1468void XfemStructuralElementInterface :: giveCZInputRecord(DynamicInputRecord &input)
1469{
1470 if ( mCZMaterialNum > 0 ) {
1472 }
1473
1474 if ( mUsePlaneStrain ) {
1476 }
1477
1479}
1480
1481void XfemStructuralElementInterface :: initializeCZMaterial()
1482{
1483 if ( mCZMaterialNum > 0 ) {
1484
1485 mpCZMat = this->element->giveDomain()->giveMaterial(mCZMaterialNum);
1486
1487 if ( mpCZMat == nullptr ) {
1488 OOFEM_ERROR("Failed to fetch pointer for mpCZMat.");
1489 }
1490 }
1491}
1492
1493bool XfemStructuralElementInterface :: useNonStdCz()
1494{
1495 if ( element->giveDomain()->hasXfemManager() ) {
1496 XfemManager *xMan = this->element->giveDomain()->giveXfemManager();
1497 XfemStructureManager *xsMan = dynamic_cast<XfemStructureManager*>( xMan );
1498
1499 if ( xsMan ) {
1500 if ( xsMan->giveUseNonStdCz() ) {
1501 return true;
1502 } else {
1503 return false;
1504 }
1505 } else {
1506 return false;
1507 }
1508 } else {
1509 return false;
1510 }
1511}
1512
1513void XfemStructuralElementInterface :: XfemElementInterface_computeDeformationGradientVector(FloatArray &answer, GaussPoint *gp, TimeStep *tStep)
1514{
1515 // Computes the deformation gradient in the Voigt format at the Gauss point gp of
1516 // the receiver at time step tStep.
1517 // Order of components: 11, 22, 33, 23, 13, 12, 32, 31, 21 in the 3D.
1518
1519 NLStructuralElement *nlStructEl = static_cast<NLStructuralElement*>( element );
1520
1521 // Obtain the current displacement vector of the element and subtract initial displacements (if present)
1522 FloatArray u;
1523 nlStructEl->computeVectorOf(VM_Total, tStep, u); // solution vector
1524 if ( nlStructEl->initialDisplacements ) {
1525 u.subtract(* nlStructEl->initialDisplacements);
1526 }
1527
1528 // Displacement gradient H = du/dX
1529 FloatMatrix B;
1530 nlStructEl->computeBHmatrixAt(gp, B);
1531 answer.beProductOf(B, u);
1532
1533 // Deformation gradient F = H + I
1534 MaterialMode matMode = gp->giveMaterialMode();
1535 if ( matMode == _3dMat || matMode == _PlaneStrain ) {
1536 answer.at(1) += 1.0;
1537 answer.at(2) += 1.0;
1538 answer.at(3) += 1.0;
1539 } else if ( matMode == _PlaneStress ) {
1540 answer.at(1) += 1.0;
1541 answer.at(2) += 1.0;
1542 } else if ( matMode == _1dMat ) {
1543 answer.at(1) += 1.0;
1544 } else {
1545 OOFEM_ERROR("MaterialMode is not supported yet (%s)", __MaterialModeToString(matMode) );
1546 }
1547}
1548
1549void XfemStructuralElementInterface :: giveIntersectionsTouchingCrack(std :: vector< int > &oTouchingEnrItemIndices, const std :: vector< int > &iCandidateIndices, int iEnrItemIndex, XfemManager &iXMan)
1550{
1551 EnrichmentItem *ei = iXMan.giveEnrichmentItem(iEnrItemIndex);
1552
1553
1554 for ( int candidateIndex : iCandidateIndices ) {
1555 if ( candidateIndex != iEnrItemIndex ) {
1556 // Fetch candidate enrichment item
1557 EnrichmentItem *eiCandidate = iXMan.giveEnrichmentItem(candidateIndex);
1558
1559 // This treatment is only necessary if the enrichment front
1560 // is an EnrFrontIntersection. Therefore, start by trying a
1561 // dynamic cast.
1562
1563 // Check start tip
1564 EnrFrontIntersection *efStart = dynamic_cast< EnrFrontIntersection * >( eiCandidate->giveEnrichmentFrontStart() );
1565 if ( efStart != nullptr ) {
1566 const TipInfo &tipInfo = efStart->giveTipInfo();
1567
1568 if ( ei->tipIsTouchingEI(tipInfo) ) {
1569 //printf("Crack %d is touched by a tip on crack %d.\n", iEnrItemIndex, candidateIndex);
1570 oTouchingEnrItemIndices.push_back(candidateIndex);
1571 }
1572 }
1573
1574 // Check end tip
1575 EnrFrontIntersection *efEnd = dynamic_cast< EnrFrontIntersection * >( eiCandidate->giveEnrichmentFrontEnd() );
1576 if ( efEnd != nullptr ) {
1577 const TipInfo &tipInfo = efEnd->giveTipInfo();
1578
1579 if ( ei->tipIsTouchingEI(tipInfo) ) {
1580 //printf("Crack %d is touched by a tip on crack %d.\n", iEnrItemIndex, candidateIndex);
1581 oTouchingEnrItemIndices.push_back(candidateIndex);
1582 }
1583 }
1584 }
1585 }
1586}
1587
1588void XfemStructuralElementInterface :: giveSubtriangulationCompositeExportData(std :: vector< ExportRegion > &vtkPieces, IntArray &primaryVarsToExport, IntArray &internalVarsToExport, IntArray cellVarsToExport, TimeStep *tStep)
1589{
1590 const int numCells = mSubTri.size();
1591 vtkPieces [ 0 ].setNumberOfCells(numCells);
1592
1593 int numTotalNodes = numCells * 3;
1594 vtkPieces [ 0 ].setNumberOfNodes(numTotalNodes);
1595
1596 // Node coordinates
1597 std :: vector< FloatArray >nodeCoords;
1598 int nodesPassed = 1;
1599 for ( auto &tri: mSubTri ) {
1600 for ( int i = 1; i <= 3; i++ ) {
1601 FloatArray x = tri.giveVertex(i);
1602 nodeCoords.push_back(x);
1603 vtkPieces [ 0 ].setNodeCoords(nodesPassed, x);
1604 nodesPassed++;
1605 }
1606 }
1607
1608 // Connectivity, offset and cell type
1609 nodesPassed = 1;
1610 int offset = 3;
1611 for ( size_t i = 1; i <= mSubTri.size(); i++ ) {
1612 IntArray nodes = {
1613 nodesPassed, nodesPassed + 1, nodesPassed + 2
1614 };
1615 nodesPassed += 3;
1616 vtkPieces [ 0 ].setConnectivity(i, nodes);
1617
1618 vtkPieces [ 0 ].setOffset(i, offset);
1619 offset += 3;
1620
1621 vtkPieces [ 0 ].setCellType(i, 5); // Linear triangle
1622 }
1623
1624
1625
1626 // Export nodal variables from primary fields
1627 vtkPieces [ 0 ].setNumberOfPrimaryVarsToExport(primaryVarsToExport, numTotalNodes);
1628
1629 for ( int fieldNum = 1; fieldNum <= primaryVarsToExport.giveSize(); fieldNum++ ) {
1630 UnknownType type = ( UnknownType ) primaryVarsToExport.at(fieldNum);
1631
1632
1633 nodesPassed = 1;
1634
1635 for ( auto &tri: mSubTri ) {
1636 FloatArray triCenter = tri.giveVertex(1);
1637 triCenter.add( tri.giveVertex(2) );
1638 triCenter.add( tri.giveVertex(3) );
1639 triCenter.times(1.0 / 3.0);
1640
1641 double meanEdgeLength = 0.0;
1642 meanEdgeLength += ( 1.0 / 3.0 ) * distance(tri.giveVertex(1), tri.giveVertex(2) );
1643 meanEdgeLength += ( 1.0 / 3.0 ) * distance(tri.giveVertex(2), tri.giveVertex(3) );
1644 meanEdgeLength += ( 1.0 / 3.0 ) * distance(tri.giveVertex(3), tri.giveVertex(1) );
1645
1646 const double relPertLength = XfemTolerances :: giveRelLengthTolTight();
1647
1648 for ( int i = 1; i <= 3; i++ ) {
1649 if ( type == DisplacementVector ) { // compute displacement
1650 FloatArray u = Vec3(
1651 0.0, 0.0, 0.0
1652 );
1653
1654
1655 // Fetch global coordinates (in undeformed configuration)
1656 const FloatArray &x = tri.giveVertex(i);
1657
1658 FloatArray locCoordNode;
1659 element->computeLocalCoordinates(locCoordNode, x);
1660
1661
1662 FloatArray pertVec;
1663 FloatArray locCoord;
1664 double pertLength = relPertLength;
1665
1666 int numTries = 1;
1667 for ( int j = 0; j < numTries; j++ ) {
1668 // Perturb towards triangle center, to ensure that
1669 // we end up on the correct side of the crack
1670 pertVec.beDifferenceOf(triCenter, x);
1671 pertVec.times(pertLength);
1672 FloatArray xPert = x;
1673 xPert.add(pertVec);
1674
1675
1676 // Compute local coordinates
1677 element->computeLocalCoordinates(locCoord, xPert);
1678 }
1679
1680 // Compute displacement in point
1681 FloatMatrix NMatrix;
1682 FloatArray solVec;
1683
1684 // Use only regular basis functions for edge nodes to get linear interpolation
1685 // (to make the visualization look nice)
1686 FloatArray N;
1687 FEInterpolation *interp = element->giveInterpolation();
1688 interp->evalN( N, locCoordNode, FEIElementGeometryWrapper(element) );
1689// interp->evalN( N, locCoord, FEIElementGeometryWrapper(element) );
1690 const int nDofMan = element->giveNumberOfDofManagers();
1691
1692 XfemManager *xMan = element->giveDomain()->giveXfemManager();
1693 int numEI = xMan->giveNumberOfEnrichmentItems();
1694
1695 bool joinNodes = false;
1696
1697 for ( int eiIndex = 1; eiIndex <= numEI; eiIndex++ ) {
1698 EnrichmentItem *ei = xMan->giveEnrichmentItem(eiIndex);
1699
1700 double levelSetTang = 0.0, levelSetNormal = 0.0, levelSetInNode = 0.0;
1701
1702 bool evaluationSucceeded = true;
1703 for ( int elNodeInd = 1; elNodeInd <= nDofMan; elNodeInd++ ) {
1704 DofManager *dMan = element->giveDofManager(elNodeInd);
1705 const auto &nodeCoord = dMan->giveCoordinates();
1706
1707 if ( !ei->evalLevelSetTangInNode(levelSetInNode, dMan->giveGlobalNumber(), nodeCoord) ) {
1708 evaluationSucceeded = false;
1709 }
1710 levelSetTang += N.at(elNodeInd) * levelSetInNode;
1711
1712 if ( !ei->evalLevelSetNormalInNode(levelSetInNode, dMan->giveGlobalNumber(), nodeCoord) ) {
1713 evaluationSucceeded = false;
1714 }
1715 levelSetNormal += N.at(elNodeInd) * levelSetInNode;
1716 }
1717
1718 double tangSignDist = levelSetTang, arcPos = 0.0;
1719
1720 GeometryBasedEI *geoEI = dynamic_cast< GeometryBasedEI * >( ei );
1721 if ( geoEI != nullptr ) {
1722 // TODO: Consider removing this special treatment. /ES
1723 geoEI->giveGeometry()->computeTangentialSignDist(tangSignDist, x, arcPos);
1724 }
1725
1726
1727 if ( !evaluationSucceeded ) {
1728// printf("!evaluationSucceeded.\n");
1729 }
1730
1731// if ( ( tangSignDist > ( 1.0e-3 ) * meanEdgeLength && fabs(levelSetNormal) < ( 1.0e-2 ) * meanEdgeLength ) && evaluationSucceeded ) {
1732// joinNodes = false;
1733// }
1734
1735// if ( ( tangSignDist < ( 1.0e-3 ) * meanEdgeLength || fabs(levelSetNormal) > ( 1.0e-2 ) * meanEdgeLength ) || !evaluationSucceeded ) {
1736 if ( ( tangSignDist < ( 1.0e-3 ) * meanEdgeLength || fabs(levelSetNormal) > ( 1.0e-2 ) * meanEdgeLength ) && false ) {
1737 joinNodes = false;
1738 }
1739 }
1740
1741 if ( joinNodes ) {
1742 // if point on edge
1743 XfemElementInterface_createEnrNmatrixAt(NMatrix, locCoord, * element, true);
1744 element->computeVectorOf(VM_Total, tStep, solVec);
1745 } else {
1746 XfemElementInterface_createEnrNmatrixAt(NMatrix, locCoord, * element, false);
1747 element->computeVectorOf(VM_Total, tStep, solVec);
1748 }
1749
1750
1751 FloatArray uTemp;
1752 uTemp.beProductOf(NMatrix, solVec);
1753
1754 if ( uTemp.giveSize() == 3 ) {
1755 u = uTemp;
1756 } else {
1757 u = Vec3(
1758 uTemp [ 0 ], uTemp [ 1 ], 0.0
1759 );
1760 }
1761
1762
1763 FloatArray valuearray = u;
1764 vtkPieces [ 0 ].setPrimaryVarInNode(type, nodesPassed, valuearray);
1765 } else {
1766 // TODO: Implement
1767 printf("fieldNum: %d\n", fieldNum);
1768 }
1769
1770 nodesPassed++;
1771 }
1772 }
1773 }
1774
1775
1776 // Export nodal variables from internal fields
1777 vtkPieces [ 0 ].setNumberOfInternalVarsToExport(internalVarsToExport, numTotalNodes);
1778
1779
1780 vtkPieces [ 0 ].setNumberOfCellVarsToExport(cellVarsToExport, numCells);
1781 for ( int i = 1; i <= cellVarsToExport.giveSize(); i++ ) {
1782 InternalStateType type = ( InternalStateType ) cellVarsToExport.at(i);
1783
1784 for ( size_t triInd = 1; triInd <= mSubTri.size(); triInd++ ) {
1785
1786 FloatArray average;
1787 IntegrationRule *iRule = element->giveIntegrationRule(0);
1788 computeIPAverageInTriangle(average, iRule, element, type, tStep, mSubTri[triInd-1]);
1789
1790 if ( average.giveSize() == 0 ) {
1791 VTKXMLExportModule :: computeIPAverage(average, iRule, element, type, tStep);
1792 }
1793
1794
1795 FloatArray averageVoigt;
1796
1797 if ( average.giveSize() == 6 ) {
1798
1799 averageVoigt.resize(9);
1800
1801 averageVoigt.at(1) = average.at(1);
1802 averageVoigt.at(5) = average.at(2);
1803 averageVoigt.at(9) = average.at(3);
1804 averageVoigt.at(6) = averageVoigt.at(8) = average.at(4);
1805 averageVoigt.at(3) = averageVoigt.at(7) = average.at(5);
1806 averageVoigt.at(2) = averageVoigt.at(4) = average.at(6);
1807 } else {
1808 if ( average.giveSize() == 1 ) {
1809 averageVoigt.resize(1);
1810 averageVoigt.at(1) = average.at(1);
1811 }
1812 }
1813
1814 vtkPieces [ 0 ].setCellVar(type, triInd, averageVoigt);
1815 }
1816 }
1817
1818
1819
1820 // Export of XFEM related quantities
1821 if ( element->giveDomain()->hasXfemManager() ) {
1822 XfemManager *xMan = element->giveDomain()->giveXfemManager();
1823
1824 int nEnrIt = xMan->giveNumberOfEnrichmentItems();
1825 vtkPieces [ 0 ].setNumberOfInternalXFEMVarsToExport(xMan->vtkExportFields.giveSize(), nEnrIt, numTotalNodes);
1826
1827 const int nDofMan = element->giveNumberOfDofManagers();
1828
1829
1830 for ( int field = 1; field <= xMan->vtkExportFields.giveSize(); field++ ) {
1831 XFEMStateType xfemstype = ( XFEMStateType ) xMan->vtkExportFields [ field - 1 ];
1832
1833 for ( int enrItIndex = 1; enrItIndex <= nEnrIt; enrItIndex++ ) {
1834 EnrichmentItem *ei = xMan->giveEnrichmentItem(enrItIndex);
1835 for ( int nodeInd = 1; nodeInd <= numTotalNodes; nodeInd++ ) {
1836 const FloatArray &x = nodeCoords [ nodeInd - 1 ];
1837 FloatArray locCoord;
1838 element->computeLocalCoordinates(locCoord, x);
1839
1840 FloatArray N;
1841 FEInterpolation *interp = element->giveInterpolation();
1842 interp->evalN( N, locCoord, FEIElementGeometryWrapper(element) );
1843
1844
1845 if ( xfemstype == XFEMST_LevelSetPhi ) {
1846 double levelSet = 0.0, levelSetInNode = 0.0;
1847
1848 for ( int elNodeInd = 1; elNodeInd <= nDofMan; elNodeInd++ ) {
1849 DofManager *dMan = element->giveDofManager(elNodeInd);
1850 const auto &nodeCoord = dMan->giveCoordinates();
1851 ei->evalLevelSetNormalInNode(levelSetInNode, dMan->giveGlobalNumber(), nodeCoord);
1852
1853 levelSet += N.at(elNodeInd) * levelSetInNode;
1854 }
1855
1856
1857 FloatArray valueArray = Vec1(
1858 levelSet
1859 );
1860 vtkPieces [ 0 ].setInternalXFEMVarInNode(field, enrItIndex, nodeInd, valueArray);
1861 } else if ( xfemstype == XFEMST_LevelSetGamma ) {
1862 double levelSet = 0.0, levelSetInNode = 0.0;
1863
1864 for ( int elNodeInd = 1; elNodeInd <= nDofMan; elNodeInd++ ) {
1865 DofManager *dMan = element->giveDofManager(elNodeInd);
1866 const auto &nodeCoord = dMan->giveCoordinates();
1867 ei->evalLevelSetTangInNode(levelSetInNode, dMan->giveGlobalNumber(), nodeCoord);
1868
1869 levelSet += N.at(elNodeInd) * levelSetInNode;
1870 }
1871
1872
1873 FloatArray valueArray = Vec1(
1874 levelSet
1875 );
1876 vtkPieces [ 0 ].setInternalXFEMVarInNode(field, enrItIndex, nodeInd, valueArray);
1877 } else if ( xfemstype == XFEMST_NodeEnrMarker ) {
1878 double nodeEnrMarker = 0.0, nodeEnrMarkerInNode = 0.0;
1879
1880 for ( int elNodeInd = 1; elNodeInd <= nDofMan; elNodeInd++ ) {
1881 DofManager *dMan = element->giveDofManager(elNodeInd);
1882 ei->evalNodeEnrMarkerInNode( nodeEnrMarkerInNode, dMan->giveGlobalNumber() );
1883
1884 nodeEnrMarker += N.at(elNodeInd) * nodeEnrMarkerInNode;
1885 }
1886
1887
1888
1889 FloatArray valueArray = Vec1(
1890 nodeEnrMarker
1891 );
1892 vtkPieces [ 0 ].setInternalXFEMVarInNode(field, enrItIndex, nodeInd, valueArray);
1893 }
1894 }
1895 }
1896 }
1897 }
1898}
1899
1900void XfemStructuralElementInterface :: computeIPAverageInTriangle(FloatArray &answer, IntegrationRule *iRule, Element *elem, InternalStateType isType, TimeStep *tStep, const Triangle &iTri)
1901{
1902 // Computes the volume average (over an element) for the quantity defined by isType
1903 double gptot = 0.0;
1904 answer.clear();
1905 FloatArray temp;
1906 if ( iRule ) {
1907 for ( IntegrationPoint *ip: *iRule ) {
1908
1909 FloatArray globCoord = ip->giveGlobalCoordinates();
1910// globCoord.resizeWithValues(2);
1911
1912 if ( iTri.pointIsInTriangle(globCoord) ) {
1913 elem->giveIPValue(temp, ip, isType, tStep);
1914 gptot += ip->giveWeight();
1915 answer.add(ip->giveWeight(), temp);
1916 }
1917 }
1918
1919 answer.times(1. / gptot);
1920 }
1921
1922}
1923
1924} /* namespace oofem */
#define N(a, b)
virtual void computeTangentialSignDist(double &oDist, const FloatArray &iPoint, double &oMinDistArcPos) const =0
void AppendCohesiveZoneGaussPoint(GaussPoint *ipGP)
Definition crack.C:59
virtual double give(CrossSectionProperty a, GaussPoint *gp) const
int giveGlobalNumber() const
Definition dofmanager.h:515
const FloatArray & giveCoordinates() const
Definition dofmanager.h:390
int giveElementPlaceInArray(int iGlobalElNum) const
Definition domain.C:188
EngngModel * giveEngngModel()
Definition domain.C:419
void setField(int item, InputFieldType id)
virtual bool isActivated(TimeStep *tStep)
Definition element.C:838
virtual int computeNumberOfDofs()
Definition element.h:436
void computeVectorOf(ValueModeType u, TimeStep *tStep, FloatArray &answer)
Definition element.C:103
virtual int giveIPValue(FloatArray &answer, GaussPoint *gp, InternalStateType type, TimeStep *tStep)
Definition element.C:1298
virtual double computeVolumeAround(GaussPoint *gp)
Definition element.h:530
virtual TimeStep * giveCurrentStep(bool force=false)
Definition engngm.h:717
const TipInfo & giveTipInfo() const
bool evalNodeEnrMarkerInNode(double &oNodeEnrMarker, int iNodeInd) const
EnrichmentFront * giveEnrichmentFrontStart()
bool evalLevelSetTangInNode(double &oLevelSet, int iNodeInd, const FloatArray &iGlobalCoord) const
bool tipIsTouchingEI(const TipInfo &iTipInfo)
EnrichmentFront * giveEnrichmentFrontEnd()
bool evalLevelSetNormalInNode(double &oLevelSet, int iNodeInd, const FloatArray &iGlobalCoord) const
virtual bool isMaterialModified(GaussPoint &iGP, Element &iEl, CrossSection *&opCS) const
virtual void evalN(FloatArray &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const =0
double & at(std::size_t i)
void resize(Index s)
Definition floatarray.C:94
double & at(Index i)
Definition floatarray.h:202
double computeSquaredNorm() const
Definition floatarray.C:867
Index giveSize() const
Returns the size of receiver.
Definition floatarray.h:261
void beDifferenceOf(const FloatArray &a, const FloatArray &b)
Definition floatarray.C:403
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
void beProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:689
void beVectorProductOf(const FloatArray &v1, const FloatArray &v2)
Definition floatarray.C:476
void beTProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:721
void add(const FloatArray &src)
Definition floatarray.C:218
void subtract(const FloatArray &src)
Definition floatarray.C:320
void times(double s)
Definition floatarray.C:834
void setColumn(const FloatArrayF< N > &src, std::size_t c)
void times(double f)
void plusProductSymmUpper(const FloatMatrix &a, const FloatMatrix &b, double dV)
void add(const FloatMatrix &a)
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
void beProductTOf(const FloatMatrix &a, const FloatMatrix &b)
void beProductOf(const FloatMatrix &a, const FloatMatrix &b)
void setColumn(const FloatArray &src, int c)
void beTranspositionOf(const FloatMatrix &src)
void zero()
Zeroes all coefficient of receiver.
int giveNumberOfRows() const
Returns number of rows of receiver.
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
MaterialMode giveMaterialMode()
Returns corresponding material mode of receiver.
Definition gausspoint.h:190
IntegrationPointStatus * giveMaterialStatus(IntegrationPointStatusIDType key=IPSID_Default)
Definition gausspoint.h:204
double giveWeight()
Returns integration weight of receiver.
Definition gausspoint.h:180
void giveSubPolygon(std ::vector< FloatArray > &oPoints, const double &iXiStart, const double &iXiEnd) const
BasicGeometry * giveGeometry()
bool isEmpty() const
Definition intarray.h:217
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
virtual void copyStateVariables(const MaterialStatus &iStatus)=0
virtual void computeBHmatrixAt(GaussPoint *gp, FloatMatrix &answer)
void setPeriodicityNormal(const FloatArray &iPeriodicityNormal)
virtual void createMaterialStatus(GaussPoint &iGP)=0
virtual FloatMatrixF< 4, 4 > giveStiffnessMatrix_PlaneStrain(MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) const =0
virtual FloatMatrixF< 3, 3 > giveStiffnessMatrix_PlaneStress(MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) const =0
StructuralCrossSection * giveStructuralCrossSection()
Helper function which returns the structural cross-section for the element.
virtual void giveMassMtrxIntegrationgMask(IntArray &answer)
virtual void computeNmatrixAt(const FloatArray &iLocCoord, FloatMatrix &answer)
std::unique_ptr< FloatArray > initialDisplacements
Initial displacement vector, describes the initial nodal displacements when element has been casted.
PrescribedGradientHomogenization * giveBC()
const FloatArray & giveNormal() const
FloatArrayF< 6 > giveRealStressVector_3d(const FloatArrayF< 6 > &strain, GaussPoint *gp, TimeStep *tStep) const override
Default implementation relies on giveRealStressVector for second Piola-Kirchoff stress.
FloatMatrixF< 6, 6 > give3dMaterialStiffnessMatrix(MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) const override
void letNormalBe(const FloatArrayF< 3 > &iN)
Assigns normal vector.
const FloatArrayF< 3 > & giveNormal() const
Returns const reference to normal vector.
virtual FloatArrayF< 3 > giveFirstPKTraction_3d(const FloatArrayF< 3 > &jump, const FloatMatrixF< 3, 3 > &F, GaussPoint *gp, TimeStep *tStep) const
virtual bool hasAnalyticalTangentStiffness() const =0
virtual FloatMatrixF< 3, 3 > give3dStiffnessMatrix_dTdj(MatResponseMode rMode, GaussPoint *gp, TimeStep *tStep) const
virtual FloatMatrixF< 6, 6 > give3dMaterialStiffnessMatrix(MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) const
virtual FloatArrayF< 6 > giveRealStressVector_3d(const FloatArrayF< 6 > &strain, GaussPoint *gp, TimeStep *tStep) const
Default implementation relies on giveRealStressVector for second Piola-Kirchoff stress.
double giveTargetTime()
Returns target time.
Definition timestep.h:164
static void refineTriangle(std::vector< Triangle > &oRefinedTri, const Triangle &iTri)
Definition geometry.C:628
bool pointIsInTriangle(const FloatArray &iP) const
Definition geometry.C:485
std ::vector< std ::unique_ptr< IntegrationRule > > mIntRule_tmp
void computeDisplacementJump(GaussPoint &iGP, FloatArray &oJump, const FloatArray &iSolVec, const FloatMatrix &iNMatrix)
static ParamKey IPK_XfemElementInterface_CohesiveZoneMaterial
std ::vector< std ::unique_ptr< IntegrationRule > > mpCZExtraIntegrationRules
virtual void XfemElementInterface_partitionElement(std ::vector< Triangle > &oTriangles, const std ::vector< FloatArray > &iPoints)
Partitions the element into patches by a triangulation.
std ::vector< std ::unique_ptr< IntegrationRule > > mpCZExtraIntegrationRules_tmp
void ComputeBOrBHMatrix(FloatMatrix &oAnswer, GaussPoint &iGP, Element &iEl, bool iComputeBH, const FloatArray &iNaturalGpCoord)
std ::vector< std ::vector< int > > mCZTouchingEnrItemIndices
XfemElementInterface(Element *e)
Constructor.
virtual void XfemElementInterface_prepareNodesForDelaunay(std ::vector< std ::vector< FloatArray > > &oPointPartitions, double &oCrackStartXi, double &oCrackEndXi, int iEnrItemIndex, bool &oIntersection)
Returns an array of array of points. Each array of points defines the points of a subregion of the el...
static ParamKey IPK_XfemElementInterface_NumIntPointsCZ
std ::vector< std ::unique_ptr< IntegrationRule > > mpCZIntegrationRules
void computeNCohesive(FloatMatrix &oN, GaussPoint &iGP, int iEnrItemIndex, const std ::vector< int > &iTouchingEnrItemIndices)
void XfemElementInterface_createEnrNmatrixAt(FloatMatrix &oAnswer, const FloatArray &iLocCoord, Element &iEl, bool iSetDiscontContribToZero)
Creates enriched N-matrix.
std ::vector< int > mCZEnrItemIndices
Index of enrichment items associated with cohesive zones.
bool mUsePlaneStrain
Flag that tells if plane stress or plane strain is assumed.
std ::vector< std ::unique_ptr< IntegrationRule > > mpCZIntegrationRules_tmp
static ParamKey IPK_XfemElementInterface_PlaneStrain
bool isElementEnriched(const Element *elem)
bool giveVtkDebug() const
void giveElementEnrichmentItemIndices(std ::vector< int > &oElemEnrInd, int iElementIndex) const
int giveNumGpPerTri() const
IntArray vtkExportFields
Domain * giveDomain()
const std ::vector< int > & giveMaterialModifyingEnrItemIndices() const
int giveNumTriRefs() const
Number of Gauss points per sub-triangle in cut elements.
EnrichmentItem * giveEnrichmentItem(int n)
int giveNumberOfEnrichmentItems() const
void computeIPAverageInTriangle(FloatArray &answer, IntegrationRule *iRule, Element *elem, InternalStateType isType, TimeStep *tStep, const Triangle &iTri)
Help functions for VTK export.
void giveIntersectionsTouchingCrack(std ::vector< int > &oTouchingEnrItemIndices, const std ::vector< int > &iCandidateIndices, int iEnrItemIndex, XfemManager &iXMan)
virtual void computeGlobalCohesiveTractionVector(FloatArray &oT, const FloatArray &iJump, const FloatArray &iCrackNormal, const FloatMatrix &iNMatrix, GaussPoint &iGP, TimeStep *tStep)
double computeEffectiveSveSize(StructuralFE2MaterialStatus *iFe2Ms)
MaterialStatus * giveClosestGP_MatStat(double &oClosestDist, std ::vector< std ::unique_ptr< IntegrationRule > > &iRules, const FloatArray &iCoord)
#define OOFEM_ERROR(...)
Definition error.h:79
#define M_PI
Definition mathfem.h:52
static FloatArray Vec2(const double &a, const double &b)
Definition floatarray.h:606
@ CS_Thickness
Thickness.
FloatMatrixF< N, P > Tdot(const FloatMatrixF< M, N > &a, const FloatMatrixF< M, P > &b)
Computes .
GaussPoint IntegrationPoint
Definition gausspoint.h:272
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
XFEMStateType
Definition xfemmanager.h:92
FloatArrayF< 3 > cross(const FloatArrayF< 3 > &x, const FloatArrayF< 3 > &y)
Computes $ x \cross y $.
double dot(const FloatArray &x, const FloatArray &y)
static FloatArray Vec4(const double &a, const double &b, const double &c, const double &d)
Definition floatarray.h:608
double distance(const FloatArray &x, const FloatArray &y)
double distance_square(const FloatArray &x, const FloatArray &y)
static FloatArray Vec1(const double &a)
Definition floatarray.h:605
FloatMatrixF< N, N > eye()
Constructs an identity matrix.
static FloatArray Vec3(const double &a, const double &b, const double &c)
Definition floatarray.h:607
#define PM_UPDATE_PARAMETER(_val, _pm, _ir, _componentnum, _paramkey, _prio)
#define _IFT_XfemElementInterface_NumIntPointsCZ
#define _IFT_XfemElementInterface_PlaneStrain
#define _IFT_XfemElementInterface_CohesiveZoneMaterial

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