Solid cleanup, 2

This commit is contained in:
Hrvoje Jasak 2013-11-04 11:58:55 +00:00
parent df769c0387
commit fd68694dcb
17 changed files with 980 additions and 1112 deletions

View file

@ -67,6 +67,8 @@ finiteVolume = finiteVolume
$(finiteVolume)/gradSchemes/leastSquaresSolidInterfaceGrad/leastSquaresSolidInterfaceGrads.C $(finiteVolume)/gradSchemes/leastSquaresSolidInterfaceGrad/leastSquaresSolidInterfaceGrads.C
$(finiteVolume)/gradSchemes/leastSquaresSolidInterfaceGrad/leastSquaresSolidInterfaceVectors.C $(finiteVolume)/gradSchemes/leastSquaresSolidInterfaceGrad/leastSquaresSolidInterfaceVectors.C
nonLinearGeometry/nonLinearGeometry.C
rheologyLaws = $(constitutiveModel)/rheologyLaws rheologyLaws = $(constitutiveModel)/rheologyLaws
$(rheologyLaws)/rheologyLaw/rheologyLaw.C $(rheologyLaws)/rheologyLaw/rheologyLaw.C
$(rheologyLaws)/rheologyLaw/newRheologyLaw.C $(rheologyLaws)/rheologyLaw/newRheologyLaw.C

View file

