1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "solidCohesiveFvPatchVectorField.H"
27 #include "addToRunTimeSelectionTable.H"
28 #include "volFields.H"
29 #include "constitutiveModel.H"
30 #include "regionSplit.H"
31 #include "crackerFvMesh.H"
32 #include "tractionBoundaryGradient.H"
34 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
39 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
41 solidCohesiveFvPatchVectorField::solidCohesiveFvPatchVectorField
44 const DimensionedField<vector, volMesh>& iF
47 directionMixedFvPatchVectorField(p, iF),
48 fieldName_("undefined"),
49 relaxationFactor_(1.0),
50 traction_(p.size(), vector::zero),
51 //minUnloadingSeparationDistance_(0.0),
54 curTractionN_(0, 0.0),
55 oldTractionN_(0, 0.0),
56 curTractionS_(0, 0.0),
57 oldTractionS_(0, 0.0),
62 unloadingDeltaEff_(0, 0.0),
68 penaltyFactorPtr_(NULL),
71 explicitSeparationDistance_(false),
74 updateGlobalPatchMaterials_(true),
75 globalPatchMaterials_(0, 0.0),
76 nonLinear_(nonLinearGeometry::OFF),
81 solidCohesiveFvPatchVectorField::solidCohesiveFvPatchVectorField
84 const DimensionedField<vector, volMesh>& iF,
85 const dictionary& dict
88 directionMixedFvPatchVectorField(p, iF),
89 fieldName_(dimensionedInternalField().name()),
90 relaxationFactor_(readScalar(dict.lookup("relaxationFactor"))),
91 traction_(p.size(), vector::zero),
92 contact_(dict.lookup("contact")),
93 cracked_(p.size(),false),
94 curTractionN_(p.size(), 0.0),
95 oldTractionN_(p.size(), 0.0),
96 curTractionS_(p.size(), 0.0),
97 oldTractionS_(p.size(), 0.0),
98 deltaN_(p.size(), 0.0),
99 oldDeltaN_(p.size(), 0.0),
100 deltaS_(p.size(), 0.0),
101 oldDeltaS_(p.size(), 0.0),
102 unloadingDeltaEff_(p.size(), 0.0),
103 currentGI_(p.size(), 0.0),
104 oldGI_(p.size(), 0.0),
105 currentGII_(p.size(), 0.0),
106 oldGII_(p.size(), 0.0),
108 penaltyFactorPtr_(NULL),
109 penaltyScale_(readScalar(dict.lookup("penaltyScale"))),
110 frictionCoeff_(readScalar(dict.lookup("frictionCoeff"))),
111 explicitSeparationDistance_(dict.lookup("explicitSeparationDistance")),
112 curDeltaN_(p.size(), 0.0),
113 curDeltaS_(p.size(), 0.0),
114 updateGlobalPatchMaterials_(true),
115 globalPatchMaterials_(0, 0.0),
116 nonLinear_(nonLinearGeometry::OFF),
119 Info<< "Creating solidCohesive patch" << nl
120 << "\tOnly Dugdale law currently available!" << endl;
122 // Check if traction boundary is for non linear solver
123 if (dict.found("nonLinear"))
125 nonLinear_ = nonLinearGeometry::nonLinearNames_.read
127 dict.lookup("nonLinear")
130 if (nonLinear_ == nonLinearGeometry::UPDATED_LAGRANGIAN)
132 Info << "\tnonLinear set to updated Lagrangian"
135 else if (nonLinear_ == nonLinearGeometry::TOTAL_LAGRANGIAN)
137 Info << "\tnonLinear set to total Lagrangian"
142 if (dict.found("orthotropic"))
144 orthotropic_ = Switch(dict.lookup("orthotropic"));
145 Info << "\t\torthotropic set to " << orthotropic_ << endl;
148 // if (minUnloadingSeparationDistance_ < 0.001)
150 // minUnloadingSeparationDistance_ = 0.001;
153 // if (minUnloadingSeparationDistance_ > 1.0)
155 // minUnloadingSeparationDistance_ = 1.0;
158 // Info << "minUnloadingSeparationDistance: "
159 // << minUnloadingSeparationDistance_ << endl;
161 if (dict.found("refValue"))
163 this->refValue() = vectorField("refValue", dict, p.size());
167 this->refValue() = vector::zero;
170 if (dict.found("refGradient"))
172 this->refGrad() = vectorField("refGradient", dict, p.size());
176 this->refGrad() = vector::zero;
179 if (dict.found("valueFraction"))
181 this->valueFraction() =
182 symmTensorField("valueFraction", dict, p.size());
186 this->valueFraction() = symmTensor::zero;
189 if (dict.found("value"))
191 vectorField::operator=(vectorField("value", dict, p.size()));
195 vectorField normalValue = transform(valueFraction(), refValue());
197 vectorField gradValue =
198 this->patchInternalField() + refGrad()/this->patch().deltaCoeffs();
200 vectorField transformGradValue =
201 transform(I - valueFraction(), gradValue);
203 vectorField::operator=(normalValue + transformGradValue);
206 if (dict.found("traction"))
209 vectorField("traction", dict, p.size());
212 // if (dict.found("unloadingSeparationDistance"))
214 // unloadingSeparationDistance_ =
215 // vectorField("unloadingSeparationDistance", dict, p.size());
218 if (dict.found("cracked"))
220 // cracked_ = Field<bool>("cracked", dict, p.size());
221 cracked_ = Field<scalar>("cracked", dict, p.size());
224 if (dict.found("curTractionN"))
226 curTractionN_ = scalarField("curTractionN", dict, p.size());
228 if (dict.found("curTractionS"))
230 curTractionS_ = scalarField("curTractionS", dict, p.size());
232 if (dict.found("oldTractionN"))
234 oldTractionN_ = scalarField("oldTractionN", dict, p.size());
236 if (dict.found("oldTractionS"))
238 oldTractionS_ = scalarField("oldTractionS", dict, p.size());
241 if (dict.found("deltaN"))
243 deltaN_ = scalarField("deltaN", dict, p.size());
245 if (dict.found("deltaS"))
247 deltaS_ = scalarField("deltaS", dict, p.size());
249 if (dict.found("oldDeltaN"))
251 oldDeltaN_ = scalarField("oldDeltaN", dict, p.size());
253 if (dict.found("oldDeltaS"))
255 oldDeltaS_ = scalarField("oldDeltaS", dict, p.size());
257 if (dict.found("curDeltaN"))
259 curDeltaN_ = scalarField("curDeltaN", dict, p.size());
261 if (dict.found("curDeltaS"))
263 curDeltaS_ = scalarField("curDeltaS", dict, p.size());
265 if (dict.found("unloadingDeltaEff"))
267 unloadingDeltaEff_ = scalarField("unloadingDeltaEff", dict, p.size());
270 if (dict.found("currentGI"))
272 currentGI_ = scalarField("currentGI", dict, p.size());
274 if (dict.found("currentGII"))
276 currentGII_ = scalarField("currentGII", dict, p.size());
278 if (dict.found("oldGI"))
280 oldGI_ = scalarField("oldGI", dict, p.size());
282 if (dict.found("oldGII"))
284 oldGII_ = scalarField("oldGII", dict, p.size());
289 solidCohesiveFvPatchVectorField::solidCohesiveFvPatchVectorField
291 const solidCohesiveFvPatchVectorField& cpf
294 directionMixedFvPatchVectorField(cpf),
295 fieldName_(cpf.fieldName_),
296 relaxationFactor_(cpf.relaxationFactor_),
297 traction_(cpf.traction_),
298 //minUnloadingSeparationDistance_(cpf.minUnloadingSeparationDistance_),
299 contact_(cpf.contact_),
300 cracked_(cpf.cracked_),
301 curTractionN_(cpf.curTractionN_),
302 oldTractionN_(cpf.oldTractionN_),
303 curTractionS_(cpf.curTractionS_),
304 oldTractionS_(cpf.oldTractionS_),
305 deltaN_(cpf.deltaN_),
306 oldDeltaN_(cpf.oldDeltaN_),
307 deltaS_(cpf.deltaS_),
308 oldDeltaS_(cpf.oldDeltaS_),
309 unloadingDeltaEff_(cpf.unloadingDeltaEff_),
310 currentGI_(cpf.currentGI_),
312 currentGII_(cpf.currentGII_),
313 oldGII_(cpf.oldGII_),
315 penaltyFactorPtr_(cpf.penaltyFactorPtr_),
316 penaltyScale_(cpf.penaltyScale_),
317 frictionCoeff_(cpf.frictionCoeff_),
318 explicitSeparationDistance_(cpf.explicitSeparationDistance_),
319 curDeltaN_(cpf.curDeltaN_),
320 curDeltaS_(cpf.curDeltaS_),
321 updateGlobalPatchMaterials_(cpf.updateGlobalPatchMaterials_),
322 globalPatchMaterials_(cpf.globalPatchMaterials_),
323 nonLinear_(cpf.nonLinear_),
324 orthotropic_(cpf.orthotropic_)
328 solidCohesiveFvPatchVectorField::solidCohesiveFvPatchVectorField
330 const solidCohesiveFvPatchVectorField& cpf,
332 const DimensionedField<vector, volMesh>& iF,
333 const fvPatchFieldMapper& mapper
336 directionMixedFvPatchVectorField(cpf, p, iF, mapper),
337 fieldName_(cpf.fieldName_),
338 relaxationFactor_(cpf.relaxationFactor_),
339 traction_(cpf.traction_, mapper),
340 //minUnloadingSeparationDistance_(cpf.minUnloadingSeparationDistance_),
341 contact_(cpf.contact_),
342 cracked_(cpf.cracked_),
343 curTractionN_(cpf.curTractionN_),
344 oldTractionN_(cpf.oldTractionN_),
345 curTractionS_(cpf.curTractionS_),
346 oldTractionS_(cpf.oldTractionS_),
347 deltaN_(cpf.deltaN_),
348 oldDeltaN_(cpf.oldDeltaN_),
349 deltaS_(cpf.deltaS_),
350 oldDeltaS_(cpf.oldDeltaS_),
351 unloadingDeltaEff_(cpf.unloadingDeltaEff_),
352 currentGI_(cpf.currentGI_),
354 currentGII_(cpf.currentGII_),
355 oldGII_(cpf.oldGII_),
357 penaltyFactorPtr_(cpf.penaltyFactorPtr_),
358 penaltyScale_(cpf.penaltyScale_),
359 frictionCoeff_(cpf.frictionCoeff_),
360 explicitSeparationDistance_(cpf.explicitSeparationDistance_),
361 curDeltaN_(cpf.curDeltaN_),
362 curDeltaS_(cpf.curDeltaS_),
363 updateGlobalPatchMaterials_(cpf.updateGlobalPatchMaterials_),
364 globalPatchMaterials_(cpf.globalPatchMaterials_),
365 nonLinear_(cpf.nonLinear_),
366 orthotropic_(cpf.orthotropic_)
370 solidCohesiveFvPatchVectorField::solidCohesiveFvPatchVectorField
372 const solidCohesiveFvPatchVectorField& cpf,
373 const DimensionedField<vector, volMesh>& iF
376 directionMixedFvPatchVectorField(cpf, iF),
377 fieldName_(cpf.fieldName_),
378 relaxationFactor_(cpf.relaxationFactor_),
379 traction_(cpf.traction_),
380 //minUnloadingSeparationDistance_(cpf.minUnloadingSeparationDistance_),
381 contact_(cpf.contact_),
382 cracked_(cpf.cracked_),
383 curTractionN_(cpf.curTractionN_),
384 oldTractionN_(cpf.oldTractionN_),
385 curTractionS_(cpf.curTractionS_),
386 oldTractionS_(cpf.oldTractionS_),
387 deltaN_(cpf.deltaN_),
388 oldDeltaN_(cpf.oldDeltaN_),
389 deltaS_(cpf.deltaS_),
390 oldDeltaS_(cpf.oldDeltaS_),
391 unloadingDeltaEff_(cpf.unloadingDeltaEff_),
392 currentGI_(cpf.currentGI_),
394 currentGII_(cpf.currentGII_),
395 oldGII_(cpf.oldGII_),
397 penaltyFactorPtr_(cpf.penaltyFactorPtr_),
398 penaltyScale_(cpf.penaltyScale_),
399 frictionCoeff_(cpf.frictionCoeff_),
400 explicitSeparationDistance_(cpf.explicitSeparationDistance_),
401 curDeltaN_(cpf.curDeltaN_),
402 curDeltaS_(cpf.curDeltaS_),
403 updateGlobalPatchMaterials_(cpf.updateGlobalPatchMaterials_),
404 globalPatchMaterials_(cpf.globalPatchMaterials_),
405 nonLinear_(cpf.nonLinear_),
406 orthotropic_(cpf.orthotropic_)
410 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
412 tmp<scalarField> solidCohesiveFvPatchVectorField::crackingAndDamage() const
414 tmp<scalarField> tcrackingAndDamage
416 new scalarField(size(), 1.0)
418 scalarField& cad = tcrackingAndDamage();
428 return tcrackingAndDamage;
432 tmp<scalarField> solidCohesiveFvPatchVectorField::GI() const
436 new scalarField(size(), 0.0)
438 scalarField& GI = tGI();
442 GI[facei] = currentGI_[facei];
449 tmp<scalarField> solidCohesiveFvPatchVectorField::GII() const
451 tmp<scalarField> tGII
453 new scalarField(size(), 0.0)
455 scalarField& GII = tGII();
459 GII[facei] = currentGII_[facei];
466 bool solidCohesiveFvPatchVectorField::cracking()
468 const fvMesh& mesh = patch().boundaryMesh().mesh();
469 const crackerFvMesh& crackerMesh = refCast<const crackerFvMesh>(mesh);
472 Field<scalar> globalCracked =
473 crackerMesh.globalCrackField(cracked_);
475 label sumDamaged = 0;
476 label sumCracked = 0;
478 forAll(globalCracked, facei)
480 if (globalCracked[facei] > 0.0)
489 Info<< "\t\tThere are " << sumDamaged << " damaged faces" << nl
490 << "\t\tThere are " << sumCracked << " cracked faces" << endl;
496 void solidCohesiveFvPatchVectorField::autoMap
498 const fvPatchFieldMapper& m
501 directionMixedFvPatchVectorField::autoMap(m);
503 traction_.autoMap(m);
505 curTractionN_.autoMap(m);
506 oldTractionN_.autoMap(m);
507 curTractionS_.autoMap(m);
508 oldTractionS_.autoMap(m);
510 oldDeltaN_.autoMap(m);
512 oldDeltaS_.autoMap(m);
513 unloadingDeltaEff_.autoMap(m);
514 currentGI_.autoMap(m);
516 currentGII_.autoMap(m);
518 curDeltaN_.autoMap(m);
519 curDeltaS_.autoMap(m);
520 globalPatchMaterials_.autoMap(m);
522 // force this field to be reset next time updateCoeffs is called
523 updateGlobalPatchMaterials_ = true;
525 // Must use primitive mesh data because fvMesh data is packed in fields
526 // and cannot be accessed during mapping. HJ, 12/Dec/2008
527 vectorField n = patch().patch().faceNormals();
529 const labelList& addressing = m.directAddressing();
531 label nNewFaces = m.size() - m.sizeBeforeMapping();
534 // when a new face is created in the crack, we need to set
535 // its traction, but how do we do it:
536 // we calculate the traciton in the solver (updatedCrack.H)
537 // but we cannot access that field here during mapping
538 // So in the solver we will have to cast this patch and update
539 // the traction_ field after mapping and call updateCoeffs.
540 // For here, we will just set traction to zero.
542 if ( (patch().size() == 1) && (nNewFaces == 1) )
545 this->valueFraction()[i] = symmTensor::zero;
547 traction_[i] = vector::zero;
549 curTractionN_[i] = 0.0;
550 oldTractionN_[i] = 0.0;
551 curTractionS_[i] = 0.0;
552 oldTractionS_[i] = 0.0;
559 unloadingDeltaEff_[i] = 0.0;
562 currentGII_[i] = 0.0;
565 else if ( (patch().size() == 2) && (nNewFaces == 1) )
568 this->valueFraction()[i] = symmTensor::zero;
569 traction_[i] = vector::zero;
572 curTractionN_[i] = 0.0;
573 oldTractionN_[i] = 0.0;
574 curTractionS_[i] = 0.0;
575 oldTractionS_[i] = 0.0;
582 unloadingDeltaEff_[i] = 0.0;
585 currentGII_[i] = 0.0;
588 else if ( (patch().size()==2) && (nNewFaces == 2) )
591 this->valueFraction()[i] = symmTensor::zero;
592 traction_[i] = vector::zero;
594 this->valueFraction()[i] = symmTensor::zero;
595 traction_[i] = vector::zero;
598 curTractionN_[i] = 0.0;
599 oldTractionN_[i] = 0.0;
600 curTractionS_[i] = 0.0;
601 oldTractionS_[i] = 0.0;
608 unloadingDeltaEff_[i] = 0.0;
611 currentGII_[i] = 0.0;
616 for (label i = 1; i < patch().size(); i++)
618 if (addressing[i] == 0)
620 this->valueFraction()[i] = symmTensor::zero;
621 traction_[i] = vector::zero;
624 curTractionN_[i] = 0.0;
625 oldTractionN_[i] = 0.0;
626 curTractionS_[i] = 0.0;
627 oldTractionS_[i] = 0.0;
634 unloadingDeltaEff_[i] = 0.0;
637 currentGII_[i] = 0.0;
645 // Reverse-map the given fvPatchField onto this fvPatchField
646 void solidCohesiveFvPatchVectorField::rmap
648 const fvPatchVectorField& ptf,
649 const labelList& addr
652 directionMixedFvPatchVectorField::rmap(ptf, addr);
654 const solidCohesiveFvPatchVectorField& dmptf =
655 refCast<const solidCohesiveFvPatchVectorField>(ptf);
657 relaxationFactor_ = dmptf.relaxationFactor_;
658 traction_.rmap(dmptf.traction_, addr);
659 contact_ = dmptf.contact_;
660 cracked_ = dmptf.cracked_;
661 curTractionN_ = dmptf.curTractionN_;
662 oldTractionN_ = dmptf.oldTractionN_;
663 curTractionS_ = dmptf.curTractionS_;
664 oldTractionS_ = dmptf.oldTractionS_;
665 deltaN_ = dmptf.deltaN_;
666 oldDeltaN_ = dmptf.oldDeltaN_;
667 deltaS_ = dmptf.deltaS_;
668 oldDeltaS_ = dmptf.oldDeltaS_;
669 curDeltaN_ = dmptf.curDeltaN_;
670 curDeltaS_ = dmptf.curDeltaS_;
671 globalPatchMaterials_ = dmptf.globalPatchMaterials_;
672 unloadingDeltaEff_ = dmptf.unloadingDeltaEff_;
673 currentGI_ = dmptf.currentGI_;
674 currentGII_ = dmptf.currentGII_;
678 // Update the coefficients associated with the patch field
679 void solidCohesiveFvPatchVectorField::updateCoeffs()
686 vectorField n = patch().nf();
688 // lookup cohesive properties from rheology
689 const constitutiveModel& rheology =
690 this->db().objectRegistry::lookupObject<constitutiveModel>
695 label patchID = patch().index();
696 const scalarField sigmaMax =
697 rheology.cohLaw().sigmaMax()().boundaryField()[patchID];
698 const scalarField tauMax =
699 rheology.cohLaw().tauMax()().boundaryField()[patchID];
700 const scalarField GIc =
701 rheology.cohLaw().GIc()().boundaryField()[patchID];
702 const scalarField GIIc =
703 rheology.cohLaw().GIIc()().boundaryField()[patchID];
706 if (curTimeIndex_ != this->db().time().timeIndex())
708 // we force the penalty factor to be calculated here for the first time
709 // as all processors must call this at the same time
710 if (contact_ && patch().size() > 0)
712 // force calculation of penalty factor here
716 oldDeltaN_ = deltaN_;
717 oldDeltaS_ = deltaS_;
718 // curDelta is always latest delta
719 // whereas delta is only latest when explicitDist is false
720 //oldDeltaN_ = curDeltaN_;
721 //oldDeltaS_ = curDeltaS_;
722 oldTractionN_ = curTractionN_;
723 oldTractionS_ = curTractionS_;
725 oldGII_ = currentGII_;
732 sqr(max(deltaN_, scalar(0))) + sqr(deltaS_)
736 curTimeIndex_ = this->db().time().timeIndex();
740 // Get face cells regions
741 const unallocLabelList& faceCells = patch().faceCells();
742 const fvMesh& mesh = patch().boundaryMesh().mesh();
744 if (!isA<crackerFvMesh>(mesh))
748 "void solidCohesiveFvPatchVectorField::updateCoeffs() const"
749 ) << "Mesh should be of type: " << crackerFvMesh::typeName
750 << abort(FatalError);
753 const crackerFvMesh& crackerMesh = refCast<const crackerFvMesh>(mesh);
755 // global patch material field is needed for multimaterial cohesive laws
756 if (updateGlobalPatchMaterials_)
758 updateGlobalPatchMaterials_ = false;
760 if (mesh.objectRegistry::foundObject<volScalarField>("materials"))
762 scalarField localPatchMaterials =
763 patch().lookupPatchField<volScalarField, scalar>
764 ("materials").patchInternalField();
765 scalarField newGlobalPatchMaterials =
766 crackerMesh.globalCrackField(localPatchMaterials);
768 globalPatchMaterials_.setSize(newGlobalPatchMaterials.size());
769 globalPatchMaterials_ = newGlobalPatchMaterials;
773 const regionSplit& regions = crackerMesh.regions();
775 labelField faceCellRegion(size(), -1);
777 forAll(faceCellRegion, faceI)
779 faceCellRegion[faceI] = regions[faceCells[faceI]];
782 labelField globalFaceCellRegion =
783 crackerMesh.globalCrackField(faceCellRegion);
785 // Patch displacement
786 vectorField UPatch = *this;
787 if (fieldName_ == "DU")
789 UPatch += patch().lookupPatchField<volVectorField, vector>("U");
792 // Global displacement
793 vectorField globalUPatch = crackerMesh.globalCrackField(UPatch);
796 // Update separation distance
797 vectorField delta(patch().size(), vector::zero);
798 const labelList& gcfa = crackerMesh.globalCrackFaceAddressing();
799 label globalIndex = crackerMesh.localCrackStart();
800 for (label i = 0; i < patch().size(); i++)
802 // newSeparationDistance[i] =
804 globalUPatch[gcfa[globalIndex]]
805 - globalUPatch[globalIndex];
810 //globalIndex = crackerMesh.localCrackStart();
811 for (label i = 0; i < patch().size(); i++)
814 curDeltaN_[i] = n[i] & delta[i];
815 curDeltaS_[i] = mag( (I - sqr(n[i])) & delta[i]); // shearing
816 if (explicitSeparationDistance_)
818 deltaN_[i] = oldDeltaN_[i];
819 deltaS_[i] = oldDeltaS_[i];
821 if (mag(deltaN_[i]) < SMALL)
823 deltaN_[i] = 2*SMALL;
826 << "explicitSeparationDistance_ is true!" << abort(FatalError);
832 relaxationFactor_*curDeltaN_[i]
833 + (1.0 - relaxationFactor_)*deltaN_[i];
836 relaxationFactor_*curDeltaS_[i]
837 + (1.0 - relaxationFactor_)*deltaS_[i];
841 curTractionN_[i] = n[i] & traction_[i];
842 curTractionS_[i] = mag( (I-sqr(n[i])) & traction_[i] );
844 // effective delta - only positive deltaN is considered
845 const scalar deltaEff =
846 Foam::sqrt(max(deltaN_[i], 0.0)*max(deltaN_[i], 0.0)
847 + deltaS_[i]*deltaS_[i]);
850 // stop calculating after cracking for convergence
851 // because crack might jump in and out of damaged/failed
852 // only update energies if there is loading
853 if ( !cracked_[i] && (deltaEff > (unloadingDeltaEff_[i]-SMALL)) )
855 // if the average normal stress is tensile
856 if ((curTractionN_[i]+oldTractionN_[i]) > 0.0)
861 + ((0.5*(curTractionN_[i]+oldTractionN_[i]))*
862 (deltaN_[i]-oldDeltaN_[i]));
866 // no modeI energy lost if in compression
867 currentGI_[i] = oldGI_[i];
870 // mode II - trapezoidal rule
871 currentGII_[i] = oldGII_[i]
872 + ((0.5*(curTractionS_[i]+oldTractionS_[i]))*
873 (deltaS_[i]-oldDeltaS_[i]));
875 //scalar currentG = currentGI_[i] + currentGII_[i];
879 // ( globalFaceCellRegion[globalIndex]
880 // == globalFaceCellRegion[gcfa[globalIndex]] )
885 // new tractions to be calculated
886 scalar curNormalTraction = 0;
887 vector curTangentialTraction = vector::zero;
890 // if the effective delta is greater than unloadingDeltaEff then
892 // unloadingDeltaEff is the maximum previsouly reached deltaEff
893 if (deltaEff > (unloadingDeltaEff_[i]-SMALL) )
895 // at the moment loading and unloading are the same
896 // if total energy is dissipated, then fully crack face
897 //if ( currentG > GIc[i] || cracked_[i] ) //Gc )
899 if ( ((currentGI_[i]/GIc[i]) + (currentGII_[i]/GIIc[i])) >= 1 )
901 //Pout << "GIc[i] is " << GIc[i] << ", curG is " << currentG << endl;
904 Pout << "Face " << i << " is fully cracked" << endl;
910 // failed faces might come in to contact so we need to deal with them
911 // here we could use the face delta values but that assumes that the
912 // opposing crack faces are aligned direclty opposite one another, which
913 // in general they are not. So we actually need to calculate the actual
914 // face penetration distances and then a standard penalty approach
915 // contact is probably fine. We will use simple assumption for now which
916 // is fine is the relative displacement
917 // of the opposing faces is not too large
918 // To-do: we must calculate actual distances
919 curNormalTraction = 0.0;
920 curTangentialTraction = vector::zero;
921 if ( contact_ && deltaN_[i] <= 0.0 )
923 curNormalTraction = deltaN_[i]*penaltyFactor();
924 //Info << "penaltyFactor() is " << penaltyFactor() << endl;
927 vector sDir = (I - sqr(n[i]))&delta[i];
928 sDir /= mag(sDir+vector(SMALL,SMALL,SMALL));
929 scalar slip = mag(deltaS_[gcfa[i]] - deltaS_[i]);
933 slip*penaltyFactor(),
934 frictionCoeff_*curNormalTraction // stick/slip
936 curTangentialTraction = fricMag*sDir;
941 relaxationFactor_*curNormalTraction
942 + (1-relaxationFactor_)*(n[i] & traction_[i]);
944 curTangentialTraction =
945 relaxationFactor_*curTangentialTraction
946 + (1-relaxationFactor_)*( (I -sqr(n[i])) & traction_[i]);
948 traction_[i] = curNormalTraction*n[i] + curTangentialTraction;
950 // damging face with positive normal delta
951 else if ( deltaN_[i] > 0.0 )
955 Pout << "Face " << i << " is un-cracked" << endl;
960 // set traction in a fixed point iteration manner to force
961 // (tN/sigmaMax)^2 + (tS/tauMax)^2 = 1
962 // while also allowing varying mode mix by assuming colinear traction
966 // sigmaMax[i] * deltaN_[i] /
967 // (SMALL + ::sqrt( (deltaN_[i]*deltaN_[i])
968 // + (deltaS_[i]*deltaS_[i])*(sigmaMax[i]*sigmaMax[i]
969 // /(tauMax[i]*tauMax[i])) ));
971 // tauMax[i] * deltaS_[i] /
972 // (SMALL + ::sqrt( (deltaS_[i]*deltaS_[i])
973 // + (deltaN_[i]*deltaN_[i])*(tauMax[i]*tauMax[i]
974 // /(sigmaMax[i]*sigmaMax[i])) ));
976 // Given current deltaN and deltaS, the cohesive law
977 // (Dugdale, linear, etc)gives back current traction:
978 scalar tN = n[i] & traction_[i];
979 scalar tS = mag( (I - sqr(n[i])) & traction_[i] );
981 rheology.cohLaw().damageTractions
990 globalPatchMaterials_
993 // shear delta direction
994 vector sDir = (I - sqr(n[i]))&delta[i];
995 sDir /= mag(sDir+vector(SMALL,SMALL,SMALL));
1000 + (1-relaxationFactor_)*(n[i] & traction_[i]);
1002 curTangentialTraction =
1003 relaxationFactor_*(tS*sDir)
1004 + (1-relaxationFactor_)*( (I -sqr(n[i])) & traction_[i]);
1006 traction_[i] = curNormalTraction*n[i] + curTangentialTraction;
1008 // damaging faces with negative normal delta
1013 Pout << "Face " << i << " is un-cracked" << endl;
1016 cracked_[i] = false;
1017 //Pout << "Contact and shearing face " << i << endl;
1019 //Pout << "Face " << i << " is damaging but in contact" << endl;
1020 // set shear traction from cohesive law
1021 // set normal traction to contact condition
1022 scalar tS = tauMax[i];
1024 vector sDir = (I - sqr(n[i])) & delta[i];
1025 sDir /= mag(sDir+vector(SMALL,SMALL,SMALL));
1027 // Simple penalty condition
1028 scalar penaltyFac = 0.0;
1031 penaltyFac = penaltyFactor();
1033 scalar contactTN = deltaN_[i]*penaltyFac;
1037 relaxationFactor_*contactTN
1038 + (1-relaxationFactor_)*(n[i] & traction_[i]);
1040 curTangentialTraction =
1041 relaxationFactor_*(tS*sDir)
1042 + (1-relaxationFactor_)*( (I -sqr(n[i])) & traction_[i]);
1044 traction_[i] = curNormalTraction*n[i] + curTangentialTraction;
1050 // as the current effective delta is less than the old time
1053 // We have two choice for unloading:
1054 // (a) ductile approach
1055 // unload with initial stiffness (which is infinite)
1056 // similar to ductilve metal stress-strain curve
1057 // as we use infinite intial stiffness, this means to elastic
1058 // energy is recovered
1059 // and we immediately start loading in opposite direction
1060 // (b) brittle approach
1061 // unload straight back to the origin
1062 // this means we recover elastic energy
1064 // approach (b) is numerically "nicer"; however, for Dugdale cohesive
1065 // zone this implys that only half the energy is dissipated just before
1066 // failure and then the other half is dissipated at failure. This may
1067 // not be an issue in practive but it does not really make sense.
1068 // Obviously it is fine for a linear cohesive zone as the energy
1069 // is smoothly dissipated up to failure. For now, we will implement
1070 // approach (b), but this requires more thinking...
1072 // reduce traction linearly with the reduction in delta
1073 scalar scaleFactor = deltaEff/(unloadingDeltaEff_[i]);
1075 relaxationFactor_*scaleFactor*traction_[i]
1076 + (1 - relaxationFactor_)*traction_[i];
1080 bool incremental(fieldName_ == "DU");
1082 this->refGrad() = tractionBoundaryGradient::snGrad
1085 scalarField(traction_.size(), 0.0),
1094 directionMixedFvPatchVectorField::updateCoeffs();
1098 void solidCohesiveFvPatchVectorField::calcPenaltyFactor()
1100 // calculate penalty factor similar to standardPenalty contact model
1101 // approx penaltyFactor from mechanical properties
1102 // this can then be scaled using the penaltyScale
1103 // to-do: write equivalent for orthotropic
1108 "void solidCohesiveFvPatchVectorField::calcPenaltyFactor()"
1109 ) << "solidCohesiveFvPatchVectorField::calcPenaltyFactor()"
1110 << " has yet to be written for orthotropic"
1111 << exit(FatalError);
1114 const label patchID = patch().index();
1115 const fvMesh& mesh = patch().boundaryMesh().mesh();
1117 const scalarField& mu =
1118 mesh.objectRegistry::lookupObject<volScalarField>
1119 ("mu").boundaryField()[patchID];
1121 const scalarField& lambda =
1122 mesh.objectRegistry::lookupObject<volScalarField>
1123 ("lambda").boundaryField()[patchID];
1125 // avarage contact patch bulk modulus
1126 scalar bulkModulus = gAverage(lambda + (2.0/3.0)*mu);
1128 // average contact patch face area
1129 scalar faceArea = gAverage(mesh.magSf().boundaryField()[patchID]);
1131 // average contact patch cell volume
1132 scalar cellVolume = 0.0;
1134 const volScalarField::DimensionedInternalField & V = mesh.V();
1136 const unallocLabelList& faceCells =
1137 mesh.boundary()[patchID].faceCells();
1139 forAll(mesh.boundary()[patchID], facei)
1141 cellVolume += V[faceCells[facei]];
1144 cellVolume /= patch().size();
1146 // approximate penalty factor based on Hallquist et al.
1147 // we approximate penalty factor for traction instead of force
1149 new scalar(penaltyScale_*bulkModulus*faceArea/cellVolume);
1154 void solidCohesiveFvPatchVectorField::write(Ostream& os) const
1156 directionMixedFvPatchVectorField::write(os);
1157 traction_.writeEntry("traction", os);
1158 os.writeKeyword("relaxationFactor")
1159 << relaxationFactor_ << token::END_STATEMENT << nl;
1161 cracked_.writeEntry("cracked", os);
1162 curTractionN_.writeEntry("curTractionN", os);
1163 curTractionS_.writeEntry("curTractionS", os);
1164 oldTractionN_.writeEntry("oldTractionN", os);
1165 oldTractionS_.writeEntry("oldTractionS", os);
1166 deltaN_.writeEntry("deltaN", os);
1167 deltaS_.writeEntry("deltaS", os);
1168 oldDeltaN_.writeEntry("oldDeltaN", os);
1169 oldDeltaS_.writeEntry("oldDeltaS", os);
1170 unloadingDeltaEff_.writeEntry("unloadingDeltaEff", os);
1171 currentGI_.writeEntry("currentGI", os);
1172 currentGII_.writeEntry("currentGII", os);
1173 oldGI_.writeEntry("oldGI", os);
1174 oldGII_.writeEntry("oldGII", os);
1176 os.writeKeyword("curTimeIndex")
1177 << curTimeIndex_ << token::END_STATEMENT << nl;
1178 os.writeKeyword("contact") << contact_<< token::END_STATEMENT << nl;
1179 os.writeKeyword("penaltyScale")
1180 << penaltyScale_ << token::END_STATEMENT << nl;
1181 os.writeKeyword("nonLinear")
1182 << nonLinearGeometry::nonLinearNames_[nonLinear_]
1183 << token::END_STATEMENT << nl;
1184 os.writeKeyword("orthotropic")
1185 << orthotropic_ << token::END_STATEMENT << nl;
1189 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1191 makePatchTypeField(fvPatchVectorField, solidCohesiveFvPatchVectorField);
1193 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1195 } // End namespace Foam
1197 // ************************************************************************* //