@ -23,7 +23,6 @@ License
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
//#define DEBUG Info<<"In file "<<__FILE__<<" at line "<<__LINE__<<endl;
#include "solidCohesiveFvPatchVectorField.H" #include "solidCohesiveFvPatchVectorField.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
@ -75,7 +74,7 @@ solidCohesiveFvPatchVectorField::solidCohesiveFvPatchVectorField
curDeltaS_(0, 0.0), curDeltaS_(0, 0.0),
updateGlobalPatchMaterials_(true), updateGlobalPatchMaterials_(true),
globalPatchMaterials_(0, 0.0), globalPatchMaterials_(0, 0.0),
nonLinear_(OFF), nonLinear_(nonLinearGeometry::OFF),
orthotropic_(false) orthotropic_(false)
{} {}
@ -115,30 +114,33 @@ solidCohesiveFvPatchVectorField::solidCohesiveFvPatchVectorField
curDeltaS_(p.size(), 0.0), curDeltaS_(p.size(), 0.0),
updateGlobalPatchMaterials_(true), updateGlobalPatchMaterials_(true),
globalPatchMaterials_(0, 0.0), globalPatchMaterials_(0, 0.0),
nonLinear_(OFF), nonLinear_(nonLinearGeometry::OFF),
orthotropic_(false) orthotropic_(false)
{ {
Info << "Creating solidCohesive patch" << nl Info << "Creating solidCohesive patch" << nl
<< "\tOnly Dugdale law currently available!" << endl; << "\tOnly Dugdale law currently available!" << endl;
//- check if traction boundary is for non linear solver //- check if traction boundary is for non linear solver
if(dict.found("nonLinear")) if (dict.found("nonLinear"))
{ {
nonLinear_ = nonLinearNames_.read(dict.lookup("nonLinear"));; nonLinear_ = nonLinearGeometry::nonLinearNames_.read
(
dict.lookup("nonLinear")
);
if(nonLinear_ == UPDATED_LAGRANGIAN) if (nonLinear_ == nonLinearGeometry::UPDATED_LAGRANGIAN)
{ {
Info << "\tnonLinear set to updated Lagrangian" Info << "\tnonLinear set to updated Lagrangian"
<< endl; << endl;
} }
else if(nonLinear_ == TOTAL_LAGRANGIAN) else if (nonLinear_ == nonLinearGeometry::TOTAL_LAGRANGIAN)
{ {
Info << "\tnonLinear set to total Lagrangian" Info << "\tnonLinear set to total Lagrangian"
<< endl; << endl;
} }
} }
if(dict.found("orthotropic")) if (dict.found("orthotropic"))
{ {
orthotropic_ = Switch(dict.lookup("orthotropic")); orthotropic_ = Switch(dict.lookup("orthotropic"));
Info << "\t\torthotropic set to " << orthotropic_ << endl; Info << "\t\torthotropic set to " << orthotropic_ << endl;
@ -214,71 +216,71 @@ solidCohesiveFvPatchVectorField::solidCohesiveFvPatchVectorField
// vectorField("unloadingSeparationDistance", dict, p.size()); // vectorField("unloadingSeparationDistance", dict, p.size());
// } // }
if(dict.found("cracked")) if (dict.found("cracked"))
{ {
// cracked_ = Field<bool>("cracked", dict, p.size()); // cracked_ = Field<bool>("cracked", dict, p.size());
cracked_ = Field<scalar>("cracked", dict, p.size()); cracked_ = Field<scalar>("cracked", dict, p.size());
} }
if(dict.found("curTractionN")) if (dict.found("curTractionN"))
{ {
curTractionN_ = scalarField("curTractionN", dict, p.size()); curTractionN_ = scalarField("curTractionN", dict, p.size());
} }
if(dict.found("curTractionS")) if (dict.found("curTractionS"))
{ {
curTractionS_ = scalarField("curTractionS", dict, p.size()); curTractionS_ = scalarField("curTractionS", dict, p.size());
} }
if(dict.found("oldTractionN")) if (dict.found("oldTractionN"))
{ {
oldTractionN_ = scalarField("oldTractionN", dict, p.size()); oldTractionN_ = scalarField("oldTractionN", dict, p.size());
} }
if(dict.found("oldTractionS")) if (dict.found("oldTractionS"))
{ {
oldTractionS_ = scalarField("oldTractionS", dict, p.size()); oldTractionS_ = scalarField("oldTractionS", dict, p.size());
} }
if(dict.found("deltaN")) if (dict.found("deltaN"))
{ {
deltaN_ = scalarField("deltaN", dict, p.size()); deltaN_ = scalarField("deltaN", dict, p.size());
} }
if(dict.found("deltaS")) if (dict.found("deltaS"))
{ {
deltaS_ = scalarField("deltaS", dict, p.size()); deltaS_ = scalarField("deltaS", dict, p.size());
} }
if(dict.found("oldDeltaN")) if (dict.found("oldDeltaN"))
{ {
oldDeltaN_ = scalarField("oldDeltaN", dict, p.size()); oldDeltaN_ = scalarField("oldDeltaN", dict, p.size());
} }
if(dict.found("oldDeltaS")) if (dict.found("oldDeltaS"))
{ {
oldDeltaS_ = scalarField("oldDeltaS", dict, p.size()); oldDeltaS_ = scalarField("oldDeltaS", dict, p.size());
} }
if(dict.found("curDeltaN")) if (dict.found("curDeltaN"))
{ {
curDeltaN_ = scalarField("curDeltaN", dict, p.size()); curDeltaN_ = scalarField("curDeltaN", dict, p.size());
} }
if(dict.found("curDeltaS")) if (dict.found("curDeltaS"))
{ {
curDeltaS_ = scalarField("curDeltaS", dict, p.size()); curDeltaS_ = scalarField("curDeltaS", dict, p.size());
} }
if(dict.found("unloadingDeltaEff")) if (dict.found("unloadingDeltaEff"))
{ {
unloadingDeltaEff_ = scalarField("unloadingDeltaEff", dict, p.size()); unloadingDeltaEff_ = scalarField("unloadingDeltaEff", dict, p.size());
} }
if(dict.found("currentGI")) if (dict.found("currentGI"))
{ {
currentGI_ = scalarField("currentGI", dict, p.size()); currentGI_ = scalarField("currentGI", dict, p.size());
} }
if(dict.found("currentGII")) if (dict.found("currentGII"))
{ {
currentGII_ = scalarField("currentGII", dict, p.size()); currentGII_ = scalarField("currentGII", dict, p.size());
} }
if(dict.found("oldGI")) if (dict.found("oldGI"))
{ {
oldGI_ = scalarField("oldGI", dict, p.size()); oldGI_ = scalarField("oldGI", dict, p.size());
} }
if(dict.found("oldGII")) if (dict.found("oldGII"))
{ {
oldGII_ = scalarField("oldGII", dict, p.size()); oldGII_ = scalarField("oldGII", dict, p.size());
} }
@ -417,7 +419,7 @@ tmp<scalarField> solidCohesiveFvPatchVectorField::crackingAndDamage() const
forAll(tcrackingAndDamage(), facei) forAll(tcrackingAndDamage(), facei)
{ {
if(cracked_[facei]) if (cracked_[facei])
{ {
tcrackingAndDamage()[facei] = 2.0; tcrackingAndDamage()[facei] = 2.0;
} }
@ -471,7 +473,7 @@ bool solidCohesiveFvPatchVectorField::cracking()
label sumCracked = 0; label sumCracked = 0;
forAll(globalCracked, facei) forAll(globalCracked, facei)
{ {
if(globalCracked[facei] > 0.0) if (globalCracked[facei] > 0.0)
{ {
sumCracked++; sumCracked++;
} }
@ -689,7 +691,7 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
{ {
// we force the penalty factor to be calculated here for the first time // we force the penalty factor to be calculated here for the first time
// as all processors must call this at the same time // as all processors must call this at the same time
if(contact_ && patch().size() > 0) if (contact_ && patch().size() > 0)
{ {
// force calculation of penalty factor here // force calculation of penalty factor here
penaltyFactor(); penaltyFactor();
@ -727,11 +729,11 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
const crackerFvMesh& crackerMesh = refCast<const crackerFvMesh>(mesh); const crackerFvMesh& crackerMesh = refCast<const crackerFvMesh>(mesh);
// global patch material field is needed for multimaterial cohesive laws // global patch material field is needed for multimaterial cohesive laws
if(updateGlobalPatchMaterials_) if (updateGlobalPatchMaterials_)
{ {
updateGlobalPatchMaterials_ = false; updateGlobalPatchMaterials_ = false;
if(mesh.objectRegistry::foundObject<volScalarField>("materials")) if (mesh.objectRegistry::foundObject<volScalarField>("materials"))
{ {
scalarField localPatchMaterials = scalarField localPatchMaterials =
patch().lookupPatchField<volScalarField, scalar>("materials").patchInternalField(); patch().lookupPatchField<volScalarField, scalar>("materials").patchInternalField();
@ -755,7 +757,7 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
// Patch displacement // Patch displacement
vectorField UPatch = *this; vectorField UPatch = *this;
if(fieldName_ == "DU") if (fieldName_ == "DU")
{ {
UPatch += UPatch +=
patch().lookupPatchField<volVectorField, vector>("U"); patch().lookupPatchField<volVectorField, vector>("U");
@ -779,29 +781,18 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
globalIndex++; globalIndex++;
} }
// calculate the actual traction instead of using what was previously set
// traction_ =
// tractionBoundaryGradient().traction
// (
// patch().lookupPatchField<volTensorField, tensor>("grad("+fieldName_+")"),
// fieldName_,
// patch(),
// orthotropic_,
// NamedEnum<Foam::solidCohesiveFvPatchVectorField::nonLinearType, 3>::names[nonLinear_]
// );
//globalIndex = crackerMesh.localCrackStart(); //globalIndex = crackerMesh.localCrackStart();
for(label i = 0; i < patch().size(); i++) for(label i = 0; i < patch().size(); i++)
{ {
// update deltas // update deltas
curDeltaN_[i] = n[i] & delta[i]; curDeltaN_[i] = n[i] & delta[i];
curDeltaS_[i] = mag( (I - sqr(n[i])) & delta[i]); // shearing curDeltaS_[i] = mag( (I - sqr(n[i])) & delta[i]); // shearing
if(explicitSeparationDistance_) if (explicitSeparationDistance_)
{ {
deltaN_[i] = oldDeltaN_[i]; deltaN_[i] = oldDeltaN_[i];
deltaS_[i] = oldDeltaS_[i]; deltaS_[i] = oldDeltaS_[i];
if(mag(deltaN_[i]) < SMALL) if (mag(deltaN_[i]) < SMALL)
{ {
deltaN_[i] = 2*SMALL; deltaN_[i] = 2*SMALL;
} }
@ -824,9 +815,9 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
// update energies // update energies
// stop calculating after cracking for convergence (because crack might jump in and out of damaged/failed // stop calculating after cracking for convergence (because crack might jump in and out of damaged/failed
// only update energies if there is loading // only update energies if there is loading
if( !cracked_[i] && (deltaEff > (unloadingDeltaEff_[i]-SMALL)) ) if ( !cracked_[i] && (deltaEff > (unloadingDeltaEff_[i]-SMALL)) )
{ {
if((curTractionN_[i]+oldTractionN_[i]) > 0.0) // if the average normal stress is tensile if ((curTractionN_[i]+oldTractionN_[i]) > 0.0) // if the average normal stress is tensile
{ {
// trapezoidal rule // trapezoidal rule
currentGI_[i] = oldGI_[i] + ((0.5*(curTractionN_[i]+oldTractionN_[i]))*(deltaN_[i]-oldDeltaN_[i])); currentGI_[i] = oldGI_[i] + ((0.5*(curTractionN_[i]+oldTractionN_[i]))*(deltaN_[i]-oldDeltaN_[i]));
@ -856,16 +847,16 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
// loading // loading
// if the effective delta is greater than unloadingDeltaEff then there is loading // if the effective delta is greater than unloadingDeltaEff then there is loading
// unloadingDeltaEff is the maximum previsouly reached deltaEff // unloadingDeltaEff is the maximum previsouly reached deltaEff
if(deltaEff > (unloadingDeltaEff_[i]-SMALL) ) if (deltaEff > (unloadingDeltaEff_[i]-SMALL) )
{ {
// at the moment loading and unloading are the same // at the moment loading and unloading are the same
// if total energy is dissipated, then fully crack face // if total energy is dissipated, then fully crack face
//if( currentG > GIc[i] || cracked_[i] ) //Gc ) //if ( currentG > GIc[i] || cracked_[i] ) //Gc )
// propagation // propagation
if( ((currentGI_[i]/GIc[i]) + (currentGII_[i]/GIIc[i])) >= 1 ) if ( ((currentGI_[i]/GIc[i]) + (currentGII_[i]/GIIc[i])) >= 1 )
{ {
//Pout << "GIc[i] is " << GIc[i] << ", curG is " << currentG << endl; //Pout << "GIc[i] is " << GIc[i] << ", curG is " << currentG << endl;
if(!cracked_[i]) Pout << "Face " << i << " is fully cracked" << endl; if (!cracked_[i]) Pout << "Face " << i << " is fully cracked" << endl;
cracked_[i] = true; cracked_[i] = true;
@ -880,7 +871,7 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
// To-do: we must calculate actual distances // To-do: we must calculate actual distances
curNormalTraction = 0.0; curNormalTraction = 0.0;
curTangentialTraction = vector::zero; curTangentialTraction = vector::zero;
if( contact_ && deltaN_[i] <= 0.0 ) if ( contact_ && deltaN_[i] <= 0.0 )
{ {
curNormalTraction = deltaN_[i]*penaltyFactor(); curNormalTraction = deltaN_[i]*penaltyFactor();
//Info << "penaltyFactor() is " << penaltyFactor() << endl; //Info << "penaltyFactor() is " << penaltyFactor() << endl;
@ -901,9 +892,9 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
} }
// damging face with positive normal delta // damging face with positive normal delta
else if( deltaN_[i] > 0.0 ) else if ( deltaN_[i] > 0.0 )
{ {
if(cracked_[i]) Pout << "Face " << i << " is un-cracked" << endl; if (cracked_[i]) Pout << "Face " << i << " is un-cracked" << endl;
cracked_[i] = false; cracked_[i] = false;
@ -937,7 +928,7 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
// damaging faces with negative normal delta // damaging faces with negative normal delta
else else
{ {
if(cracked_[i]) Pout << "Face " << i << " is un-cracked" << endl; if (cracked_[i]) Pout << "Face " << i << " is un-cracked" << endl;
cracked_[i] = false; cracked_[i] = false;
//Pout << "Contact and shearing face " << i << endl; //Pout << "Contact and shearing face " << i << endl;
@ -952,7 +943,7 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
// Simple penalty condition // Simple penalty condition
scalar penaltyFac = 0.0; scalar penaltyFac = 0.0;
if(contact_) if (contact_)
{ {
penaltyFac = penaltyFactor(); penaltyFac = penaltyFactor();
} }
@ -997,15 +988,15 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
this->refGrad() = this->refGrad() =
tractionBoundaryGradient() tractionBoundaryGradient()
( (
traction_, traction_,
scalarField(traction_.size(), 0.0), scalarField(traction_.size(), 0.0),
word(fieldName_), word(fieldName_),
patch(), patch(),
orthotropic_, orthotropic_,
NamedEnum<Foam::solidCohesiveFvPatchVectorField::nonLinearType, 3>::names[nonLinear_] nonLinearGeometry::nonLinearNames_[nonLinear_]
)(); )();
directionMixedFvPatchVectorField::updateCoeffs(); directionMixedFvPatchVectorField::updateCoeffs();
} }
@ -1016,12 +1007,12 @@ void solidCohesiveFvPatchVectorField::updateCoeffs()
// approx penaltyFactor from mechanical properties // approx penaltyFactor from mechanical properties
// this can then be scaled using the penaltyScale // this can then be scaled using the penaltyScale
// to-do: write equivalent for orthotropic // to-do: write equivalent for orthotropic
if(orthotropic_) if (orthotropic_)
{ {
FatalError << "solidCohesiveFvPatchVectorField::calcPenaltyFactor()" FatalError << "solidCohesiveFvPatchVectorField::calcPenaltyFactor()"
<< " has yet to be written for orthotropic" << " has yet to be written for orthotropic"
<< exit(FatalError); << exit(FatalError);
} }
const label patchID = patch().index(); const label patchID = patch().index();
const fvMesh& mesh = patch().boundaryMesh().mesh(); const fvMesh& mesh = patch().boundaryMesh().mesh();
@ -1080,22 +1071,11 @@ void solidCohesiveFvPatchVectorField::write(Ostream& os) const
os.writeKeyword("curTimeIndex") << curTimeIndex_ << token::END_STATEMENT << nl; os.writeKeyword("curTimeIndex") << curTimeIndex_ << token::END_STATEMENT << nl;
os.writeKeyword("contact") << contact_<< token::END_STATEMENT << nl; os.writeKeyword("contact") << contact_<< token::END_STATEMENT << nl;
os.writeKeyword("penaltyScale") << penaltyScale_ << token::END_STATEMENT << nl; os.writeKeyword("penaltyScale") << penaltyScale_ << token::END_STATEMENT << nl;
os.writeKeyword("nonLinear") << nonLinearNames_[nonLinear_] << token::END_STATEMENT << nl; os.writeKeyword("nonLinear") << nonLinearGeometry::nonLinearNames_[nonLinear_] << token::END_STATEMENT << nl;
os.writeKeyword("orthotropic") << orthotropic_ << token::END_STATEMENT << nl; os.writeKeyword("orthotropic") << orthotropic_ << token::END_STATEMENT << nl;
} }
template<>
const char* Foam::NamedEnum<Foam::solidCohesiveFvPatchVectorField::nonLinearType, 3>::names[] =
{
"off",
"updatedLagrangian",
"totalLagrangian"
};
const Foam::NamedEnum<Foam::solidCohesiveFvPatchVectorField::nonLinearType, 3>
Foam::solidCohesiveFvPatchVectorField::nonLinearNames_;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
makePatchTypeField(fvPatchVectorField, solidCohesiveFvPatchVectorField); makePatchTypeField(fvPatchVectorField, solidCohesiveFvPatchVectorField);

View file

@ -29,7 +29,7 @@ Description
Cohesive law fv patch field for arbitrary crack procedure, Cohesive law fv patch field for arbitrary crack procedure,
where the mode mixity is allowed to vary depending on how where the mode mixity is allowed to vary depending on how
the crack opens. the crack opens.
This procedure allows sigmaMax, tauMax, GIc, and GIIc This procedure allows sigmaMax, tauMax, GIc, and GIIc
to be independently specified. to be independently specified.
@ -37,11 +37,11 @@ Description
The dissipated fracture energy is constantly monitored, by The dissipated fracture energy is constantly monitored, by
integrating in time. integrating in time.
Author Author
Philip Cardiff UCD Philip Cardiff UCD
based on original Tukovic cohesive law boundary condition. based on original Tukovic cohesive law boundary condition.
SourceFiles SourceFiles
solidCohesiveFvPatchVectorField.C solidCohesiveFvPatchVectorField.C
@ -52,6 +52,7 @@ SourceFiles
#include "fvPatchFields.H" #include "fvPatchFields.H"
#include "directionMixedFvPatchFields.H" #include "directionMixedFvPatchFields.H"
#include "nonLinearGeometry.H"
#include "cohesiveFvPatch.H" #include "cohesiveFvPatch.H"
#include "Switch.H" #include "Switch.H"
#include "tractionBoundaryGradient.H" #include "tractionBoundaryGradient.H"
@ -63,7 +64,7 @@ namespace Foam
{ {
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class solidCohesiveFvPatch Declaration Class solidCohesiveFvPatch Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
class solidCohesiveFvPatchVectorField class solidCohesiveFvPatchVectorField
@ -115,7 +116,7 @@ class solidCohesiveFvPatchVectorField
scalarField currentGII_; scalarField currentGII_;
scalarField oldGII_; scalarField oldGII_;
//- Current time index //- Current time index
label curTimeIndex_; label curTimeIndex_;
@ -125,8 +126,8 @@ class solidCohesiveFvPatchVectorField
scalar penaltyScale_; scalar penaltyScale_;
scalar frictionCoeff_; // Coulomb friction coefficient scalar frictionCoeff_; // Coulomb friction coefficient
// If yes, cohesive traction will be calculated // If yes, cohesive traction will be calculated
// using old separation distance // using old separation distance
Switch explicitSeparationDistance_; Switch explicitSeparationDistance_;
scalarField curDeltaN_; scalarField curDeltaN_;
scalarField curDeltaS_; scalarField curDeltaS_;
@ -135,18 +136,8 @@ class solidCohesiveFvPatchVectorField
bool updateGlobalPatchMaterials_; bool updateGlobalPatchMaterials_;
scalarField globalPatchMaterials_; scalarField globalPatchMaterials_;
//- non-linear solver options //- Is it a non linear solver
enum nonLinearType nonLinearGeometry::nonLinearType nonLinear_;
{
OFF,
UPDATED_LAGRANGIAN,
TOTAL_LAGRANGIAN
};
static const NamedEnum<nonLinearType, 3> nonLinearNames_;
//- if it is a non linear solver
nonLinearType nonLinear_;
//- if it is an orthropic solver //- if it is an orthropic solver
Switch orthotropic_; Switch orthotropic_;
@ -158,13 +149,13 @@ class solidCohesiveFvPatchVectorField
void calcPenaltyFactor(); void calcPenaltyFactor();
virtual scalar penaltyFactor() virtual scalar penaltyFactor()
{ {
if(!penaltyFactorPtr_) if(!penaltyFactorPtr_)
{ {
calcPenaltyFactor(); calcPenaltyFactor();
} }
return *penaltyFactorPtr_; return *penaltyFactorPtr_;
} }
public: public:

View file

@ -97,7 +97,7 @@ protected:
//- Return reference to mesh //- Return reference to mesh
const fvMesh& mesh() const const fvMesh& mesh() const
{ {
return patch_.boundaryMesh().mesh(); return patch_.boundaryMesh().mesh();
} }
@ -116,14 +116,22 @@ public:
dictionary, dictionary,
( (
const word name, const word name,
const fvPatch& patch, const fvPatch& patch,
const dictionary& dict, const dictionary& dict,
const label masterPatchID, const label masterPatchID,
const label slavePatchID, const label slavePatchID,
const label masterFaceZoneID, const label masterFaceZoneID,
const label slaveFaceZoneID const label slaveFaceZoneID
), ),
(name, patch, dict, masterPatchID, slavePatchID, masterFaceZoneID, slaveFaceZoneID) (
name,
patch,
dict,
masterPatchID,
slavePatchID,
masterFaceZoneID,
slaveFaceZoneID
)
); );
@ -135,10 +143,10 @@ public:
const word& name, const word& name,
const fvPatch& patch, const fvPatch& patch,
const dictionary& dict, const dictionary& dict,
const label masterPatchID, const label masterPatchID,
const label slavePatchID, const label slavePatchID,
const label masterFaceZoneID, const label masterFaceZoneID,
const label slaveFaceZoneID const label slaveFaceZoneID
); );
@ -150,10 +158,10 @@ public:
const word& name, const word& name,
const fvPatch& patch, const fvPatch& patch,
const dictionary& dict, const dictionary& dict,
const label masterPatchID, const label masterPatchID,
const label slavePatchID, const label slavePatchID,
const label masterFaceZoneID, const label masterFaceZoneID,
const label slaveFaceZoneID const label slaveFaceZoneID
); );
@ -173,18 +181,18 @@ public:
//- Correct contatc model //- Correct contatc model
virtual void correct virtual void correct
( (
const vectorField& slavePressure, const vectorField& slavePressure,
const PrimitivePatch<face, List, pointField>& masterFaceZonePatch, const PrimitivePatch<face, List, pointField>& masterFaceZonePatch,
const PrimitivePatch<face, List, pointField>& slaveFaceZonePatch, const PrimitivePatch<face, List, pointField>& slaveFaceZonePatch,
const intersection::algorithm alg, const intersection::algorithm alg,
const intersection::direction dir, const intersection::direction dir,
const word interpolationMethod, const word interpolationMethod,
const word fieldName, const word fieldName,
const Switch orthotropic, const Switch orthotropic,
const word nonLinear, const word nonLinear,
const vectorField& slaveFaceNormals const vectorField& slaveFaceNormals
) = 0; ) = 0;
//- Return slave friction displacement //- Return slave friction displacement
virtual const vectorField& slaveDisp() const = 0; virtual const vectorField& slaveDisp() const = 0;
@ -198,33 +206,33 @@ public:
//- Return master patch ID //- Return master patch ID
virtual label masterPatchID() const virtual label masterPatchID() const
{ {
return masterPatchID_; return masterPatchID_;
} }
//- Return master patch ID //- Return master patch ID
virtual label slavePatchID() const virtual label slavePatchID() const
{ {
return slavePatchID_; return slavePatchID_;
} }
//- Return master face zone ID //- Return master face zone ID
virtual label masterFaceZoneID() const virtual label masterFaceZoneID() const
{ {
return masterFaceZoneID_; return masterFaceZoneID_;
} }
//- Return master face zone ID //- Return master face zone ID
virtual label slaveFaceZoneID() const virtual label slaveFaceZoneID() const
{ {
return slaveFaceZoneID_; return slaveFaceZoneID_;
} }
//- Return stick slip faces field //- Return stick slip faces field
// virtual volScalarField& stickSlipFaces() // virtual volScalarField& stickSlipFaces()
virtual scalarField& stickSlipFaces() virtual scalarField& stickSlipFaces()
{ {
return stickSlipFaces_; return stickSlipFaces_;
} }
//- Write model dictionary //- Write model dictionary
virtual void writeDict(Ostream& os) const {}; virtual void writeDict(Ostream& os) const {};

View file

@ -48,6 +48,7 @@ Author
#include "fvPatchFields.H" #include "fvPatchFields.H"
#include "directionMixedFvPatchFields.H" #include "directionMixedFvPatchFields.H"
#include "nonLinearGeometry.H"
#include "Switch.H" #include "Switch.H"
#include "interpolationTable.H" #include "interpolationTable.H"
@ -78,18 +79,8 @@ class fixedDisplacementOrSolidTractionFvPatchVectorField
//- Displacement //- Displacement
vectorField displacement_; vectorField displacement_;
//- non-linear solver options //- Is it a non linear solver
enum nonLinearType nonLinearGeometry::nonLinearType nonLinear_;
{
OFF,
UPDATED_LAGRANGIAN,
TOTAL_LAGRANGIAN
};
static const NamedEnum<nonLinearType, 3> nonLinearNames_;
//- if it is a non linear solver
nonLinearType nonLinear_;
//- if it is an orthropic solver //- if it is an orthropic solver
Switch orthotropic_; Switch orthotropic_;

View file

@ -43,7 +43,8 @@ namespace Foam
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
fixedDisplacementZeroShearFvPatchVectorField::fixedDisplacementZeroShearFvPatchVectorField fixedDisplacementZeroShearFvPatchVectorField::
fixedDisplacementZeroShearFvPatchVectorField
( (
const fvPatch& p, const fvPatch& p,
const DimensionedField<vector, volMesh>& iF const DimensionedField<vector, volMesh>& iF
@ -51,12 +52,13 @@ fixedDisplacementZeroShearFvPatchVectorField::fixedDisplacementZeroShearFvPatchV
: :
directionMixedFvPatchVectorField(p, iF), directionMixedFvPatchVectorField(p, iF),
fieldName_("undefined"), fieldName_("undefined"),
nonLinear_(OFF), nonLinear_(nonLinearGeometry::OFF),
orthotropic_(false) orthotropic_(false)
{} {}
fixedDisplacementZeroShearFvPatchVectorField::fixedDisplacementZeroShearFvPatchVectorField fixedDisplacementZeroShearFvPatchVectorField::
fixedDisplacementZeroShearFvPatchVectorField
( (
const fixedDisplacementZeroShearFvPatchVectorField& ptf, const fixedDisplacementZeroShearFvPatchVectorField& ptf,
const fvPatch& p, const fvPatch& p,
@ -71,7 +73,8 @@ fixedDisplacementZeroShearFvPatchVectorField::fixedDisplacementZeroShearFvPatchV
{} {}
fixedDisplacementZeroShearFvPatchVectorField::fixedDisplacementZeroShearFvPatchVectorField fixedDisplacementZeroShearFvPatchVectorField::
fixedDisplacementZeroShearFvPatchVectorField
( (
const fvPatch& p, const fvPatch& p,
const DimensionedField<vector, volMesh>& iF, const DimensionedField<vector, volMesh>& iF,
@ -80,45 +83,48 @@ fixedDisplacementZeroShearFvPatchVectorField::fixedDisplacementZeroShearFvPatchV
: :
directionMixedFvPatchVectorField(p, iF), directionMixedFvPatchVectorField(p, iF),
fieldName_(dimensionedInternalField().name()), fieldName_(dimensionedInternalField().name()),
nonLinear_(OFF), nonLinear_(nonLinearGeometry::OFF),
orthotropic_(false) orthotropic_(false)
{ {
//- check if traction boundary is for non linear solver //- check if traction boundary is for non linear solver
if(dict.found("nonLinear")) if (dict.found("nonLinear"))
{ {
nonLinear_ = nonLinearNames_.read(dict.lookup("nonLinear"));; nonLinear_ = nonLinearGeometry::nonLinearNames_.read
(
dict.lookup("nonLinear")
);
if(nonLinear_ == UPDATED_LAGRANGIAN) if (nonLinear_ == nonLinearGeometry::UPDATED_LAGRANGIAN)
{ {
Info << "\tnonLinear set to updated Lagrangian" Info<< "\tnonLinear set to updated Lagrangian"
<< endl; << endl;
} }
else if(nonLinear_ == TOTAL_LAGRANGIAN) else if (nonLinear_ == nonLinearGeometry::TOTAL_LAGRANGIAN)
{ {
Info << "\tnonLinear set to total Lagrangian" Info<< "\tnonLinear set to total Lagrangian"
<< endl; << endl;
} }
} }
if(dict.found("orthotropic")) if (dict.found("orthotropic"))
{ {
orthotropic_ = Switch(dict.lookup("orthotropic")); orthotropic_ = Switch(dict.lookup("orthotropic"));
Info << "\t\torthotropic set to " << orthotropic_ << endl; Info << "\t\torthotropic set to " << orthotropic_ << endl;
} }
//- the leastSquares has zero non-orthogonal correction //- the leastSquares has zero non-orthogonal correction
//- on the boundary //- on the boundary
//- so the gradient scheme should be extendedLeastSquares //- so the gradient scheme should be extendedLeastSquares
// if(Foam::word(dimensionedInternalField().mesh()..schemesDict().gradScheme("grad(" + fieldName_ + ")")) != "extendedLeastSquares") // if (Foam::word(dimensionedInternalField().mesh()..schemesDict().gradScheme("grad(" + fieldName_ + ")")) != "extendedLeastSquares")
// { // {
// Warning << "The gradScheme for " << fieldName_ // Warning << "The gradScheme for " << fieldName_
// << " should be \"extendedLeastSquares 0\" for the boundary " // << " should be \"extendedLeastSquares 0\" for the boundary "
// << "non-orthogonal correction to be right" << endl; // << "non-orthogonal correction to be right" << endl;
// } // }
this->refGrad() = vector::zero; this->refGrad() = vector::zero;
vectorField n = patch().nf(); vectorField n = patch().nf();
this->valueFraction() = sqr(n); this->valueFraction() = sqr(n);
if (dict.found("value")) if (dict.found("value"))
@ -128,18 +134,18 @@ fixedDisplacementZeroShearFvPatchVectorField::fixedDisplacementZeroShearFvPatchV
else else
{ {
FatalError << "value entry not found for patch " << patch().name() FatalError << "value entry not found for patch " << patch().name()
<< exit(FatalError); << exit(FatalError);
} }
this->refValue() = *this; this->refValue() = *this;
Field<vector> normalValue = transform(valueFraction(), refValue()); Field<vector> normalValue = transform(valueFraction(), refValue());
Field<vector> gradValue = Field<vector> gradValue =
this->patchInternalField() + refGrad()/this->patch().deltaCoeffs(); this->patchInternalField() + refGrad()/this->patch().deltaCoeffs();
Field<vector> transformGradValue = Field<vector> transformGradValue =
transform(I - valueFraction(), gradValue); transform(I - valueFraction(), gradValue);
Field<vector>::operator=(normalValue + transformGradValue); Field<vector>::operator=(normalValue + transformGradValue);
} }
@ -198,14 +204,14 @@ void fixedDisplacementZeroShearFvPatchVectorField::updateCoeffs()
//- or fix deformed normal //- or fix deformed normal
//- I should add an option to choose which normal to fix //- I should add an option to choose which normal to fix
// if(nonLinear_ != OFF) // if (nonLinear_ != OFF)
// { // {
// tensorField F = I + gradField; // tensorField F = I + gradField;
// tensorField Finv = inv(F); // tensorField Finv = inv(F);
// scalarField J = det(F); // scalarField J = det(F);
// vectorField nCurrent = Finv & n; // vectorField nCurrent = Finv & n;
// nCurrent /= mag(nCurrent); // nCurrent /= mag(nCurrent);
// this->valueFraction() = sqr(nCurrent); // this->valueFraction() = sqr(nCurrent);
// } // }
refGrad() = tractionBoundaryGradient() refGrad() = tractionBoundaryGradient()
@ -215,7 +221,7 @@ void fixedDisplacementZeroShearFvPatchVectorField::updateCoeffs()
word(fieldName_), word(fieldName_),
patch(), patch(),
orthotropic_, orthotropic_,
NamedEnum<Foam::fixedDisplacementZeroShearFvPatchVectorField::nonLinearType, 3>::names[nonLinear_] nonLinearGeometry::nonLinearNames_[nonLinear_]
)(); )();
directionMixedFvPatchVectorField::updateCoeffs(); directionMixedFvPatchVectorField::updateCoeffs();
@ -226,24 +232,20 @@ void fixedDisplacementZeroShearFvPatchVectorField::updateCoeffs()
void fixedDisplacementZeroShearFvPatchVectorField::write(Ostream& os) const void fixedDisplacementZeroShearFvPatchVectorField::write(Ostream& os) const
{ {
directionMixedFvPatchVectorField::write(os); directionMixedFvPatchVectorField::write(os);
os.writeKeyword("nonLinear") << nonLinearNames_[nonLinear_] << token::END_STATEMENT << nl; os.writeKeyword("nonLinear")
<< nonLinearGeometry::nonLinearNames_[nonLinear_]
<< token::END_STATEMENT << nl;
} }
template<>
const char* Foam::NamedEnum<Foam::fixedDisplacementZeroShearFvPatchVectorField::nonLinearType, 3>::names[] =
{
"off",
"updatedLagrangian",
"totalLagrangian"
};
const Foam::NamedEnum<Foam::fixedDisplacementZeroShearFvPatchVectorField::nonLinearType, 3>
Foam::fixedDisplacementZeroShearFvPatchVectorField::nonLinearNames_;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
makePatchTypeField(fvPatchVectorField, fixedDisplacementZeroShearFvPatchVectorField); makePatchTypeField
(
fvPatchVectorField,
fixedDisplacementZeroShearFvPatchVectorField
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View file

@ -48,6 +48,7 @@ Author
#include "fvPatchFields.H" #include "fvPatchFields.H"
#include "directionMixedFvPatchFields.H" #include "directionMixedFvPatchFields.H"
#include "nonLinearGeometry.H"
#include "Switch.H" #include "Switch.H"
#include "interpolationTable.H" #include "interpolationTable.H"
@ -81,20 +82,10 @@ class fixedDisplacementZeroShearOrSolidTractionFvPatchVectorField
//- Normal to fix for displacement phase //- Normal to fix for displacement phase
vector fixedNormal_; vector fixedNormal_;
//- non-linear solver options //- Is it a non linear solver
enum nonLinearType nonLinearGeometry::nonLinearType nonLinear_;
{
OFF,
UPDATED_LAGRANGIAN,
TOTAL_LAGRANGIAN
};
static const NamedEnum<nonLinearType, 3> nonLinearNames_;
//- if it is a non linear solver //- Is it an orthropic solver
nonLinearType nonLinear_;
//- if it is an orthropic solver
Switch orthotropic_; Switch orthotropic_;
//- The time series - 0 for traction, anything else for displacement. //- The time series - 0 for traction, anything else for displacement.

View file

@ -50,8 +50,8 @@ fixedRotationFvPatchVectorField::fixedRotationFvPatchVectorField
rotationAngle_(0.0), rotationAngle_(0.0),
rotationAxis_(vector::zero), rotationAxis_(vector::zero),
rotationOrigin_(vector::zero), rotationOrigin_(vector::zero),
origCf_(0,vector::zero), origCf_(0, vector::zero),
nonLinear_(OFF) nonLinear_(nonLinearGeometry::OFF)
{} {}
@ -69,7 +69,7 @@ fixedRotationFvPatchVectorField::fixedRotationFvPatchVectorField
rotationAxis_(ptf.rotationAxis_), rotationAxis_(ptf.rotationAxis_),
rotationOrigin_(ptf.rotationOrigin_), rotationOrigin_(ptf.rotationOrigin_),
origCf_(ptf.origCf_), origCf_(ptf.origCf_),
nonLinear_(OFF) nonLinear_(nonLinearGeometry::OFF)
{} {}
@ -86,33 +86,36 @@ fixedRotationFvPatchVectorField::fixedRotationFvPatchVectorField
rotationAxis_(dict.lookup("rotationAxis")), rotationAxis_(dict.lookup("rotationAxis")),
rotationOrigin_(dict.lookup("rotationOrigin")), rotationOrigin_(dict.lookup("rotationOrigin")),
origCf_(patch().patch().faceCentres()), origCf_(patch().patch().faceCentres()),
nonLinear_(OFF) nonLinear_(nonLinearGeometry::OFF)
{ {
//- check if traction boundary is for non linear solver //- check if traction boundary is for non linear solver
if(dict.found("nonLinear")) if (dict.found("nonLinear"))
{ {
nonLinear_ = nonLinearNames_.read(dict.lookup("nonLinear"));; nonLinear_ = nonLinearGeometry::nonLinearNames_.read
(
dict.lookup("nonLinear")
);
if(nonLinear_ == UPDATED_LAGRANGIAN) if (nonLinear_ == nonLinearGeometry::UPDATED_LAGRANGIAN)
{ {
Info << "\tnonLinear set to updated Lagrangian" Info<< "\tnonLinear set to updated Lagrangian"
<< endl; << endl;
} }
else if(nonLinear_ == TOTAL_LAGRANGIAN) else if (nonLinear_ == nonLinearGeometry::TOTAL_LAGRANGIAN)
{ {
Info << "\tnonLinear set to total Lagrangian" Info << "\tnonLinear set to total Lagrangian"
<< endl; << endl;
} }
} }
//- the leastSquares has zero non-orthogonal correction //- the leastSquares has zero non-orthogonal correction
//- on the boundary //- on the boundary
//- so the gradient scheme should be extendedLeastSquares //- so the gradient scheme should be extendedLeastSquares
if(Foam::word(dimensionedInternalField().mesh().schemesDict().gradScheme("grad(" + fieldName_ + ")")) != "extendedLeastSquares") if (word(dimensionedInternalField().mesh().schemesDict().gradScheme("grad(" + fieldName_ + ")")) != "extendedLeastSquares")
{ {
Warning << "The gradScheme for " << fieldName_ Warning << "The gradScheme for " << fieldName_
<< " should be \"extendedLeastSquares 0\" for the boundary " << " should be \"extendedLeastSquares 0\" for the boundary "
<< "non-orthogonal correction to be right" << endl; << "non-orthogonal correction to be right" << endl;
} }
} }
@ -155,7 +158,7 @@ snGrad() const
{ {
//- fixedValue snGrad with no correction //- fixedValue snGrad with no correction
// return (*this - patchInternalField())*this->patch().deltaCoeffs(); // return (*this - patchInternalField())*this->patch().deltaCoeffs();
const fvPatchField<tensor>& gradField = const fvPatchField<tensor>& gradField =
patch().lookupPatchField<volTensorField, tensor> patch().lookupPatchField<volTensorField, tensor>
( (
@ -168,9 +171,9 @@ snGrad() const
//- correction vector //- correction vector
vectorField k = delta - n*(n&delta); vectorField k = delta - n*(n&delta);
return return
( (
*this *this
- (patchInternalField() + (k&gradField.patchInternalField())) - (patchInternalField() + (k&gradField.patchInternalField()))
)*this->patch().deltaCoeffs(); )*this->patch().deltaCoeffs();
} }
@ -185,23 +188,23 @@ void fixedRotationFvPatchVectorField::updateCoeffs()
tensor rotMat = RodriguesRotation(rotationAxis_, rotationAngle_); tensor rotMat = RodriguesRotation(rotationAxis_, rotationAngle_);
vectorField oldFaceCentres = dimensionedInternalField().mesh().C().boundaryField()[patch().index()]; vectorField oldFaceCentres = dimensionedInternalField().mesh().C().boundaryField()[patch().index()];
vectorField newFaceCentres = (rotMat & (oldFaceCentres - rotationOrigin_)) + rotationOrigin_; vectorField newFaceCentres = (rotMat & (oldFaceCentres - rotationOrigin_)) + rotationOrigin_;
vectorField disp = newFaceCentres - oldFaceCentres; vectorField disp = newFaceCentres - oldFaceCentres;
if(fieldName_ == "DU") if (fieldName_ == "DU")
{ {
const fvPatchField<vector>& U = const fvPatchField<vector>& U =
patch().lookupPatchField<volVectorField, vector>("U"); patch().lookupPatchField<volVectorField, vector>("U");
disp -= U; disp -= U;
} }
else if(fieldName_ != "U") else if (fieldName_ != "U")
{ {
FatalError << "The displacement field should be U or DU" FatalError << "The displacement field should be U or DU"
<< exit(FatalError); << exit(FatalError);
} }
fvPatchField<vector>::operator== fvPatchField<vector>::operator==
( (
disp disp
@ -232,25 +235,21 @@ gradientBoundaryCoeffs() const
void fixedRotationFvPatchVectorField::write(Ostream& os) const void fixedRotationFvPatchVectorField::write(Ostream& os) const
{ {
fixedValueFvPatchVectorField::write(os); fixedValueFvPatchVectorField::write(os);
os.writeKeyword("rotationAngle") << rotationAngle_ << token::END_STATEMENT << nl; os.writeKeyword("rotationAngle")
os.writeKeyword("rotationAxis") << rotationAxis_ << token::END_STATEMENT << nl; << rotationAngle_
os.writeKeyword("rotationOrigin") << rotationOrigin_ << token::END_STATEMENT << nl; << token::END_STATEMENT << nl;
os.writeKeyword("nonLinear") << nonLinearNames_[nonLinear_] << token::END_STATEMENT << nl; os.writeKeyword("rotationAxis")
<< rotationAxis_
<< token::END_STATEMENT << nl;
os.writeKeyword("rotationOrigin")
<< rotationOrigin_
<< token::END_STATEMENT << nl;
os.writeKeyword("nonLinear")
<< nonLinearGeometry::nonLinearNames_[nonLinear_]
<< token::END_STATEMENT << nl;
} }
template<>
const char* Foam::NamedEnum<Foam::fixedRotationFvPatchVectorField::nonLinearType, 3>::names[] =
{
"off",
"updatedLagrangian",
"totalLagrangian"
};
const Foam::NamedEnum<Foam::fixedRotationFvPatchVectorField::nonLinearType, 3>
Foam::fixedRotationFvPatchVectorField::nonLinearNames_;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
makePatchTypeField makePatchTypeField

View file

@ -42,6 +42,7 @@ Author
#include "fvPatchFields.H" #include "fvPatchFields.H"
#include "fixedValueFvPatchFields.H" #include "fixedValueFvPatchFields.H"
#include "nonLinearGeometry.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -49,7 +50,7 @@ namespace Foam
{ {
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class fixedRotationFvPatch Declaration Class fixedRotationFvPatch Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
class fixedRotationFvPatchVectorField class fixedRotationFvPatchVectorField
@ -74,18 +75,9 @@ class fixedRotationFvPatchVectorField
//- Initial mesh position //- Initial mesh position
const vectorField origCf_; const vectorField origCf_;
//- non-linear solver options //- Is it a non linear solver
enum nonLinearType nonLinearGeometry::nonLinearType nonLinear_;
{
OFF,
UPDATED_LAGRANGIAN,
TOTAL_LAGRANGIAN
};
static const NamedEnum<nonLinearType, 3> nonLinearNames_;
//- if it is a non linear solver
nonLinearType nonLinear_;
public: public:
@ -160,16 +152,17 @@ public:
// Access functions // Access functions
virtual nonLinearType& nonLinear() const nonLinearGeometry::nonLinearType& nonLinear() const
{ {
return nonLinear_; return nonLinear_;
} }
virtual const NamedEnum<nonLinearType, 3>& nonLinearNames() nonLinearGeometry::nonLinearType& nonLinear()
{ {
return nonLinearNames_; return nonLinear_;
} }
// Evaluation functions // Evaluation functions
//- Return patch-normal gradient //- Return patch-normal gradient

View file

@ -46,6 +46,7 @@ Author
#include "fvPatchFields.H" #include "fvPatchFields.H"
#include "directionMixedFvPatchFields.H" #include "directionMixedFvPatchFields.H"
#include "nonLinearGeometry.H"
#include "normalContactModel.H" #include "normalContactModel.H"
#include "frictionContactModel.H" #include "frictionContactModel.H"
#include "primitivePatchInterpolation.H" #include "primitivePatchInterpolation.H"
@ -117,7 +118,7 @@ class solidContactFvPatchVectorField
word interpolationMethod_; word interpolationMethod_;
//- zoneToZone or ggiZone for interpolation of traction from slave to master //- zoneToZone or ggiZone for interpolation of traction from slave to master
//zoneToZoneInterpolation* slaveToMasterPatchToPatchInterpolatorPtr_; //zoneToZoneInterpolation* slaveToMasterPatchToPatchInterpolatorPtr_;
PatchToPatchInterpolation< PrimitivePatch<face, List, pointField>, PatchToPatchInterpolation< PrimitivePatch<face, List, pointField>,
PrimitivePatch<face, List, pointField> PrimitivePatch<face, List, pointField>
>* slaveToMasterPatchToPatchInterpolatorPtr_; >* slaveToMasterPatchToPatchInterpolatorPtr_;
@ -162,27 +163,17 @@ class solidContactFvPatchVectorField
// Force correction of contact on next call // Force correction of contact on next call
bool forceCorrection_; bool forceCorrection_;
// if the solver uses a nonlinear approach //- Is it a non linear solver
//- non-linear solver options nonLinearGeometry::nonLinearType nonLinear_;
enum nonLinearType
{
OFF,
UPDATED_LAGRANGIAN,
TOTAL_LAGRANGIAN
};
static const NamedEnum<nonLinearType, 3> nonLinearNames_;
//- if it is a non linear solver
nonLinearType nonLinear_;
// Private Member Functions // Private Member Functions
// Move the contact face zone patches to the deformed position // Move the contact face zone patches to the deformed position
virtual void moveFaceZonePatches(); virtual void moveFaceZonePatches();
// check shadow patch and face zones exist // check shadow patch and face zones exist
virtual bool checkPatchAndFaceZones(const dictionary& dict) const; virtual bool checkPatchAndFaceZones(const dictionary& dict) const;
public: public:
@ -352,7 +343,7 @@ public:
//- with non-orthogonal correction regardless of whether snGrad //- with non-orthogonal correction regardless of whether snGrad
//- is corrected or not //- is corrected or not
virtual tmp<Field<vector> > snGrad() const; virtual tmp<Field<vector> > snGrad() const;
// Member functions // Member functions
@ -380,9 +371,9 @@ public:
<< " is NULL" << exit(FatalError); << " is NULL" << exit(FatalError);
} }
return stickSlipFieldPtr_->boundaryField()[patch().index()]; return stickSlipFieldPtr_->boundaryField()[patch().index()];
} }
//- Write //- Write
virtual void write(Ostream&) const; virtual void write(Ostream&) const;

View file

@ -27,9 +27,10 @@ License
#include "solidTractionFvPatchVectorField.H" #include "solidTractionFvPatchVectorField.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
#include "volFields.H" #include "volFields.H"
#include "rheologyModel.H" //#include "rheologyModel.H"
#include "plasticityModel.H" //#include "plasticityModel.H"
#include "thermalModel.H" //#include "thermalModel.H"
#include "tractionBoundaryGradient.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -81,20 +82,30 @@ solidTractionFvPatchVectorField
//- check if traction boundary is for non linear solver //- check if traction boundary is for non linear solver
if (dict.found("nonLinear")) if (dict.found("nonLinear"))
{ {
nonLinear_ = nonLinearNames_.read(dict.lookup("nonLinear")); nonLinear_ = nonLinearGeometry::nonLinearNames_.read
(
dict.lookup("nonLinear")
);
if (nonLinear_ == UPDATED_LAGRANGIAN) if (nonLinear_ == nonLinearGeometry::UPDATED_LAGRANGIAN)
{ {
Info << "\tnonLinear set to updated Lagrangian" Info << "\tnonLinear set to updated Lagrangian"
<< endl; << endl;
} }
else if (nonLinear_ == TOTAL_LAGRANGIAN) else if (nonLinear_ == nonLinearGeometry::TOTAL_LAGRANGIAN)
{ {
Info << "\tnonLinear set to total Lagrangian" Info << "\tnonLinear set to total Lagrangian"
<< endl; << endl;
} }
} }
if(dict.found("orthotropic"))
{
orthotropic_ = Switch(dict.lookup("orthotropic"));
Info << "\t\torthotropic set to " << orthotropic_ << endl;
}
//- the leastSquares has zero non-orthogonal correction //- the leastSquares has zero non-orthogonal correction
//- on the boundary //- on the boundary
//- so the gradient scheme should be extendedLeastSquares //- so the gradient scheme should be extendedLeastSquares
@ -203,159 +214,15 @@ void solidTractionFvPatchVectorField::updateCoeffs()
return; return;
} }
//---------------------------// gradient() = tractionBoundaryGradient()
//- material properties (
//---------------------------// traction_,
const rheologyModel& rheology = pressure_,
this->db().objectRegistry::lookupObject<rheologyModel> word(fieldName_),
( patch(),
"rheologyProperties" orthotropic_,
); nonLinearGeometry::nonLinearNames_[nonLinear_]
)();
scalarField mu =
rheology.mu()().boundaryField()[patch().index()];
scalarField lambda =
rheology.lambda()().boundaryField()[patch().index()];
if(rheology.type() == plasticityModel::typeName)
{
const plasticityModel& plasticity =
refCast<const plasticityModel>(rheology);
mu = plasticity.newMu().boundaryField()[patch().index()];
lambda = plasticity.newLambda().boundaryField()[patch().index()];
}
//---------------------------//
//- required fields
//---------------------------//
vectorField n = patch().nf();
//- gradient of the field
const fvPatchField<tensor>& gradField =
patch().lookupPatchField<volTensorField, tensor>
(
"grad(" + fieldName_ + ")"
);
//---------------------------//
//- calculate the traction to apply
//---------------------------//
vectorField Traction(n.size(),vector::zero);
//- total Lagrangian small strain
if (fieldName_ == "U" && nonLinear_ == nonLinearGeometry::OFF)
{
//- total traction
Traction = (traction_ - n*pressure_);
}
//- incremental total Lagrangian small strain
else if
(
fieldName_ == "DU"
&& nonLinear_ == nonLinearGeometry::OFF
) //- incremental small strain
{
const fvPatchField<symmTensor>& sigma =
patch().lookupPatchField<volSymmTensorField, symmTensor>("sigma");
//- increment of traction
Traction = (traction_ - n*pressure_) - (n & sigma);
}
//- updated Lagrangian or total Lagrangian large strain
else if
(
nonLinear_ == nonLinearGeometry::UPDATED_LAGRANGIAN
|| nonLinear_ == nonLinearGeometry::TOTAL_LAGRANGIAN
)
{
const fvPatchField<symmTensor>& sigma =
patch().lookupPatchField<volSymmTensorField, symmTensor>("sigma");
tensorField F = I + gradField;
tensorField Finv = inv(F);
scalarField J = det(F);
vectorField nCurrent = Finv & n;
nCurrent /= mag(nCurrent);
vectorField tractionCauchy = traction_ - nCurrent*pressure_;
if (nonLinear_ == nonLinearGeometry::UPDATED_LAGRANGIAN)
{
//- increment of 2nd Piola-Kirchhoff traction
Traction = (mag(J * Finv & n) * tractionCauchy & Finv)
- (n & sigma);
}
else if (nonLinear_ == nonLinearGeometry::TOTAL_LAGRANGIAN)
{
//- total 2nd Piola-Kirchhoff traction
Traction = mag(J * Finv & n) * tractionCauchy & Finv;
}
}
else
{
FatalErrorIn
(
"void solidTractionFvPatchVectorField::updateCoeffs()"
) << "Field " << fieldName_ << " and " << nonLinear_
<< " nonLinear are not compatible!"
<< exit(FatalError);
}
//---------------------------//
//- calculate the normal gradient based on the traction
//---------------------------//
vectorField newGradient =
Traction
- (n & (mu*gradField.T() - (mu + lambda)*gradField))
- n*lambda*tr(gradField);
//- if there is plasticity
if(rheology.type() == plasticityModel::typeName)
{
const plasticityModel& plasticity =
refCast<const plasticityModel>(rheology);
newGradient +=
2*mu*(n & plasticity.DEpsilonP().boundaryField()[patch().index()]);
}
//- if there are thermal effects
if(this->db().objectRegistry::foundObject<thermalModel>("thermalProperties"))
{
const thermalModel& thermo =
this->db().objectRegistry::lookupObject<thermalModel>("thermalProperties");
const fvPatchField<scalar>& T =
patch().lookupPatchField<volScalarField, scalar>("T");
const fvPatchField<scalar>& threeKalpha =
patch().lookupPatchField<volScalarField, scalar>("((threeK*rho)*alpha)");
const scalarField T0 = thermo.T0()().boundaryField()[patch().index()];
newGradient += (n*threeKalpha*(T - T0));
}
//- higher order non-linear terms
if
(
nonLinear_ == nonLinearGeometry::UPDATED_LAGRANGIAN
|| nonLinear_ == nonLinearGeometry::TOTAL_LAGRANGIAN
)
{
newGradient -=
(n & (mu*(gradField & gradField.T())))
+ 0.5*n*lambda*(gradField && gradField);
//- tensorial identity
//- tr(gradField & gradField.T())*I == (gradField && gradField)*I
}
newGradient /= (2.0*mu + lambda);
gradient() = newGradient;
fixedGradientFvPatchVectorField::updateCoeffs(); fixedGradientFvPatchVectorField::updateCoeffs();
} }

View file

@ -27,9 +27,10 @@ License
#include "solidTractionFreeFvPatchVectorField.H" #include "solidTractionFreeFvPatchVectorField.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
#include "volFields.H" #include "volFields.H"
#include "rheologyModel.H" //#include "rheologyModel.H"
#include "plasticityModel.H" //#include "plasticityModel.H"
#include "thermalModel.H" //#include "thermalModel.H"
#include "tractionBoundaryGradient.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -94,6 +95,12 @@ solidTractionFreeFvPatchVectorField
} }
} }
if(dict.found("orthotropic"))
{
orthotropic_ = Switch(dict.lookup("orthotropic"));
Info << "\t\torthotropic set to " << orthotropic_ << endl;
}
//- the leastSquares has zero non-orthogonal correction //- the leastSquares has zero non-orthogonal correction
//- on the boundary //- on the boundary
//- so the gradient scheme should be extendedLeastSquares //- so the gradient scheme should be extendedLeastSquares
@ -188,104 +195,15 @@ void solidTractionFreeFvPatchVectorField::updateCoeffs()
return; return;
} }
//---------------------------// gradient() = tractionBoundaryGradient()
//- material properties (
//---------------------------// vectorField(patch().size(), vector::zero),
const rheologyModel& rheology = scalarField(patch().size(), 0.0),
this->db().objectRegistry::lookupObject<rheologyModel>("rheologyProperties"); word(fieldName_),
scalarField mu = patch(),
rheology.mu()().boundaryField()[patch().index()]; orthotropic_,
scalarField lambda = NamedEnum<Foam::solidTractionFreeFvPatchVectorField::nonLinearType, 3>::names[nonLinear_]
rheology.lambda()().boundaryField()[patch().index()]; )();
if(rheology.type() == plasticityModel::typeName)
{
const plasticityModel& plasticity =
refCast<const plasticityModel>(rheology);
mu = plasticity.newMu().boundaryField()[patch().index()];
lambda = plasticity.newLambda().boundaryField()[patch().index()];
}
//---------------------------//
//- required fields
//---------------------------//
vectorField n = patch().nf();
//- gradient of the field
const fvPatchField<tensor>& gradField =
patch().lookupPatchField<volTensorField, tensor>("grad(" + fieldName_ + ")");
//---------------------------//
//- calculate the traction to apply
//---------------------------//
vectorField Traction(n.size(),vector::zero);
//- incremental solvers
if(fieldName_ == "DU")
{
const fvPatchField<symmTensor>& sigma =
patch().lookupPatchField<volSymmTensorField, symmTensor>("sigma");
//- increment of traction
Traction = - (n & sigma);
}
//---------------------------//
//- calculate the normal gradient based on the traction
//---------------------------//
vectorField newGradient =
Traction
- (n & (mu*gradField.T() - (mu + lambda)*gradField))
- n*lambda*tr(gradField);
//- if there is plasticity
if(rheology.type() == plasticityModel::typeName)
{
const plasticityModel& plasticity =
refCast<const plasticityModel>(rheology);
newGradient +=
2*mu*(n & plasticity.DEpsilonP().boundaryField()[patch().index()]);
}
//- if there are thermal effects
if(this->db().objectRegistry::foundObject<thermalModel>("thermalProperties"))
{
const thermalModel& thermo =
this->db().objectRegistry::lookupObject<thermalModel>("thermalProperties");
const fvPatchField<scalar>& T =
patch().lookupPatchField<volScalarField, scalar>("T");
const fvPatchField<scalar>& threeKalpha =
patch().lookupPatchField<volScalarField, scalar>("((threeK*rho)*alpha)");
const scalarField T0 = thermo.T0()().boundaryField()[patch().index()];
newGradient += (n*threeKalpha*(T - T0));
}
//- higher order non-linear terms
if
(
nonLinear_ == nonLinearGeometry::UPDATED_LAGRANGIAN
|| nonLinear_ == nonLinearGeometry::TOTAL_LAGRANGIAN
)
{
newGradient -=
(n & (mu*(gradField & gradField.T())))
+ 0.5*n*lambda*(gradField && gradField);
//- tensorial identity
//- tr(gradField & gradField.T())*I == (gradField && gradField)*I
}
newGradient /= (2.0*mu + lambda);
gradient() = newGradient;
fixedGradientFvPatchVectorField::updateCoeffs(); fixedGradientFvPatchVectorField::updateCoeffs();
} }

View file

@ -45,7 +45,8 @@ namespace Foam
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
timeVaryingFixedDisplacementZeroShearFvPatchVectorField::timeVaryingFixedDisplacementZeroShearFvPatchVectorField timeVaryingFixedDisplacementZeroShearFvPatchVectorField::
timeVaryingFixedDisplacementZeroShearFvPatchVectorField
( (
const fvPatch& p, const fvPatch& p,
const DimensionedField<vector, volMesh>& iF const DimensionedField<vector, volMesh>& iF
@ -53,13 +54,14 @@ timeVaryingFixedDisplacementZeroShearFvPatchVectorField::timeVaryingFixedDisplac
: :
directionMixedFvPatchVectorField(p, iF), directionMixedFvPatchVectorField(p, iF),
fieldName_("undefined"), fieldName_("undefined"),
nonLinear_(OFF), nonLinear_(nonLinearGeometry::OFF),
orthotropic_(false), orthotropic_(false),
timeSeries_() timeSeries_()
{} {}
timeVaryingFixedDisplacementZeroShearFvPatchVectorField::timeVaryingFixedDisplacementZeroShearFvPatchVectorField timeVaryingFixedDisplacementZeroShearFvPatchVectorField::
timeVaryingFixedDisplacementZeroShearFvPatchVectorField
( (
const timeVaryingFixedDisplacementZeroShearFvPatchVectorField& ptf, const timeVaryingFixedDisplacementZeroShearFvPatchVectorField& ptf,
const fvPatch& p, const fvPatch& p,
@ -75,7 +77,8 @@ timeVaryingFixedDisplacementZeroShearFvPatchVectorField::timeVaryingFixedDisplac
{} {}
timeVaryingFixedDisplacementZeroShearFvPatchVectorField::timeVaryingFixedDisplacementZeroShearFvPatchVectorField timeVaryingFixedDisplacementZeroShearFvPatchVectorField::
timeVaryingFixedDisplacementZeroShearFvPatchVectorField
( (
const fvPatch& p, const fvPatch& p,
const DimensionedField<vector, volMesh>& iF, const DimensionedField<vector, volMesh>& iF,
@ -84,21 +87,24 @@ timeVaryingFixedDisplacementZeroShearFvPatchVectorField::timeVaryingFixedDisplac
: :
directionMixedFvPatchVectorField(p, iF), directionMixedFvPatchVectorField(p, iF),
fieldName_(dimensionedInternalField().name()), fieldName_(dimensionedInternalField().name()),
nonLinear_(OFF), nonLinear_(nonLinearGeometry::OFF),
orthotropic_(false), orthotropic_(false),
timeSeries_(dict) timeSeries_(dict)
{ {
//- check if traction boundary is for non linear solver //- check if traction boundary is for non linear solver
if(dict.found("nonLinear")) if(dict.found("nonLinear"))
{ {
nonLinear_ = nonLinearNames_.read(dict.lookup("nonLinear"));; nonLinear_ = nonLinearGeometry::nonLinearNames_.read
(
dict.lookup("nonLinear")
);
if(nonLinear_ == UPDATED_LAGRANGIAN) if(nonLinear_ == nonLinearGeometry::UPDATED_LAGRANGIAN)
{ {
Info << "\tnonLinear set to updated Lagrangian" Info << "\tnonLinear set to updated Lagrangian"
<< endl; << endl;
} }
else if(nonLinear_ == TOTAL_LAGRANGIAN) else if(nonLinear_ == nonLinearGeometry::TOTAL_LAGRANGIAN)
{ {
Info << "\tnonLinear set to total Lagrangian" Info << "\tnonLinear set to total Lagrangian"
<< endl; << endl;
@ -221,7 +227,7 @@ void timeVaryingFixedDisplacementZeroShearFvPatchVectorField::updateCoeffs()
word(fieldName_), word(fieldName_),
patch(), patch(),
orthotropic_, orthotropic_,
NamedEnum<Foam::timeVaryingFixedDisplacementZeroShearFvPatchVectorField::nonLinearType, 3>::names[nonLinear_] nonLinearGeometry::nonLinearNames_[nonLinear_]
)(); )();
directionMixedFvPatchVectorField::updateCoeffs(); directionMixedFvPatchVectorField::updateCoeffs();
@ -229,28 +235,28 @@ void timeVaryingFixedDisplacementZeroShearFvPatchVectorField::updateCoeffs()
// Write // Write
void timeVaryingFixedDisplacementZeroShearFvPatchVectorField::write(Ostream& os) const void
timeVaryingFixedDisplacementZeroShearFvPatchVectorField::write
(
Ostream& os
) const
{ {
directionMixedFvPatchVectorField::write(os); directionMixedFvPatchVectorField::write(os);
os.writeKeyword("nonLinear") << nonLinearNames_[nonLinear_] << token::END_STATEMENT << nl; os.writeKeyword("nonLinear")
<< nonLinearGeometry::nonLinearNames_[nonLinear_]
<< token::END_STATEMENT << nl;
timeSeries_.write(os); timeSeries_.write(os);
} }
template<>
const char* Foam::NamedEnum<Foam::timeVaryingFixedDisplacementZeroShearFvPatchVectorField::nonLinearType, 3>::names[] =
{
"off",
"updatedLagrangian",
"totalLagrangian"
};
const Foam::NamedEnum<Foam::timeVaryingFixedDisplacementZeroShearFvPatchVectorField::nonLinearType, 3>
Foam::timeVaryingFixedDisplacementZeroShearFvPatchVectorField::nonLinearNames_;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
makePatchTypeField(fvPatchVectorField, timeVaryingFixedDisplacementZeroShearFvPatchVectorField); makePatchTypeField
(
fvPatchVectorField,
timeVaryingFixedDisplacementZeroShearFvPatchVectorField
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View file

@ -55,6 +55,7 @@ Author
#include "fvPatchFields.H" #include "fvPatchFields.H"
#include "directionMixedFvPatchFields.H" #include "directionMixedFvPatchFields.H"
#include "nonLinearGeometry.H"
#include "interpolationTable.H" #include "interpolationTable.H"
#include "Switch.H" #include "Switch.H"
@ -76,20 +77,10 @@ class timeVaryingFixedDisplacementZeroShearFvPatchVectorField
//- Name of the displacement field //- Name of the displacement field
const word fieldName_; const word fieldName_;
//- non-linear solver options //- Is it a non linear solver
enum nonLinearType nonLinearGeometry::nonLinearType nonLinear_;
{
OFF,
UPDATED_LAGRANGIAN,
TOTAL_LAGRANGIAN
};
static const NamedEnum<nonLinearType, 3> nonLinearNames_;
//- if it is a non linear solver //- Is it an orthropic solver
nonLinearType nonLinear_;
//- if it is an orthropic solver
Switch orthotropic_; Switch orthotropic_;
//- The time series being used, including the bounding treatment //- The time series being used, including the bounding treatment

View file

@ -0,0 +1,53 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\*---------------------------------------------------------------------------*/
#include "nonLinearGeometry.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<>
const char*
Foam::NamedEnum<Foam::nonLinearGeometry::nonLinearType, 3>::names[] =
{
"off",
"updatedLagrangian",
"totalLagrangian"
};
const Foam::NamedEnum<Foam::nonLinearGeometry::nonLinearType, 3>
Foam::nonLinearGeometry::nonLinearNames_;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View file

@ -0,0 +1,77 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Class
nonLinearGeometry
Description
Non-linear handling of geometric deformation in simulation
Author
Hrvoje Jasak
SourceFiles
nonLinearGeometry.C
\*---------------------------------------------------------------------------*/
#ifndef nonLinearGeometry_H
#define nonLinearGeometry_H
#include "NamedEnum.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class nonLinearGeometry Declaration
\*---------------------------------------------------------------------------*/
class nonLinearGeometry
{
public:
//- non-linear solver options
enum nonLinearType
{
OFF,
UPDATED_LAGRANGIAN,
TOTAL_LAGRANGIAN
};
static const NamedEnum<nonLinearType, 3> nonLinearNames_;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //