Merge remote-tracking branch 'origin/feature/solidMechanics' into nextRelease
This commit is contained in:
commit
2344c8c728
617 changed files with 777323 additions and 1 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -109,4 +109,12 @@ src/lduSolvers/amg/amgPolicy/samgPolicy.H
|
||||||
src/lduSolvers/amg/amgPolicy/aamgPolicy.C
|
src/lduSolvers/amg/amgPolicy/aamgPolicy.C
|
||||||
src/lduSolvers/amg/amgPolicy/aamgPolicy.H
|
src/lduSolvers/amg/amgPolicy/aamgPolicy.H
|
||||||
|
|
||||||
|
# The following files are blacklisted because of a DMCA complaint by ANSYS.
|
||||||
|
src/lduSolvers/tools/PriorityArray.C
|
||||||
|
src/lduSolvers/tools/PriorityArray.H
|
||||||
|
src/lduSolvers/amg/amgPolicy/samgPolicy.C
|
||||||
|
src/lduSolvers/amg/amgPolicy/samgPolicy.H
|
||||||
|
src/lduSolvers/amg/amgPolicy/aamgPolicy.C
|
||||||
|
src/lduSolvers/amg/amgPolicy/aamgPolicy.H
|
||||||
|
|
||||||
# end-of-file
|
# end-of-file
|
||||||
|
|
20
applications/solvers/solidMechanics/Allwclean
Executable file
20
applications/solvers/solidMechanics/Allwclean
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -x
|
||||||
|
|
||||||
|
wclean solidModels
|
||||||
|
|
||||||
|
wclean elasticContactSolidFoam
|
||||||
|
wclean elasticContactIncrSolidFoam
|
||||||
|
wclean elasticContactNonLinULSolidFoam
|
||||||
|
wclean elasticGravitySolidFoam
|
||||||
|
wclean elasticIncrSolidFoam
|
||||||
|
wclean elasticNonLinTLSolidFoam
|
||||||
|
wclean elasticNonLinULSolidFoam
|
||||||
|
wclean elasticPlasticSolidFoam
|
||||||
|
wclean elasticPlasticNonLinULSolidFoam
|
||||||
|
wclean elasticSolidFoam
|
||||||
|
wclean elasticThermalSolidFoam
|
||||||
|
wclean icoFsiElasticNonLinULSolidFoam
|
||||||
|
wclean viscoElasticSolidFoam
|
||||||
|
|
||||||
|
(cd utilities && ./Allwclean)
|
20
applications/solvers/solidMechanics/Allwmake
Executable file
20
applications/solvers/solidMechanics/Allwmake
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -x
|
||||||
|
|
||||||
|
wmake libso solidModels
|
||||||
|
|
||||||
|
wmake elasticContactSolidFoam
|
||||||
|
wmake elasticContactIncrSolidFoam
|
||||||
|
wmake elasticContactNonLinULSolidFoam
|
||||||
|
wmake elasticGravitySolidFoam
|
||||||
|
wmake elasticIncrSolidFoam
|
||||||
|
wmake elasticNonLinTLSolidFoam
|
||||||
|
wmake elasticNonLinULSolidFoam
|
||||||
|
wmake elasticPlasticNonLinULSolidFoam
|
||||||
|
wmake elasticPlasticSolidFoam
|
||||||
|
wmake elasticSolidFoam
|
||||||
|
wmake elasticThermalSolidFoam
|
||||||
|
wmake icoFsiElasticNonLinULSolidFoam
|
||||||
|
wmake viscoElasticSolidFoam
|
||||||
|
|
||||||
|
(cd utilities && ./Allwmake)
|
|
@ -0,0 +1,3 @@
|
||||||
|
elasticContactIncrSolidFoam.C
|
||||||
|
|
||||||
|
EXE = $(FOAM_USER_APPBIN)/elasticContactIncrSolidFoam
|
|
@ -0,0 +1,14 @@
|
||||||
|
EXE_INC = \
|
||||||
|
-I$(FOAM_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/meshTools/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/lagrangian/basic/lnInclude \
|
||||||
|
-I../solidModels/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/VectorN/lnInclude
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) -lsolidModels \
|
||||||
|
-lfiniteVolume \
|
||||||
|
-llduSolvers \
|
||||||
|
-lmeshTools \
|
||||||
|
-llagrangian \
|
||||||
|
-lVectorN
|
|
@ -0,0 +1,15 @@
|
||||||
|
EXE_INC = \
|
||||||
|
// -I../../../myLibraries/finiteVolume/lnInclude \
|
||||||
|
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||||
|
-I../materialModels/lnInclude \
|
||||||
|
-I./solidInterface
|
||||||
|
// -I./patchToPatchInterpolation
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) \
|
||||||
|
// -lfiniteVolume_philipc \
|
||||||
|
// -lfiniteVolume \
|
||||||
|
-lmaterialModels_philipc \
|
||||||
|
-llduSolvers \
|
||||||
|
-lmeshTools
|
|
@ -0,0 +1,9 @@
|
||||||
|
EXE_INC = \
|
||||||
|
-I$(FOAM_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/dynamicMesh/lnInclude \
|
||||||
|
-I../materialModels/lnInclude
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) \
|
||||||
|
-lfiniteVolume \
|
||||||
|
-lmaterialModels_philipc
|
|
@ -0,0 +1,3 @@
|
||||||
|
DEpsilon = symm(gradDU);
|
||||||
|
|
||||||
|
DSigma = 2*mu*DEpsilon + lambda*(I*tr(DEpsilon));
|
|
@ -0,0 +1,47 @@
|
||||||
|
if(divDSigmaExpMethod == "standard")
|
||||||
|
{
|
||||||
|
divDSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
mu*gradDU.T() + lambda*(I*tr(gradDU)) - (mu + lambda)*gradDU,
|
||||||
|
"div(sigma)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divDSigmaExpMethod == "surface")
|
||||||
|
{
|
||||||
|
divDSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
muf*(mesh.Sf() & fvc::interpolate(gradDU.T()))
|
||||||
|
+ lambdaf*(mesh.Sf() & I*fvc::interpolate(tr(gradDU)))
|
||||||
|
- (muf + lambdaf)*(mesh.Sf() & fvc::interpolate(gradDU))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divDSigmaExpMethod == "decompose")
|
||||||
|
{
|
||||||
|
surfaceTensorField shearGradDU =
|
||||||
|
((I - n*n)&fvc::interpolate(gradDU));
|
||||||
|
|
||||||
|
divDSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
mesh.magSf()
|
||||||
|
*(
|
||||||
|
- (muf + lambdaf)*(fvc::snGrad(DU)&(I - n*n))
|
||||||
|
+ lambdaf*tr(shearGradDU&(I - n*n))*n
|
||||||
|
+ muf*(shearGradDU&n)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divDSigmaExpMethod == "laplacian")
|
||||||
|
{
|
||||||
|
divDSigmaExp =
|
||||||
|
- fvc::laplacian(mu + lambda, DU, "laplacian(DDU,DU)")
|
||||||
|
+ fvc::div
|
||||||
|
(
|
||||||
|
mu*gradDU.T()
|
||||||
|
+ lambda*(I*tr(gradDU)),
|
||||||
|
"div(sigma)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalError << "divDSigmaExp method " << divDSigmaExpMethod << " not found!" << endl;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
scalarField magDU = mag(DU.internalField());
|
||||||
|
|
||||||
|
forAll(magDU, cellI)
|
||||||
|
{
|
||||||
|
if (magDU[cellI] < SMALL)
|
||||||
|
{
|
||||||
|
magDU[cellI] = SMALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relativeResidual =
|
||||||
|
gMax
|
||||||
|
(
|
||||||
|
mag
|
||||||
|
(
|
||||||
|
DU.internalField()
|
||||||
|
- DU.prevIter().internalField()
|
||||||
|
)
|
||||||
|
/magDU
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
correctGlobalFaceZoneMesh.H
|
||||||
|
|
||||||
|
When there is a globalFaceZone and the mesh is moved by interpolating U to the
|
||||||
|
vertices with volPointInterpolation, then there are two problems:
|
||||||
|
-some points on the patch with the faceZone are moved incorrectly, I think
|
||||||
|
it is because the faceZone has no U and causes an incorrect interpolation,
|
||||||
|
-the faceZones points not on the proc cells are not moved at all because
|
||||||
|
they have no U.
|
||||||
|
|
||||||
|
So the points on the patch with the faceZone need to be fixed and also all the
|
||||||
|
faceZone points need to be moved and synchronised so each proc has the same
|
||||||
|
full faceZone mesh.
|
||||||
|
|
||||||
|
The mapping of procs faceZone order of points to the master procs faceZone point
|
||||||
|
order is kept in procToGlobalFZmap, which is calculated at the start of the run
|
||||||
|
in the createGlobalToLocalFaceZonePointMap.H header file.
|
||||||
|
|
||||||
|
Note: DU is used for updated Lagrangian solver instead of U
|
||||||
|
|
||||||
|
philipc
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//- this is only needed in a parallel runs
|
||||||
|
if(Pstream::parRun())
|
||||||
|
{
|
||||||
|
//***** FIX INCORRECT POINT ON PATCHES WITH FACEZONE *****//
|
||||||
|
contactPatchPairList& contacts = contact;
|
||||||
|
|
||||||
|
forAll(contacts, contactI)
|
||||||
|
{
|
||||||
|
label masterID = contacts[contactI].masterPatch().index();
|
||||||
|
label slaveID = contacts[contactI].slavePatch().index();
|
||||||
|
|
||||||
|
primitivePatchInterpolation masterInterpolator
|
||||||
|
(mesh.boundaryMesh()[masterID]);
|
||||||
|
primitivePatchInterpolation slaveInterpolator
|
||||||
|
(mesh.boundaryMesh()[slaveID]);
|
||||||
|
|
||||||
|
//- U must be interpolated to the vertices, this ignores the faceZone
|
||||||
|
//- points with no U (unlike volPointInterpolation)
|
||||||
|
vectorField correctMasterPointU =
|
||||||
|
masterInterpolator.faceToPointInterpolate<vector>
|
||||||
|
(
|
||||||
|
U.boundaryField()[masterID]
|
||||||
|
);
|
||||||
|
vectorField correctSlavePointU =
|
||||||
|
slaveInterpolator.faceToPointInterpolate<vector>
|
||||||
|
(
|
||||||
|
U.boundaryField()[slaveID]
|
||||||
|
);
|
||||||
|
|
||||||
|
vectorField oldMasterPoints =
|
||||||
|
mesh.boundaryMesh()[masterID].localPoints();
|
||||||
|
vectorField oldSlavePoints =
|
||||||
|
mesh.boundaryMesh()[slaveID].localPoints();
|
||||||
|
|
||||||
|
labelList masterPointLabels =
|
||||||
|
mesh.boundaryMesh()[masterID].meshPoints();
|
||||||
|
labelList slavePointLabels =
|
||||||
|
mesh.boundaryMesh()[slaveID].meshPoints();
|
||||||
|
|
||||||
|
//- correct the patch newPoints
|
||||||
|
forAll(masterPointLabels, pointI)
|
||||||
|
{
|
||||||
|
label pointGlobalLabel = masterPointLabels[pointI];
|
||||||
|
newPoints[pointGlobalLabel] =
|
||||||
|
oldMasterPoints[pointI]
|
||||||
|
+
|
||||||
|
correctMasterPointU[pointI];
|
||||||
|
}
|
||||||
|
forAll(slavePointLabels, pointI)
|
||||||
|
{
|
||||||
|
label pointGlobalLabel = slavePointLabels[pointI];
|
||||||
|
newPoints[pointGlobalLabel] =
|
||||||
|
oldSlavePoints[pointI]
|
||||||
|
+
|
||||||
|
correctSlavePointU[pointI];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//***** NOW FIX AND SYNCHRONISE ALL THE FACEZONE POINTS *****//
|
||||||
|
|
||||||
|
forAll(mesh.faceZones(), faceZoneI)
|
||||||
|
{
|
||||||
|
//- find the patch corresponding to this faceZone
|
||||||
|
//- assuming that the FZ is called <patch_name>FaceZone
|
||||||
|
string faceZoneName = mesh.faceZones().names()[faceZoneI];
|
||||||
|
//- remove the string FaceZone from the end of the face zone name to get the patch name
|
||||||
|
string patchName = faceZoneName.substr(0, (faceZoneName.size()-8));
|
||||||
|
label patchID = mesh.boundaryMesh().findPatchID(patchName);
|
||||||
|
if(patchID == -1)
|
||||||
|
{
|
||||||
|
FatalError << "Patch " << patchName << " not found corresponding for faceZone"
|
||||||
|
<< faceZoneName << exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
vectorField globalFZpoints =
|
||||||
|
mesh.faceZones()[faceZoneI]().localPoints();
|
||||||
|
|
||||||
|
//- new points for the face zone
|
||||||
|
vectorField globalFZnewPoints(globalFZpoints.size(), vector::zero);
|
||||||
|
|
||||||
|
//- inter-proc points are shared by multiple procs
|
||||||
|
//- pointNumProc is the number of procs which a point lies on
|
||||||
|
scalarField pointNumProcs(globalFZpoints.size(), 0.0);
|
||||||
|
|
||||||
|
forAll(globalFZnewPoints, globalPointI)
|
||||||
|
{
|
||||||
|
label localPoint = procToGlobalFZmap[faceZoneI][globalPointI];
|
||||||
|
|
||||||
|
//if(localPoint < mesh.boundaryMesh()[patchID].localPoints().size())
|
||||||
|
if(pointOnLocalProcPatch[faceZoneI][localPoint])
|
||||||
|
{
|
||||||
|
label procPoint =
|
||||||
|
mesh.faceZones()[faceZoneI]().meshPoints()[localPoint];
|
||||||
|
globalFZnewPoints[globalPointI] =
|
||||||
|
newPoints[procPoint];
|
||||||
|
pointNumProcs[globalPointI] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce(globalFZnewPoints, sumOp<vectorField>());
|
||||||
|
reduce(pointNumProcs, sumOp<scalarField>());
|
||||||
|
|
||||||
|
//- now average the newPoints between all procs
|
||||||
|
if(min(pointNumProcs) < 1)
|
||||||
|
{
|
||||||
|
FatalError << "pointNumProc has not been set for all points" << exit(FatalError);
|
||||||
|
}
|
||||||
|
globalFZnewPoints /= pointNumProcs;
|
||||||
|
|
||||||
|
//- the globalFZnewPoints now contains the correct FZ new points in
|
||||||
|
//- a global order, now convert them back into the local proc order
|
||||||
|
|
||||||
|
vectorField procFZnewPoints(globalFZpoints.size(), vector::zero);
|
||||||
|
|
||||||
|
forAll(globalFZnewPoints, globalPointI)
|
||||||
|
{
|
||||||
|
label localPoint = procToGlobalFZmap[faceZoneI][globalPointI];
|
||||||
|
|
||||||
|
procFZnewPoints[localPoint] =
|
||||||
|
globalFZnewPoints[globalPointI];
|
||||||
|
}
|
||||||
|
|
||||||
|
//- now fix the newPoints points on the globalFaceZones
|
||||||
|
labelList procFZmeshPoints =
|
||||||
|
mesh.faceZones()[faceZoneI]().meshPoints();
|
||||||
|
|
||||||
|
forAll(procFZmeshPoints, pointI)
|
||||||
|
{
|
||||||
|
label procPoint = procFZmeshPoints[pointI];
|
||||||
|
newPoints[procPoint] =
|
||||||
|
procFZnewPoints[pointI];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
Info<< "Reading field DU\n" << endl;
|
||||||
|
volVectorField DU
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"DU",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::MUST_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh
|
||||||
|
);
|
||||||
|
|
||||||
|
volTensorField gradDU = fvc::grad(DU);
|
||||||
|
|
||||||
|
volVectorField U
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"U",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedVector("zero", dimLength, vector::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField DEpsilon
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"DEpsilon",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimless, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField epsilon
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"epsilon",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimless, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField DSigma
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"DSigma",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimForce/dimArea, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField sigma
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"sigma",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimForce/dimArea, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volVectorField divDSigmaExp
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"divDSigmaExp",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedVector("zero", dimensionSet(1,-2,-2,0,0,0,0), vector::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// read rheology properties
|
||||||
|
rheologyModel rheology(sigma);
|
||||||
|
|
||||||
|
volScalarField rho = rheology.rho();
|
||||||
|
|
||||||
|
volScalarField mu = rheology.mu();
|
||||||
|
volScalarField lambda = rheology.lambda();
|
||||||
|
surfaceScalarField muf = fvc::interpolate(mu, "mu");
|
||||||
|
surfaceScalarField lambdaf = fvc::interpolate(lambda, "lambda");
|
||||||
|
|
||||||
|
surfaceVectorField n = mesh.Sf()/mesh.magSf();
|
||||||
|
|
||||||
|
//- create contact problem
|
||||||
|
contactProblem contact(DU);
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
createGlobalToLocalFaceZonePointMap.H
|
||||||
|
|
||||||
|
I could not figure out the order of the points on a globalFaceZone, they is a
|
||||||
|
different order for each processor where the processors own points come first.
|
||||||
|
|
||||||
|
So I decide that the master proc order is the global order and I find the map
|
||||||
|
from this order to each proc order here by just commparing actual point
|
||||||
|
coordinates.
|
||||||
|
|
||||||
|
This map is then used to correct and synchronise the globalFaceZone points on
|
||||||
|
all the procs when the mesh is moved, in header file correctGlobalFaceZoneMesh.H.
|
||||||
|
|
||||||
|
philipc
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//- procToGlobalFZmap is a map from the current proc faceZone point order to the
|
||||||
|
//- master proc point order
|
||||||
|
//- these are read if present to allow restarting of contact cases
|
||||||
|
IOList<labelList> procToGlobalFZmap
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"procToGlobalFZmap",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh.faceZones().size()
|
||||||
|
);
|
||||||
|
|
||||||
|
IOList<labelList> pointOnLocalProcPatch
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointOnLocalProcPatch",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh.faceZones().size()
|
||||||
|
);
|
||||||
|
|
||||||
|
//- if they have been read then don't recalculate it
|
||||||
|
bool globalFaceZoneMappingSet = false;
|
||||||
|
if(gMax(procToGlobalFZmap[0]) > 0 && gMax(pointOnLocalProcPatch[0]) > 0)
|
||||||
|
{
|
||||||
|
Info << "Reading procToGlobalFZmap and pointOnLocalProcPatch allowing restart of contact cases"
|
||||||
|
<< endl;
|
||||||
|
globalFaceZoneMappingSet = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info << "procToGlobalFZmap and pointOnLocalProcPatch will be calculated as it has not been found" << nl
|
||||||
|
<< "this message should only appear starting a new analysis" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- this is only needed in a parallel runs
|
||||||
|
if(Pstream::parRun())
|
||||||
|
{
|
||||||
|
if(!globalFaceZoneMappingSet)
|
||||||
|
{
|
||||||
|
forAll(mesh.faceZones(), faceZoneI)
|
||||||
|
{
|
||||||
|
vectorField globalFZpoints = mesh.faceZones()[faceZoneI]().localPoints();
|
||||||
|
|
||||||
|
procToGlobalFZmap[faceZoneI].setSize(globalFZpoints.size(), 0);
|
||||||
|
|
||||||
|
//- set all slave points to zero because only the master order is used
|
||||||
|
if(!Pstream::master())
|
||||||
|
globalFZpoints *= 0.0;
|
||||||
|
|
||||||
|
//- pass points to all procs
|
||||||
|
reduce(globalFZpoints, sumOp<vectorField>());
|
||||||
|
|
||||||
|
|
||||||
|
//- now every proc has the master's list of FZ points
|
||||||
|
//- every proc must now find the mapping from their local FZpoints to
|
||||||
|
//- the globalFZpoints
|
||||||
|
|
||||||
|
vectorField procFZpoints = mesh.faceZones()[faceZoneI]().localPoints();
|
||||||
|
|
||||||
|
forAll(globalFZpoints, globalPointI)
|
||||||
|
{
|
||||||
|
forAll(procFZpoints, procPointI)
|
||||||
|
{
|
||||||
|
if(procFZpoints[procPointI] == globalFZpoints[globalPointI])
|
||||||
|
{
|
||||||
|
procToGlobalFZmap[faceZoneI][globalPointI] = procPointI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//- procToGlobalFZmap now contains the local FZpoint label for each
|
||||||
|
//- global FZ point label - for each faceZone
|
||||||
|
|
||||||
|
//- check what points are on the current proc patch
|
||||||
|
pointOnLocalProcPatch[faceZoneI].setSize(globalFZpoints.size(), 0);
|
||||||
|
|
||||||
|
//- find corresponding patch
|
||||||
|
string faceZoneName = mesh.faceZones().names()[faceZoneI];
|
||||||
|
//- remove the string FaceZone from the end of the face zone name to get the patch name
|
||||||
|
string patchName = faceZoneName.substr(0, (faceZoneName.size()-8));
|
||||||
|
label patchID = mesh.boundaryMesh().findPatchID(patchName);
|
||||||
|
if(patchID == -1)
|
||||||
|
{
|
||||||
|
FatalError << "Patch " << patchName << " not found corresponding for faceZone"
|
||||||
|
<< faceZoneName << exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
forAll(mesh.faceZones()[faceZoneI]().localPoints(), fzpi)
|
||||||
|
{
|
||||||
|
forAll(mesh.boundaryMesh()[patchID].localPoints(), pi)
|
||||||
|
{
|
||||||
|
if(mesh.faceZones()[faceZoneI]().localPoints()[fzpi] == mesh.boundaryMesh()[patchID].localPoints()[pi])
|
||||||
|
{
|
||||||
|
pointOnLocalProcPatch[faceZoneI][fzpi] = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} //- end if(!globalFaceZoneMappingSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
//- write to disk to allow restart of cases
|
||||||
|
//- because it is not possible to calculate the
|
||||||
|
//- mapping after the meshes have moved
|
||||||
|
if(!globalFaceZoneMappingSet && Pstream::parRun())
|
||||||
|
{
|
||||||
|
procToGlobalFZmap.write();
|
||||||
|
pointOnLocalProcPatch.write();
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
Switch solidInterfaceCorr(false);
|
||||||
|
|
||||||
|
solidInterface* solidInterfacePtr(NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
const dictionary& stressControl =
|
||||||
|
mesh.solutionDict().subDict("stressedFoam");
|
||||||
|
|
||||||
|
solidInterfaceCorr = Switch(stressControl.lookup("solidInterface"));
|
||||||
|
|
||||||
|
if(solidInterfaceCorr)
|
||||||
|
{
|
||||||
|
Info << "Creating solid interface correction" << endl;
|
||||||
|
solidInterfacePtr = new solidInterface(mesh, rheology);
|
||||||
|
solidInterfacePtr->modifyProperties(muf, lambdaf);
|
||||||
|
gradDU = solidInterfacePtr->grad(DU);
|
||||||
|
|
||||||
|
//- solidInterface needs muf and lambdaf to be used for divSigmaExp
|
||||||
|
if(divDSigmaExpMethod != "surface" && divDSigmaExpMethod != "decompose")
|
||||||
|
{
|
||||||
|
FatalError << "divDSigmaExp must be decompose or surface when solidInterface is on"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2004-2007 Hrvoje Jasak
|
||||||
|
\\/ 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
|
||||||
|
|
||||||
|
Application
|
||||||
|
elasticContactIncrSolidFoam
|
||||||
|
|
||||||
|
Description
|
||||||
|
Transient/steady-state segregated finite-volume solver for small strain
|
||||||
|
elastic solid bodies in contact, using an incremental total Lagrangian
|
||||||
|
approach.
|
||||||
|
Works in parallel.
|
||||||
|
|
||||||
|
Solves for the displacement increment vector field DU, also generating the
|
||||||
|
stress tensor field sigma.
|
||||||
|
|
||||||
|
It is only for frictionless contact, friction not implemented yet.
|
||||||
|
|
||||||
|
Author
|
||||||
|
Philip Cardiff
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "fvCFD.H"
|
||||||
|
#include "rheologyModel.H"
|
||||||
|
#include "contactProblem.H"
|
||||||
|
#include "solidInterface.H"
|
||||||
|
|
||||||
|
#include "volPointInterpolation.H"
|
||||||
|
#include "pointPatchInterpolation.H"
|
||||||
|
#include "primitivePatchInterpolation.H"
|
||||||
|
#include "fixedValuePointPatchFields.H"
|
||||||
|
#include "pointFields.H"
|
||||||
|
#include "pointMesh.H"
|
||||||
|
#include "pointBoundaryMesh.H"
|
||||||
|
#include "primitivePatchInterpolation.H"
|
||||||
|
#include "twoDPointCorrector.H"
|
||||||
|
//#include "leastSquaresVolPointInterpolation.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
# include "setRootCase.H"
|
||||||
|
|
||||||
|
# include "createTime.H"
|
||||||
|
|
||||||
|
# include "createMesh.H"
|
||||||
|
|
||||||
|
# include "createFields.H"
|
||||||
|
|
||||||
|
# include "readDivDSigmaExpMethod.H"
|
||||||
|
|
||||||
|
# include "createGlobalToLocalFaceZonePointMap.H"
|
||||||
|
|
||||||
|
# include "createSolidInterface.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Info<< "\nStarting time loop\n" << endl;
|
||||||
|
|
||||||
|
for (runTime++; !runTime.end(); runTime++)
|
||||||
|
{
|
||||||
|
Info<< "Time: " << runTime.timeName() << endl;
|
||||||
|
|
||||||
|
# include "readContactControls.H"
|
||||||
|
|
||||||
|
# include "readStressedFoamControls.H"
|
||||||
|
|
||||||
|
//-- for moving the mesh and then back again
|
||||||
|
vectorField oldMeshPoints = mesh.allPoints();
|
||||||
|
|
||||||
|
int iCorr = 0;
|
||||||
|
lduMatrix::solverPerformance solverPerf;
|
||||||
|
word solverName;
|
||||||
|
lduMatrix::debug = 0;
|
||||||
|
scalar residual = GREAT;
|
||||||
|
scalar initialResidual = 0;
|
||||||
|
scalar relativeResidual = GREAT;
|
||||||
|
|
||||||
|
//- reset DU to zero at the start of the time-step if
|
||||||
|
//- a predictor is not required
|
||||||
|
if(!predictor)
|
||||||
|
DU = dimensionedVector("zero", dimLength, vector::zero);
|
||||||
|
|
||||||
|
do //- start of momentum loop
|
||||||
|
{
|
||||||
|
DU.storePrevIter();
|
||||||
|
|
||||||
|
//- correct the contact boundaries
|
||||||
|
if(iCorr % uEqnContactCorrFreq == 0)
|
||||||
|
{
|
||||||
|
Info << "\t\tCorrecting contact in the momentum loop "
|
||||||
|
<< "iteration: " << iCorr
|
||||||
|
<< ", residual: " << residual
|
||||||
|
<< endl;
|
||||||
|
//# include "moveMeshLeastSquares.H"
|
||||||
|
# include "moveSolidMesh.H"
|
||||||
|
contact.correct();
|
||||||
|
mesh.movePoints(oldMeshPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
# include "calculateDivDSigmaExp.H"
|
||||||
|
|
||||||
|
fvVectorMatrix DUEqn
|
||||||
|
(
|
||||||
|
fvm::d2dt2(rho, DU)
|
||||||
|
==
|
||||||
|
fvm::laplacian(2*mu + lambda, DU, "laplacian(DDU,DU)")
|
||||||
|
+ divDSigmaExp
|
||||||
|
);
|
||||||
|
|
||||||
|
if(solidInterfaceCorr)
|
||||||
|
{
|
||||||
|
solidInterfacePtr->correct(DUEqn);
|
||||||
|
}
|
||||||
|
|
||||||
|
solverPerf = DUEqn.solve();
|
||||||
|
|
||||||
|
DU.relax();
|
||||||
|
|
||||||
|
solverName = solverPerf.solverName();
|
||||||
|
|
||||||
|
if(solidInterfaceCorr)
|
||||||
|
{
|
||||||
|
gradDU = solidInterfacePtr->grad(DU);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gradDU = fvc::grad(DU);
|
||||||
|
}
|
||||||
|
|
||||||
|
U = U.oldTime() + DU;
|
||||||
|
|
||||||
|
residual = solverPerf.initialResidual();
|
||||||
|
|
||||||
|
//****************************************************//
|
||||||
|
// The contact residual is the initial residual for the
|
||||||
|
// first iteration of the momentum equation
|
||||||
|
//****************************************************//
|
||||||
|
if(iCorr == 0)
|
||||||
|
{
|
||||||
|
initialResidual = solverPerf.initialResidual();
|
||||||
|
}
|
||||||
|
|
||||||
|
# include "calculateRelativeResidual.H"
|
||||||
|
|
||||||
|
Info << "\tTime " << runTime.value()
|
||||||
|
<< ", Corrector " << iCorr
|
||||||
|
<< ", Solving for " << DU.name()
|
||||||
|
<< " using " << solverPerf.solverName()
|
||||||
|
<< ", residual = " << solverPerf.initialResidual()
|
||||||
|
<< ", relative residual = " << relativeResidual << endl;
|
||||||
|
} //- end of momentum loop
|
||||||
|
while
|
||||||
|
(
|
||||||
|
relativeResidual > convergenceTolerance
|
||||||
|
//residual > convergenceTolerance
|
||||||
|
&&
|
||||||
|
++iCorr < nCorr
|
||||||
|
);
|
||||||
|
|
||||||
|
// Print out info per contact iteration
|
||||||
|
Info << "\t\tSolving for " << DU.name()
|
||||||
|
<< " using " << solverName
|
||||||
|
<< ", Initial residual = " << initialResidual
|
||||||
|
<< ", Final residual = " << solverPerf.initialResidual()
|
||||||
|
<< ", No outer iterations " << iCorr << endl;
|
||||||
|
|
||||||
|
lduMatrix::debug = 1;
|
||||||
|
|
||||||
|
# include "calculateDEpsilonDSigma.H"
|
||||||
|
|
||||||
|
epsilon += DEpsilon;
|
||||||
|
|
||||||
|
sigma += DSigma;
|
||||||
|
|
||||||
|
# include "writeFields.H"
|
||||||
|
|
||||||
|
//# include "writeBoundaryNetForces.H"
|
||||||
|
|
||||||
|
//# include "moveMeshLeastSquares.H"
|
||||||
|
//# include "moveSolidMesh.H"
|
||||||
|
//# include "printContactResults.H"
|
||||||
|
//mesh.movePoints(oldMeshPoints);
|
||||||
|
|
||||||
|
Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
|
||||||
|
<< " ClockTime = " << runTime.elapsedClockTime() << " s"
|
||||||
|
<< endl << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< "End\n" << endl;
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
|
@ -0,0 +1,56 @@
|
||||||
|
//--------------------------------------------------//
|
||||||
|
//- move mesh
|
||||||
|
//--------------------------------------------------//
|
||||||
|
if(min(J.internalField()) > 0)
|
||||||
|
{
|
||||||
|
Info << "Moving mesh using least squares interpolation" << endl;
|
||||||
|
|
||||||
|
leastSquaresVolPointInterpolation pointInterpolation(mesh);
|
||||||
|
|
||||||
|
// Create point mesh
|
||||||
|
pointMesh pMesh(mesh);
|
||||||
|
|
||||||
|
wordList types
|
||||||
|
(
|
||||||
|
pMesh.boundary().size(),
|
||||||
|
calculatedFvPatchVectorField::typeName
|
||||||
|
);
|
||||||
|
|
||||||
|
pointVectorField pointDU
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointDU",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedVector("zero", dimLength, vector::zero),
|
||||||
|
types
|
||||||
|
);
|
||||||
|
|
||||||
|
pointInterpolation.interpolate(DU, pointDU);
|
||||||
|
|
||||||
|
const vectorField& pointDUI =
|
||||||
|
pointDU.internalField();
|
||||||
|
|
||||||
|
//- Move mesh
|
||||||
|
vectorField newPoints = mesh.allPoints();
|
||||||
|
|
||||||
|
forAll (pointDUI, pointI)
|
||||||
|
{
|
||||||
|
newPoints[pointI] += pointDUI[pointI];
|
||||||
|
}
|
||||||
|
|
||||||
|
twoDPointCorrector twoDCorrector(mesh);
|
||||||
|
twoDCorrector.correctPoints(newPoints);
|
||||||
|
mesh.movePoints(newPoints);
|
||||||
|
mesh.V00();
|
||||||
|
mesh.moving(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalErrorIn(args.executable())
|
||||||
|
<< "Negative Jacobian"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
//- move mesh for the contact correction
|
||||||
|
|
||||||
|
// Create point interpolation
|
||||||
|
volPointInterpolation pointInterpolation(mesh);
|
||||||
|
|
||||||
|
// Calculate mesh points displacement
|
||||||
|
pointVectorField pointU = pointInterpolation.interpolate(U);
|
||||||
|
|
||||||
|
const vectorField& pointUI = pointU.internalField();
|
||||||
|
|
||||||
|
// Move mesh
|
||||||
|
vectorField newPoints = mesh.allPoints();
|
||||||
|
|
||||||
|
forAll (pointUI, pointI)
|
||||||
|
{
|
||||||
|
newPoints[pointI] += pointUI[pointI];
|
||||||
|
}
|
||||||
|
|
||||||
|
# include "correctGlobalFaceZoneMesh.H"
|
||||||
|
|
||||||
|
twoDPointCorrector twoDCorrector(mesh);
|
||||||
|
twoDCorrector.correctPoints(newPoints);
|
||||||
|
|
||||||
|
mesh.movePoints(newPoints);
|
||||||
|
mesh.V00();
|
||||||
|
mesh.moving(false);
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
if (runTime.outputTime())
|
||||||
|
{
|
||||||
|
// FAILS IN PARALLEL - FIX
|
||||||
|
// Info << "Print contact area" << endl;
|
||||||
|
//volScalarField ca = contact.contactArea();
|
||||||
|
//ca.write();
|
||||||
|
|
||||||
|
//-------------------------------------------------------------//
|
||||||
|
// I couldn't get tmp to return the pointScalarField correctly //
|
||||||
|
// so I had to make the pointScalarField here and pass it to //
|
||||||
|
// contactGapPoints and pointContactForce to populate //
|
||||||
|
//-------------------------------------------------------------//
|
||||||
|
//This is the point distance for each contact vertex
|
||||||
|
pointScalarField cGapPoints
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointContactGap",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedScalar("scalar", dimLength, 0.0),
|
||||||
|
"calculated"
|
||||||
|
);
|
||||||
|
|
||||||
|
contact.contactGapPoints(cGapPoints);
|
||||||
|
cGapPoints.write();
|
||||||
|
|
||||||
|
|
||||||
|
//- This is the point distance for each contact vertex
|
||||||
|
pointVectorField cPointForce
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointContactForce",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedVector("vector", dimForce, vector::zero),
|
||||||
|
"calculated"
|
||||||
|
);
|
||||||
|
contact.contactPointForce(cPointForce);
|
||||||
|
cPointForce.write();
|
||||||
|
|
||||||
|
//- this is the actual (sigma&n)&n) on the contact patches
|
||||||
|
//- SHOULD THIS BE A REF TO A TMP...?
|
||||||
|
volScalarField cPressure = contact.contactPressure();
|
||||||
|
cPressure.write();
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
//****************************************************//
|
||||||
|
// Read the contact tol and max contact correctors
|
||||||
|
//****************************************************//
|
||||||
|
const IOdictionary& contactControl =
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"contactProperties",
|
||||||
|
U.time().constant(),
|
||||||
|
U.db(),
|
||||||
|
IOobject::MUST_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//- The frequnecy the conatct is corrected inside the momentum loop
|
||||||
|
int uEqnContactCorrFreq(readInt(contactControl.lookup("innerContactCorrectFreq")));
|
|
@ -0,0 +1,9 @@
|
||||||
|
//- how explicit component of sigma is to be calculated
|
||||||
|
word divDSigmaExpMethod(mesh.solutionDict().subDict("stressedFoam").lookup("divDSigmaExp"));
|
||||||
|
Info << divDSigmaExpMethod << " method chosen for calculation of sigmaExp" << endl;
|
||||||
|
if(divDSigmaExpMethod != "standard" && divDSigmaExpMethod != "surface" && divDSigmaExpMethod != "decompose" && divDSigmaExpMethod != "laplacian")
|
||||||
|
{
|
||||||
|
FatalError << "divDSigmaExp method " << divDSigmaExpMethod << " not found!" << nl
|
||||||
|
<< "valid methods are:\nstandard\nsurface\ndecompose\nlaplacian"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
const dictionary& stressControl =
|
||||||
|
mesh.solutionDict().subDict("stressedFoam");
|
||||||
|
|
||||||
|
int nCorr(readInt(stressControl.lookup("nCorrectors")));
|
||||||
|
scalar convergenceTolerance(readScalar(stressControl.lookup("DU")));
|
||||||
|
|
||||||
|
Switch predictor(stressControl.lookup("predictor"));
|
|
@ -0,0 +1,14 @@
|
||||||
|
// * * * * * * * * * * * * * * * * NET FORCES * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
vectorField netForces(mesh.boundary().size(), vector::zero);
|
||||||
|
|
||||||
|
Info << nl;
|
||||||
|
forAll(netForces, patchI)
|
||||||
|
{
|
||||||
|
netForces[patchI] = gSum(mesh.Sf().boundaryField()[patchI] & sigma.boundaryField()[patchI]);
|
||||||
|
|
||||||
|
Info << "patch\t" << mesh.boundary()[patchI].name() << "\t\tnet force is\t"
|
||||||
|
<< netForces[patchI] << " N" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
@ -0,0 +1,77 @@
|
||||||
|
if (runTime.outputTime())
|
||||||
|
{
|
||||||
|
volScalarField epsilonEq
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"epsilonEq",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
sqrt((2.0/3.0)*magSqr(dev(epsilon)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< "Max epsilonEq = " << max(epsilonEq).value()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
volScalarField sigmaEq
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"sigmaEq",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
sqrt((3.0/2.0)*magSqr(dev(sigma)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< "Max sigmaEq = " << max(sigmaEq).value()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
volScalarField pressure
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pressure",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
tr(sigma)/3.0
|
||||||
|
);
|
||||||
|
//- boundary surface pressure
|
||||||
|
forAll(pressure.boundaryField(), patchi)
|
||||||
|
{
|
||||||
|
const vectorField& nb = n.boundaryField()[patchi];
|
||||||
|
pressure.boundaryField()[patchi] =
|
||||||
|
-(nb & ( nb & sigma.boundaryField()[patchi] ));
|
||||||
|
}
|
||||||
|
|
||||||
|
//- contact slave penetration
|
||||||
|
# include "moveSolidMesh.H"
|
||||||
|
pointMesh pMesh(mesh);
|
||||||
|
pointScalarField cGapPoints
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointContactGap",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedScalar("scalar", dimLength, 0.0),
|
||||||
|
"calculated"
|
||||||
|
);
|
||||||
|
contact.contactGapPoints(cGapPoints);
|
||||||
|
cGapPoints.write();
|
||||||
|
mesh.movePoints(oldMeshPoints);
|
||||||
|
|
||||||
|
runTime.write();
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
elasticContactNonLinULSolidFoam.C
|
||||||
|
|
||||||
|
EXE = $(FOAM_USER_APPBIN)/elasticContactNonLinULSolidFoam
|
|
@ -0,0 +1,14 @@
|
||||||
|
EXE_INC = \
|
||||||
|
-I$(FOAM_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/meshTools/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/lagrangian/basic/lnInclude \
|
||||||
|
-I../solidModels/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/VectorN/lnInclude
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) -lsolidModels \
|
||||||
|
-lfiniteVolume \
|
||||||
|
-llduSolvers \
|
||||||
|
-lmeshTools \
|
||||||
|
-llagrangian \
|
||||||
|
-lVectorN
|
|
@ -0,0 +1,15 @@
|
||||||
|
EXE_INC = \
|
||||||
|
// -I../../../myLibraries/finiteVolume/lnInclude \
|
||||||
|
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||||
|
-I../materialModels/lnInclude \
|
||||||
|
-I./solidInterface
|
||||||
|
// -I./patchToPatchInterpolation
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) \
|
||||||
|
// -lfiniteVolume_philipc \
|
||||||
|
// -lfiniteVolume \
|
||||||
|
-lmaterialModels_philipc \
|
||||||
|
-llduSolvers \
|
||||||
|
-lmeshTools
|
|
@ -0,0 +1,9 @@
|
||||||
|
EXE_INC = \
|
||||||
|
-I$(FOAM_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/dynamicMesh/lnInclude \
|
||||||
|
-I../materialModels/lnInclude
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) \
|
||||||
|
-lfiniteVolume \
|
||||||
|
-lmaterialModels_philipc
|
|
@ -0,0 +1,3 @@
|
||||||
|
DEpsilon = symm(gradDU) + 0.5*symm(gradDU & gradDU.T());
|
||||||
|
|
||||||
|
DSigma = 2*mu*DEpsilon + lambda*(I*tr(DEpsilon));
|
|
@ -0,0 +1,47 @@
|
||||||
|
if(divDSigmaExpMethod == "standard")
|
||||||
|
{
|
||||||
|
divDSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
mu*gradDU.T() + lambda*(I*tr(gradDU)) - (mu + lambda)*gradDU,
|
||||||
|
"div(sigma)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divDSigmaExpMethod == "surface")
|
||||||
|
{
|
||||||
|
divDSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
muf*(mesh.Sf() & fvc::interpolate(gradDU.T()))
|
||||||
|
+ lambdaf*(mesh.Sf() & I*fvc::interpolate(tr(gradDU)))
|
||||||
|
- (muf + lambdaf)*(mesh.Sf() & fvc::interpolate(gradDU))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divDSigmaExpMethod == "decompose")
|
||||||
|
{
|
||||||
|
surfaceTensorField shearGradDU =
|
||||||
|
((I - n*n)&fvc::interpolate(gradDU));
|
||||||
|
|
||||||
|
divDSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
mesh.magSf()
|
||||||
|
*(
|
||||||
|
- (muf + lambdaf)*(fvc::snGrad(DU)&(I - n*n))
|
||||||
|
+ lambdaf*tr(shearGradDU&(I - n*n))*n
|
||||||
|
+ muf*(shearGradDU&n)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divDSigmaExpMethod == "laplacian")
|
||||||
|
{
|
||||||
|
divDSigmaExp =
|
||||||
|
- fvc::laplacian(mu + lambda, DU, "laplacian(DDU,DU)")
|
||||||
|
+ fvc::div
|
||||||
|
(
|
||||||
|
mu*gradDU.T()
|
||||||
|
+ lambda*(I*tr(gradDU)),
|
||||||
|
"div(sigma)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalError << "divDSigmaExp method " << divDSigmaExpMethod << " not found!" << endl;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
//----------------------------------------------------//
|
||||||
|
//- sigma explicit large strain explicit terms
|
||||||
|
//----------------------------------------------------//
|
||||||
|
if(divDSigmaLargeStrainExpMethod == "standard")
|
||||||
|
{
|
||||||
|
divDSigmaLargeStrainExp =
|
||||||
|
fvc::div
|
||||||
|
(
|
||||||
|
mu*(gradDU & gradDU.T())
|
||||||
|
+ 0.5*lambda*(gradDU && gradDU)*I //- equivalent to 0.5*lambda*(I*tr(gradDU & gradDU.T()))
|
||||||
|
+ ((sigma + DSigma) & DF.T()),
|
||||||
|
"div(sigma)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divDSigmaLargeStrainExpMethod == "surface")
|
||||||
|
{
|
||||||
|
divDSigmaLargeStrainExp =
|
||||||
|
fvc::div
|
||||||
|
(
|
||||||
|
muf * (mesh.Sf() & fvc::interpolate(gradDU & gradDU.T()))
|
||||||
|
+ 0.5*lambdaf * (mesh.Sf() & (fvc::interpolate(gradDU && gradDU)*I))
|
||||||
|
+ (mesh.Sf() & fvc::interpolate( sigma & DF.T() ))
|
||||||
|
+ (mesh.Sf() & fvc::interpolate(DSigma & DF.T() ))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalError
|
||||||
|
<< "divDSigmaLargeStrainExp not found!"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- relax large strain component
|
||||||
|
divDSigmaLargeStrainExp.relax();
|
|
@ -0,0 +1,73 @@
|
||||||
|
//void Foam::edgeCorrectedVolPointInterpolation::makeExtrapolationWeights() const
|
||||||
|
//{
|
||||||
|
// Interpolation:
|
||||||
|
// For each point to be corrected calculate the extrapolated value
|
||||||
|
// for each face around it and combine them using the inverse
|
||||||
|
// distance weighting factors
|
||||||
|
|
||||||
|
//const labelList& ptc = boundaryPoints();
|
||||||
|
|
||||||
|
// Calculate the correction vectors
|
||||||
|
|
||||||
|
//extrapolationVectorsPtr_ =
|
||||||
|
// new FieldField<Field, vector>(ptc.size());
|
||||||
|
//FieldField<Field, vector>& extraVecs = *extrapolationVectorsPtr_;
|
||||||
|
FieldField<Field, vector> extraVecs(ptc.size());
|
||||||
|
|
||||||
|
{
|
||||||
|
const labelListList& pfaces = mesh.pointFaces();
|
||||||
|
|
||||||
|
const volVectorField& centres = mesh.C();
|
||||||
|
|
||||||
|
const fvBoundaryMesh& bm = mesh.boundary();
|
||||||
|
|
||||||
|
forAll (ptc, pointI)
|
||||||
|
{
|
||||||
|
const label curPoint = ptc[pointI];
|
||||||
|
|
||||||
|
const labelList& curFaces = pfaces[curPoint];
|
||||||
|
|
||||||
|
// extraVecs.hook(new vectorField(curFaces.size())); //- no hook function
|
||||||
|
extraVecs.set
|
||||||
|
(
|
||||||
|
pointI,
|
||||||
|
new vectorField(curFaces.size())
|
||||||
|
);
|
||||||
|
|
||||||
|
vectorField& curExtraVectors = extraVecs[pointI];
|
||||||
|
|
||||||
|
label nFacesAroundPoint = 0;
|
||||||
|
|
||||||
|
const vector& pointLoc = mesh.points()[curPoint];
|
||||||
|
|
||||||
|
// Go through all the faces
|
||||||
|
forAll (curFaces, faceI)
|
||||||
|
{
|
||||||
|
if (!mesh.isInternalFace(curFaces[faceI]))
|
||||||
|
{
|
||||||
|
// This is a boundary face. If not in the empty patch
|
||||||
|
// or coupled calculate the extrapolation vector
|
||||||
|
label patchID =
|
||||||
|
mesh.boundaryMesh().whichPatch(curFaces[faceI]);
|
||||||
|
|
||||||
|
if
|
||||||
|
(
|
||||||
|
!isA<emptyFvPatch>(bm[patchID])
|
||||||
|
&& !bm[patchID].coupled()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Found a face for extrapolation
|
||||||
|
curExtraVectors[nFacesAroundPoint] =
|
||||||
|
pointLoc
|
||||||
|
- centres.boundaryField()[patchID]
|
||||||
|
[bm[patchID].patch().whichFace(curFaces[faceI])];
|
||||||
|
|
||||||
|
nFacesAroundPoint++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
curExtraVectors.setSize(nFacesAroundPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
//void volPointInterpolation::makeBoundaryWeights() const
|
||||||
|
//{
|
||||||
|
// const labelList& ptc = boundaryPoints();
|
||||||
|
|
||||||
|
// Calculate the correction vectors and weighting factors
|
||||||
|
//pointBoundaryWeightsPtr_ = new FieldField<Field, scalar>(ptc.size());
|
||||||
|
//FieldField<Field, scalar>& w = *pointBoundaryWeightsPtr_;
|
||||||
|
FieldField<Field, scalar> w(ptc.size());
|
||||||
|
|
||||||
|
{
|
||||||
|
const labelListList& pf = mesh.pointFaces();
|
||||||
|
|
||||||
|
const volVectorField& centres = mesh.C();
|
||||||
|
|
||||||
|
const fvBoundaryMesh& bm = mesh.boundary();
|
||||||
|
|
||||||
|
pointScalarField volPointSumWeights
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"volPointSumWeights",
|
||||||
|
mesh.polyMesh::instance(),
|
||||||
|
mesh
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedScalar("zero", dimless, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
forAll (ptc, pointI)
|
||||||
|
{
|
||||||
|
const label curPoint = ptc[pointI];
|
||||||
|
|
||||||
|
const labelList& curFaces = pf[curPoint];
|
||||||
|
|
||||||
|
//w.hook(new scalarField(curFaces.size())); //philipc no hook function
|
||||||
|
w.set
|
||||||
|
(
|
||||||
|
pointI,
|
||||||
|
new scalarField(curFaces.size())
|
||||||
|
);
|
||||||
|
|
||||||
|
scalarField& curWeights = w[pointI];
|
||||||
|
|
||||||
|
label nFacesAroundPoint = 0;
|
||||||
|
|
||||||
|
const vector& pointLoc = mesh.points()[curPoint];
|
||||||
|
|
||||||
|
// Go through all the faces
|
||||||
|
forAll (curFaces, faceI)
|
||||||
|
{
|
||||||
|
if (!mesh.isInternalFace(curFaces[faceI]))
|
||||||
|
{
|
||||||
|
// This is a boundary face. If not in the empty patch
|
||||||
|
// or coupled calculate the extrapolation vector
|
||||||
|
label patchID =
|
||||||
|
mesh.boundaryMesh().whichPatch(curFaces[faceI]);
|
||||||
|
|
||||||
|
if
|
||||||
|
(
|
||||||
|
!isA<emptyFvPatch>(bm[patchID])
|
||||||
|
&& !(
|
||||||
|
bm[patchID].coupled()
|
||||||
|
//&& Pstream::parRun()
|
||||||
|
//&& !mesh.parallelData().cyclicParallel()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
curWeights[nFacesAroundPoint] =
|
||||||
|
1.0/mag
|
||||||
|
(
|
||||||
|
pointLoc
|
||||||
|
- centres.boundaryField()[patchID]
|
||||||
|
[
|
||||||
|
bm[patchID].patch().whichFace(curFaces[faceI])
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
nFacesAroundPoint++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the sizes of the local weights
|
||||||
|
curWeights.setSize(nFacesAroundPoint);
|
||||||
|
|
||||||
|
// Collect the sum of weights for parallel correction
|
||||||
|
volPointSumWeights[curPoint] += sum(curWeights);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do parallel correction of weights
|
||||||
|
|
||||||
|
// Update coupled boundaries
|
||||||
|
// Work-around for cyclic parallels.
|
||||||
|
/*if (Pstream::parRun() && !mesh.parallelData().cyclicParallel())
|
||||||
|
{
|
||||||
|
forAll (volPointSumWeights.boundaryField(), patchI)
|
||||||
|
{
|
||||||
|
if (volPointSumWeights.boundaryField()[patchI].coupled())
|
||||||
|
{
|
||||||
|
volPointSumWeights.boundaryField()[patchI].initAddField();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
forAll (volPointSumWeights.boundaryField(), patchI)
|
||||||
|
{
|
||||||
|
if (volPointSumWeights.boundaryField()[patchI].coupled())
|
||||||
|
{
|
||||||
|
volPointSumWeights.boundaryField()[patchI].addField
|
||||||
|
(
|
||||||
|
volPointSumWeights.internalField()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// Re-scale the weights for the current point
|
||||||
|
forAll (ptc, pointI)
|
||||||
|
{
|
||||||
|
w[pointI] /= volPointSumWeights[ptc[pointI]];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
scalarField magDU = mag(DU.internalField());
|
||||||
|
|
||||||
|
forAll(magDU, cellI)
|
||||||
|
{
|
||||||
|
if (magDU[cellI] < SMALL)
|
||||||
|
{
|
||||||
|
magDU[cellI] = SMALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relativeResidual =
|
||||||
|
gMax
|
||||||
|
(
|
||||||
|
mag
|
||||||
|
(
|
||||||
|
DU.internalField()
|
||||||
|
- DU.prevIter().internalField()
|
||||||
|
)
|
||||||
|
/magDU
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
correctGlobalFaceZoneMesh.H
|
||||||
|
|
||||||
|
When there is a globalFaceZone and the mesh is moved by interpolating U to the
|
||||||
|
vertices with volPointInterpolation, then there are two problems:
|
||||||
|
-some points on the patch with the faceZone are moved incorrectly, I think
|
||||||
|
it is because the faceZone has no U and causes an incorrect interpolation,
|
||||||
|
-the faceZones points not on the proc cells are not moved at all because
|
||||||
|
they have no U.
|
||||||
|
|
||||||
|
So the points on the patch with the faceZone need to be fixed and also all the
|
||||||
|
faceZone points need to be moved and synchronised so each proc has the same
|
||||||
|
full faceZone mesh.
|
||||||
|
|
||||||
|
The mapping of procs faceZone order of points to the master procs faceZone point
|
||||||
|
order is kept in procToGlobalFZmap, which is calculated at the start of the run
|
||||||
|
in the createGlobalToLocalFaceZonePointMap.H header file.
|
||||||
|
|
||||||
|
Note: DU is used for updated Lagrangian solver instead of U
|
||||||
|
|
||||||
|
philipc
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//- this is only needed in a parallel runs
|
||||||
|
if(Pstream::parRun())
|
||||||
|
{
|
||||||
|
//***** FIX INCORRECT POINT ON PATCHES WITH FACEZONE *****//
|
||||||
|
contactPatchPairList& contacts = contact;
|
||||||
|
|
||||||
|
forAll(contacts, contactI)
|
||||||
|
{
|
||||||
|
label masterID = contacts[contactI].masterPatch().index();
|
||||||
|
label slaveID = contacts[contactI].slavePatch().index();
|
||||||
|
|
||||||
|
primitivePatchInterpolation masterInterpolator
|
||||||
|
(mesh.boundaryMesh()[masterID]);
|
||||||
|
primitivePatchInterpolation slaveInterpolator
|
||||||
|
(mesh.boundaryMesh()[slaveID]);
|
||||||
|
|
||||||
|
//- DU must be interpolated to the vertices, this ignores the faceZone
|
||||||
|
//- points with no DU (unlike volPointInterpolation)
|
||||||
|
vectorField correctMasterPointDU =
|
||||||
|
masterInterpolator.faceToPointInterpolate<vector>
|
||||||
|
(
|
||||||
|
DU.boundaryField()[masterID]
|
||||||
|
);
|
||||||
|
vectorField correctSlavePointDU =
|
||||||
|
slaveInterpolator.faceToPointInterpolate<vector>
|
||||||
|
(
|
||||||
|
DU.boundaryField()[slaveID]
|
||||||
|
);
|
||||||
|
|
||||||
|
vectorField oldMasterPoints =
|
||||||
|
mesh.boundaryMesh()[masterID].localPoints();
|
||||||
|
vectorField oldSlavePoints =
|
||||||
|
mesh.boundaryMesh()[slaveID].localPoints();
|
||||||
|
|
||||||
|
labelList masterPointLabels =
|
||||||
|
mesh.boundaryMesh()[masterID].meshPoints();
|
||||||
|
labelList slavePointLabels =
|
||||||
|
mesh.boundaryMesh()[slaveID].meshPoints();
|
||||||
|
|
||||||
|
//- correct the patch newPoints
|
||||||
|
forAll(masterPointLabels, pointI)
|
||||||
|
{
|
||||||
|
label pointGlobalLabel = masterPointLabels[pointI];
|
||||||
|
newPoints[pointGlobalLabel] =
|
||||||
|
oldMasterPoints[pointI]
|
||||||
|
+
|
||||||
|
correctMasterPointDU[pointI];
|
||||||
|
}
|
||||||
|
forAll(slavePointLabels, pointI)
|
||||||
|
{
|
||||||
|
label pointGlobalLabel = slavePointLabels[pointI];
|
||||||
|
newPoints[pointGlobalLabel] =
|
||||||
|
oldSlavePoints[pointI]
|
||||||
|
+
|
||||||
|
correctSlavePointDU[pointI];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//***** NOW FIX AND SYNCHRONISE ALL THE FACEZONE POINTS *****//
|
||||||
|
|
||||||
|
forAll(mesh.faceZones(), faceZoneI)
|
||||||
|
{
|
||||||
|
//- find the patch corresponding to this faceZone
|
||||||
|
//- assuming that the FZ is called <patch_name>FaceZone
|
||||||
|
string faceZoneName = mesh.faceZones().names()[faceZoneI];
|
||||||
|
//- remove the string FaceZone from the end of the face zone name to get the patch name
|
||||||
|
string patchName = faceZoneName.substr(0, (faceZoneName.size()-8));
|
||||||
|
label patchID = mesh.boundaryMesh().findPatchID(patchName);
|
||||||
|
if(patchID == -1)
|
||||||
|
{
|
||||||
|
FatalError << "Patch " << patchName << " not found corresponding for faceZone"
|
||||||
|
<< faceZoneName << exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
vectorField globalFZpoints =
|
||||||
|
mesh.faceZones()[faceZoneI]().localPoints();
|
||||||
|
|
||||||
|
//- new points for the face zone
|
||||||
|
vectorField globalFZnewPoints(globalFZpoints.size(), vector::zero);
|
||||||
|
|
||||||
|
//- inter-proc points are shared by multiple procs
|
||||||
|
//- pointNumProc is the number of procs which a point lies on
|
||||||
|
scalarField pointNumProcs(globalFZpoints.size(), 0.0);
|
||||||
|
|
||||||
|
forAll(globalFZnewPoints, globalPointI)
|
||||||
|
{
|
||||||
|
label localPoint = procToGlobalFZmap[faceZoneI][globalPointI];
|
||||||
|
|
||||||
|
//if(localPoint < mesh.boundaryMesh()[patchID].localPoints().size())
|
||||||
|
if(pointOnLocalProcPatch[faceZoneI][localPoint])
|
||||||
|
{
|
||||||
|
label procPoint =
|
||||||
|
mesh.faceZones()[faceZoneI]().meshPoints()[localPoint];
|
||||||
|
globalFZnewPoints[globalPointI] =
|
||||||
|
newPoints[procPoint];
|
||||||
|
pointNumProcs[globalPointI] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce(globalFZnewPoints, sumOp<vectorField>());
|
||||||
|
reduce(pointNumProcs, sumOp<scalarField>());
|
||||||
|
|
||||||
|
//- now average the newPoints between all procs
|
||||||
|
if(min(pointNumProcs) < 1)
|
||||||
|
{
|
||||||
|
FatalError << "pointNumProc has not been set for all points" << exit(FatalError);
|
||||||
|
}
|
||||||
|
globalFZnewPoints /= pointNumProcs;
|
||||||
|
|
||||||
|
//- the globalFZnewPoints now contains the correct FZ new points in
|
||||||
|
//- a global order, now convert them back into the local proc order
|
||||||
|
|
||||||
|
vectorField procFZnewPoints(globalFZpoints.size(), vector::zero);
|
||||||
|
|
||||||
|
forAll(globalFZnewPoints, globalPointI)
|
||||||
|
{
|
||||||
|
label localPoint = procToGlobalFZmap[faceZoneI][globalPointI];
|
||||||
|
|
||||||
|
procFZnewPoints[localPoint] =
|
||||||
|
globalFZnewPoints[globalPointI];
|
||||||
|
}
|
||||||
|
|
||||||
|
//- now fix the newPoints points on the globalFaceZones
|
||||||
|
labelList procFZmeshPoints =
|
||||||
|
mesh.faceZones()[faceZoneI]().meshPoints();
|
||||||
|
|
||||||
|
forAll(procFZmeshPoints, pointI)
|
||||||
|
{
|
||||||
|
label procPoint = procFZmeshPoints[pointI];
|
||||||
|
newPoints[procPoint] =
|
||||||
|
procFZnewPoints[pointI];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
Info<< "Reading field DU\n" << endl;
|
||||||
|
volVectorField DU
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"DU",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::MUST_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh
|
||||||
|
);
|
||||||
|
|
||||||
|
volTensorField gradDU = fvc::grad(DU);
|
||||||
|
|
||||||
|
volVectorField U
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"U",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedVector("zero", dimLength, vector::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField DEpsilon
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"DEpsilon",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimless, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField epsilon
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"epsilon",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimless, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField DSigma
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"DSigma",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimForce/dimArea, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField sigma
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"sigma",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimForce/dimArea, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volVectorField divDSigmaExp
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"divDSigmaExp",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedVector("zero", dimensionSet(1,-2,-2,0,0,0,0), vector::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volVectorField divDSigmaLargeStrainExp
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"divDSigmaLargeStrainExp",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedVector("zero", dimensionSet(1,-2,-2,0,0,0,0), vector::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
// read rheology properties
|
||||||
|
rheologyModel rheology(sigma);
|
||||||
|
|
||||||
|
volScalarField rho = rheology.rho();
|
||||||
|
|
||||||
|
volScalarField mu = rheology.mu();
|
||||||
|
volScalarField lambda = rheology.lambda();
|
||||||
|
surfaceScalarField muf = fvc::interpolate(mu, "mu");
|
||||||
|
surfaceScalarField lambdaf = fvc::interpolate(lambda, "lambda");
|
||||||
|
|
||||||
|
surfaceVectorField n = mesh.Sf()/mesh.magSf();
|
||||||
|
|
||||||
|
volTensorField DF = gradDU.T();
|
||||||
|
volTensorField F = I + DF;
|
||||||
|
volScalarField J = det(F);
|
||||||
|
|
||||||
|
//- create contact problem
|
||||||
|
contactProblem contact(DU);
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
createGlobalToLocalFaceZonePointMap.H
|
||||||
|
|
||||||
|
I could not figure out the order of the points on a globalFaceZone, they is a
|
||||||
|
different order for each processor where the processors own points come first.
|
||||||
|
|
||||||
|
So I decide that the master proc order is the global order and I find the map
|
||||||
|
from this order to each proc order here by just commparing actual point
|
||||||
|
coordinates.
|
||||||
|
|
||||||
|
This map is then used to correct and synchronise the globalFaceZone points on
|
||||||
|
all the procs when the mesh is moved, in header file correctGlobalFaceZoneMesh.H.
|
||||||
|
|
||||||
|
philipc
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//- procToGlobalFZmap is a map from the current proc faceZone point order to the
|
||||||
|
//- master proc point order
|
||||||
|
//- these are read if present to allow restarting of contact cases
|
||||||
|
IOList<labelList> procToGlobalFZmap
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"procToGlobalFZmap",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh.faceZones().size()
|
||||||
|
);
|
||||||
|
|
||||||
|
IOList<labelList> pointOnLocalProcPatch
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointOnLocalProcPatch",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh.faceZones().size()
|
||||||
|
);
|
||||||
|
|
||||||
|
//- if they have been read then don't recalculate it
|
||||||
|
bool globalFaceZoneMappingSet = false;
|
||||||
|
if(gMax(procToGlobalFZmap[0]) > 0 && gMax(pointOnLocalProcPatch[0]) > 0)
|
||||||
|
{
|
||||||
|
Info << "Reading procToGlobalFZmap and pointOnLocalProcPatch allowing restart of contact cases"
|
||||||
|
<< endl;
|
||||||
|
globalFaceZoneMappingSet = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info << "procToGlobalFZmap and pointOnLocalProcPatch will be calculated as it has not been found" << nl
|
||||||
|
<< "this message should only appear starting a new analysis" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- this is only needed in a parallel runs
|
||||||
|
if(Pstream::parRun())
|
||||||
|
{
|
||||||
|
if(!globalFaceZoneMappingSet)
|
||||||
|
{
|
||||||
|
forAll(mesh.faceZones(), faceZoneI)
|
||||||
|
{
|
||||||
|
vectorField globalFZpoints = mesh.faceZones()[faceZoneI]().localPoints();
|
||||||
|
|
||||||
|
procToGlobalFZmap[faceZoneI].setSize(globalFZpoints.size(), 0);
|
||||||
|
|
||||||
|
//- set all slave points to zero because only the master order is used
|
||||||
|
if(!Pstream::master())
|
||||||
|
globalFZpoints *= 0.0;
|
||||||
|
|
||||||
|
//- pass points to all procs
|
||||||
|
reduce(globalFZpoints, sumOp<vectorField>());
|
||||||
|
|
||||||
|
|
||||||
|
//- now every proc has the master's list of FZ points
|
||||||
|
//- every proc must now find the mapping from their local FZpoints to
|
||||||
|
//- the globalFZpoints
|
||||||
|
|
||||||
|
vectorField procFZpoints = mesh.faceZones()[faceZoneI]().localPoints();
|
||||||
|
|
||||||
|
forAll(globalFZpoints, globalPointI)
|
||||||
|
{
|
||||||
|
forAll(procFZpoints, procPointI)
|
||||||
|
{
|
||||||
|
if(procFZpoints[procPointI] == globalFZpoints[globalPointI])
|
||||||
|
{
|
||||||
|
procToGlobalFZmap[faceZoneI][globalPointI] = procPointI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//- procToGlobalFZmap now contains the local FZpoint label for each
|
||||||
|
//- global FZ point label - for each faceZone
|
||||||
|
|
||||||
|
//- check what points are on the current proc patch
|
||||||
|
pointOnLocalProcPatch[faceZoneI].setSize(globalFZpoints.size(), 0);
|
||||||
|
|
||||||
|
//- find corresponding patch
|
||||||
|
string faceZoneName = mesh.faceZones().names()[faceZoneI];
|
||||||
|
//- remove the string FaceZone from the end of the face zone name to get the patch name
|
||||||
|
string patchName = faceZoneName.substr(0, (faceZoneName.size()-8));
|
||||||
|
label patchID = mesh.boundaryMesh().findPatchID(patchName);
|
||||||
|
if(patchID == -1)
|
||||||
|
{
|
||||||
|
FatalError << "Patch " << patchName << " not found corresponding for faceZone"
|
||||||
|
<< faceZoneName << exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
forAll(mesh.faceZones()[faceZoneI]().localPoints(), fzpi)
|
||||||
|
{
|
||||||
|
forAll(mesh.boundaryMesh()[patchID].localPoints(), pi)
|
||||||
|
{
|
||||||
|
if(mesh.faceZones()[faceZoneI]().localPoints()[fzpi] == mesh.boundaryMesh()[patchID].localPoints()[pi])
|
||||||
|
{
|
||||||
|
pointOnLocalProcPatch[faceZoneI][fzpi] = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} //- end if(!globalFaceZoneMappingSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
//- write to disk to allow restart of cases
|
||||||
|
//- because it is not possible to calculate the
|
||||||
|
//- mapping after the meshes have moved
|
||||||
|
if(!globalFaceZoneMappingSet)
|
||||||
|
{
|
||||||
|
procToGlobalFZmap.write();
|
||||||
|
pointOnLocalProcPatch.write();
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2004-2007 Hrvoje Jasak
|
||||||
|
\\/ 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
|
||||||
|
|
||||||
|
Application
|
||||||
|
elasticContactNonLinSolidFoam
|
||||||
|
|
||||||
|
Description
|
||||||
|
Transient/steady-state segregated finite-volume solver for large strain
|
||||||
|
elastic solid bodies in contact, using an incremental updated Lagrangian
|
||||||
|
approach.
|
||||||
|
|
||||||
|
Works in parallel but mesh.movePoints sometimes fails for some unknown
|
||||||
|
reason depending on the decomposition.
|
||||||
|
|
||||||
|
Solves for the displacement increment vector field DU, also generating the
|
||||||
|
stress tensor field sigma.
|
||||||
|
|
||||||
|
It is only for frictionless contact, friction not implemented yet.
|
||||||
|
|
||||||
|
Author
|
||||||
|
Philip Cardiff
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "fvCFD.H"
|
||||||
|
#include "rheologyModel.H"
|
||||||
|
#include "contactProblem.H"
|
||||||
|
|
||||||
|
#include "volPointInterpolation.H"
|
||||||
|
#include "leastSquaresVolPointInterpolation.H"
|
||||||
|
#include "pointPatchInterpolation.H"
|
||||||
|
#include "primitivePatchInterpolation.H"
|
||||||
|
#include "fixedValuePointPatchFields.H"
|
||||||
|
#include "pointFields.H"
|
||||||
|
#include "pointMesh.H"
|
||||||
|
#include "pointBoundaryMesh.H"
|
||||||
|
#include "primitivePatchInterpolation.H"
|
||||||
|
#include "twoDPointCorrector.H"
|
||||||
|
#include "plane.H"
|
||||||
|
#include "meshSearch.H"
|
||||||
|
|
||||||
|
#include "OFstream.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
# include "setRootCase.H"
|
||||||
|
|
||||||
|
# include "createTime.H"
|
||||||
|
|
||||||
|
# include "createMesh.H"
|
||||||
|
|
||||||
|
# include "createFields.H"
|
||||||
|
|
||||||
|
# include "readDivDSigmaExpMethod.H"
|
||||||
|
|
||||||
|
# include "readDivDSigmaLargeStrainMethod.H"
|
||||||
|
|
||||||
|
# include "readMoveMeshMethod.H"
|
||||||
|
|
||||||
|
# include "createGlobalToLocalFaceZonePointMap.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Info<< "\nStarting time loop\n" << endl;
|
||||||
|
|
||||||
|
for (runTime++; !runTime.end(); runTime++)
|
||||||
|
{
|
||||||
|
Info<< "Time: " << runTime.timeName() << endl;
|
||||||
|
|
||||||
|
# include "readContactControls.H"
|
||||||
|
|
||||||
|
# include "readStressedFoamControls.H"
|
||||||
|
|
||||||
|
//-- for moving the mesh and then back again
|
||||||
|
vectorField oldMeshPoints = mesh.allPoints();
|
||||||
|
|
||||||
|
int iCorr = 0;
|
||||||
|
lduMatrix::solverPerformance solverPerf;
|
||||||
|
word solverName;
|
||||||
|
lduMatrix::debug = 0;
|
||||||
|
scalar residual = GREAT;
|
||||||
|
scalar initialResidual = 0;
|
||||||
|
scalar relativeResidual = GREAT;
|
||||||
|
|
||||||
|
do //- start of momentum loop
|
||||||
|
{
|
||||||
|
DU.storePrevIter();
|
||||||
|
|
||||||
|
divDSigmaLargeStrainExp.storePrevIter();
|
||||||
|
|
||||||
|
//- correct the contact boundaries
|
||||||
|
if(iCorr % uEqnContactCorrFreq == 0)
|
||||||
|
{
|
||||||
|
Info << "\t\tCorrecting contact in the momentum loop "
|
||||||
|
<< "iteration: " << iCorr
|
||||||
|
<< ", residual: " << residual
|
||||||
|
<< endl;
|
||||||
|
//# include "moveMeshLeastSquares.H"
|
||||||
|
# include "moveSolidMeshForContact.H"
|
||||||
|
contact.correct();
|
||||||
|
mesh.movePoints(oldMeshPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
# include "calculateDivDSigmaExp.H"
|
||||||
|
|
||||||
|
# include "calculateDivDSigmaExpLargeStrain.H"
|
||||||
|
|
||||||
|
fvVectorMatrix DUEqn
|
||||||
|
(
|
||||||
|
fvm::d2dt2(rho, DU)
|
||||||
|
==
|
||||||
|
fvm::laplacian(2*mu + lambda, DU, "laplacian(DDU,DU)")
|
||||||
|
+ divDSigmaExp
|
||||||
|
+ divDSigmaLargeStrainExp
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
solverPerf = DUEqn.solve();
|
||||||
|
|
||||||
|
DU.relax();
|
||||||
|
|
||||||
|
solverName = solverPerf.solverName();
|
||||||
|
|
||||||
|
gradDU = fvc::grad(DU);
|
||||||
|
|
||||||
|
DF = gradDU.T();
|
||||||
|
|
||||||
|
# include "calculateDEpsilonDSigma.H"
|
||||||
|
|
||||||
|
residual = solverPerf.initialResidual();
|
||||||
|
|
||||||
|
if(iCorr == 0)
|
||||||
|
{
|
||||||
|
initialResidual = solverPerf.initialResidual();
|
||||||
|
}
|
||||||
|
|
||||||
|
# include "calculateRelativeResidual.H"
|
||||||
|
|
||||||
|
Info << "\tTime " << runTime.value()
|
||||||
|
<< ", Corrector " << iCorr
|
||||||
|
<< ", Solving for " << DU.name()
|
||||||
|
<< " using " << solverPerf.solverName()
|
||||||
|
<< ", residual = " << solverPerf.initialResidual()
|
||||||
|
<< ", relative residual = " << relativeResidual << endl;
|
||||||
|
} //- end of momentum loop
|
||||||
|
while
|
||||||
|
(
|
||||||
|
relativeResidual > convergenceTolerance
|
||||||
|
//residual > convergenceTolerance
|
||||||
|
&&
|
||||||
|
++iCorr < nCorr
|
||||||
|
);
|
||||||
|
|
||||||
|
// Print out info per contact iteration
|
||||||
|
Info << "\t\tSolving for " << DU.name()
|
||||||
|
<< " using " << solverName
|
||||||
|
<< ", Initial residual = " << initialResidual
|
||||||
|
<< ", Final residual = " << solverPerf.initialResidual()
|
||||||
|
<< ", No outer iterations " << iCorr << endl;
|
||||||
|
|
||||||
|
lduMatrix::debug = 1;
|
||||||
|
|
||||||
|
# include "rotateFields.H"
|
||||||
|
|
||||||
|
# include "moveMesh.H"
|
||||||
|
|
||||||
|
# include "writeFields.H"
|
||||||
|
|
||||||
|
Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
|
||||||
|
<< " ClockTime = " << runTime.elapsedClockTime() << " s"
|
||||||
|
<< endl << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< "End\n" << endl;
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
|
@ -0,0 +1,39 @@
|
||||||
|
//void volPointInterpolation::makeBoundaryAddressing() const
|
||||||
|
//{
|
||||||
|
|
||||||
|
// Go through all patches and mark up the external edge points
|
||||||
|
labelHashSet pointsCorrectionMap(max(mesh.nPoints()/10, 100));
|
||||||
|
|
||||||
|
const fvBoundaryMesh& bm = mesh.boundary();
|
||||||
|
|
||||||
|
forAll (bm, patchI)
|
||||||
|
{
|
||||||
|
// If the patch is empty, skip it
|
||||||
|
// If the patch is coupled, and there are no cyclic parallels, skip it
|
||||||
|
if
|
||||||
|
(
|
||||||
|
!isA<emptyFvPatch>(bm[patchI])
|
||||||
|
&& !(
|
||||||
|
bm[patchI].coupled()
|
||||||
|
//&& Pstream::parRun()
|
||||||
|
//&& !mesh.parallelData().cyclicParallel()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const labelList& bp = bm[patchI].patch().boundaryPoints();
|
||||||
|
|
||||||
|
const labelList& meshPoints = bm[patchI].patch().meshPoints();
|
||||||
|
|
||||||
|
forAll (bp, pointI)
|
||||||
|
{
|
||||||
|
pointsCorrectionMap.insert(meshPoints[bp[pointI]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the points to correct
|
||||||
|
//boundaryPointsPtr_ = new labelList(pointsCorrectionMap.toc());
|
||||||
|
//labelList& ptc = *boundaryPointsPtr_;
|
||||||
|
labelList ptc(pointsCorrectionMap.toc());
|
||||||
|
|
||||||
|
sort(ptc);
|
|
@ -0,0 +1,15 @@
|
||||||
|
if(moveMeshMethod == "inverseDistance")
|
||||||
|
{
|
||||||
|
# include "moveMeshInverseDistance.H"
|
||||||
|
}
|
||||||
|
else if(moveMeshMethod == "leastSquares")
|
||||||
|
{
|
||||||
|
# include "moveMeshLeastSquares.H"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalError << "move mesh method " << moveMeshMethod << " not recognised" << nl
|
||||||
|
<< "available methods are:" << nl
|
||||||
|
<< "inverseDistance" << nl
|
||||||
|
<< "leastSquares" << exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
//--------------------------------------------------//
|
||||||
|
//- move mesh
|
||||||
|
//--------------------------------------------------//
|
||||||
|
if(min(J.internalField()) > 0)
|
||||||
|
{
|
||||||
|
Info << "Move solid mesh using inverse distance interpolation" << endl;
|
||||||
|
|
||||||
|
// Create point mesh
|
||||||
|
pointMesh pMesh(mesh);
|
||||||
|
|
||||||
|
// Create point interpolation
|
||||||
|
volPointInterpolation pointInterpolation(mesh);
|
||||||
|
|
||||||
|
wordList types
|
||||||
|
(
|
||||||
|
pMesh.boundary().size(),
|
||||||
|
//fixedValueFvPatchVectorField::typeName
|
||||||
|
calculatedFvPatchVectorField::typeName
|
||||||
|
);
|
||||||
|
|
||||||
|
pointVectorField pointDU
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointDU",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedVector("zero", dimLength, vector::zero),
|
||||||
|
types
|
||||||
|
);
|
||||||
|
|
||||||
|
// Calculate mesh points displacement
|
||||||
|
pointInterpolation.interpolate(DU, pointDU);
|
||||||
|
|
||||||
|
//- correct edge interpolation
|
||||||
|
//- this is the stuff from edgeCorrectedVolPointInterpolation but
|
||||||
|
//- that class no longer works
|
||||||
|
# include "performEdgeCorrectedVolPointInterpolation.H"
|
||||||
|
|
||||||
|
//pointDU.write();
|
||||||
|
|
||||||
|
const vectorField& pointDUI =
|
||||||
|
pointDU.internalField();
|
||||||
|
|
||||||
|
// Move mesh
|
||||||
|
vectorField newPoints = mesh.allPoints();
|
||||||
|
|
||||||
|
forAll (pointDUI, pointI)
|
||||||
|
{
|
||||||
|
newPoints[pointI] += pointDUI[pointI];
|
||||||
|
}
|
||||||
|
|
||||||
|
twoDPointCorrector twoDCorrector(mesh);
|
||||||
|
twoDCorrector.correctPoints(newPoints);
|
||||||
|
mesh.movePoints(newPoints);
|
||||||
|
mesh.V00();
|
||||||
|
mesh.moving(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalErrorIn(args.executable())
|
||||||
|
<< "Negative Jacobian"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
//--------------------------------------------------//
|
||||||
|
//- move mesh
|
||||||
|
//--------------------------------------------------//
|
||||||
|
if(min(J.internalField()) > 0)
|
||||||
|
{
|
||||||
|
Info << "Moving mesh using least squares interpolation" << endl;
|
||||||
|
|
||||||
|
leastSquaresVolPointInterpolation pointInterpolation(mesh);
|
||||||
|
|
||||||
|
// Create point mesh
|
||||||
|
pointMesh pMesh(mesh);
|
||||||
|
|
||||||
|
wordList types
|
||||||
|
(
|
||||||
|
pMesh.boundary().size(),
|
||||||
|
calculatedFvPatchVectorField::typeName
|
||||||
|
);
|
||||||
|
|
||||||
|
pointVectorField pointDU
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointDU",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedVector("zero", dimLength, vector::zero),
|
||||||
|
types
|
||||||
|
);
|
||||||
|
|
||||||
|
pointInterpolation.interpolate(DU, pointDU);
|
||||||
|
|
||||||
|
const vectorField& pointDUI =
|
||||||
|
pointDU.internalField();
|
||||||
|
|
||||||
|
//- Move mesh
|
||||||
|
vectorField newPoints = mesh.allPoints();
|
||||||
|
|
||||||
|
forAll (pointDUI, pointI)
|
||||||
|
{
|
||||||
|
newPoints[pointI] += pointDUI[pointI];
|
||||||
|
}
|
||||||
|
|
||||||
|
twoDPointCorrector twoDCorrector(mesh);
|
||||||
|
twoDCorrector.correctPoints(newPoints);
|
||||||
|
mesh.movePoints(newPoints);
|
||||||
|
mesh.V00();
|
||||||
|
mesh.moving(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalErrorIn(args.executable())
|
||||||
|
<< "Negative Jacobian"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
// Create point interpolation
|
||||||
|
volPointInterpolation pointInterpolation(mesh);
|
||||||
|
|
||||||
|
// Calculate mesh points displacement
|
||||||
|
pointVectorField pointDU = pointInterpolation.interpolate(DU);
|
||||||
|
|
||||||
|
vectorField pointDUI = pointDU.internalField();
|
||||||
|
|
||||||
|
// Move mesh
|
||||||
|
vectorField newPoints = mesh.allPoints();
|
||||||
|
|
||||||
|
forAll (pointDUI, pointI)
|
||||||
|
{
|
||||||
|
newPoints[pointI] += pointDUI[pointI];
|
||||||
|
}
|
||||||
|
|
||||||
|
# include "correctGlobalFaceZoneMesh.H"
|
||||||
|
|
||||||
|
twoDPointCorrector twoDCorrector(mesh);
|
||||||
|
twoDCorrector.correctPoints(newPoints);
|
||||||
|
|
||||||
|
mesh.movePoints(newPoints);
|
||||||
|
// pMesh.movePoints(newPoints);
|
||||||
|
mesh.V00();
|
||||||
|
mesh.moving(false);
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
// Do "normal" interpolation
|
||||||
|
//volPointInterpolation::interpolate(vf, pf);
|
||||||
|
|
||||||
|
//- interpolation is done just before this file
|
||||||
|
pointVectorField& pf = pointDU;
|
||||||
|
|
||||||
|
|
||||||
|
// Do the correction
|
||||||
|
//GeometricField<Type, pointPatchField, pointMesh> pfCorr
|
||||||
|
/*pointVectorField pfCorr
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
// "edgeCorrectedVolPointInterpolate(" + vf.name() + ")Corr",
|
||||||
|
"edgeCorrectedVolPointInterpolate(" + DU.name() + ")Corr",
|
||||||
|
//vf.instance(),
|
||||||
|
DU,
|
||||||
|
pMesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
//dimensioned<Type>("zero", pf.dimensions(), pTraits<Type>::zero),
|
||||||
|
dimensionedVector("zero", pf.dimensions(), vector::zero),
|
||||||
|
pf.boundaryField().types()
|
||||||
|
);*/
|
||||||
|
|
||||||
|
pointVectorField pfCorr
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointDUcorr",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedVector("vector", dimLength, vector::zero),
|
||||||
|
"calculated"
|
||||||
|
);
|
||||||
|
|
||||||
|
//const labelList& ptc = boundaryPoints();
|
||||||
|
#include "findBoundaryPoints.H"
|
||||||
|
|
||||||
|
//const FieldField<Field, vector>& extraVecs = extrapolationVectors(); ///*********
|
||||||
|
#include "calculateExtrapolationVectors.H"
|
||||||
|
|
||||||
|
//const FieldField<Field, scalar>& w = pointBoundaryWeights(); ///*********
|
||||||
|
#include "calculatePointBoundaryWeights.H"
|
||||||
|
|
||||||
|
//Info << "w: " << w << endl;
|
||||||
|
|
||||||
|
const labelListList& PointFaces = mesh.pointFaces();
|
||||||
|
|
||||||
|
//const fvBoundaryMesh& bm = mesh.boundary(); // declared in findBoundaryPoints.H
|
||||||
|
|
||||||
|
forAll (ptc, pointI)
|
||||||
|
{
|
||||||
|
const label curPoint = ptc[pointI];
|
||||||
|
|
||||||
|
const labelList& curFaces = PointFaces[curPoint];
|
||||||
|
|
||||||
|
label fI = 0;
|
||||||
|
|
||||||
|
// Go through all the faces
|
||||||
|
forAll (curFaces, faceI)
|
||||||
|
{
|
||||||
|
if (!mesh.isInternalFace(curFaces[faceI]))
|
||||||
|
{
|
||||||
|
// This is a boundary face. If not in the empty patch
|
||||||
|
// or coupled calculate the extrapolation vector
|
||||||
|
label patchID =
|
||||||
|
mesh.boundaryMesh().whichPatch(curFaces[faceI]);
|
||||||
|
|
||||||
|
if
|
||||||
|
(
|
||||||
|
!isA<emptyFvPatch>(mesh.boundary()[patchID])
|
||||||
|
&& !mesh.boundary()[patchID].coupled()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
label faceInPatchID =
|
||||||
|
bm[patchID].patch().whichFace(curFaces[faceI]);
|
||||||
|
|
||||||
|
pfCorr[curPoint] +=
|
||||||
|
w[pointI][fI]*
|
||||||
|
(
|
||||||
|
extraVecs[pointI][fI]
|
||||||
|
& gradDU.boundaryField()[patchID][faceInPatchID]
|
||||||
|
);
|
||||||
|
|
||||||
|
fI++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update coupled boundaries
|
||||||
|
/*forAll (pfCorr.boundaryField(), patchI)
|
||||||
|
{
|
||||||
|
if (pfCorr.boundaryField()[patchI].coupled())
|
||||||
|
{
|
||||||
|
pfCorr.boundaryField()[patchI].initAddField();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*forAll (pfCorr.boundaryField(), patchI)
|
||||||
|
{
|
||||||
|
if (pfCorr.boundaryField()[patchI].coupled())
|
||||||
|
{
|
||||||
|
pfCorr.boundaryField()[patchI].addField(pfCorr.internalField());
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
//Info << "pfCorr: " << pfCorr << endl;
|
||||||
|
pfCorr.correctBoundaryConditions();
|
||||||
|
|
||||||
|
//pfCorr.write();
|
||||||
|
|
||||||
|
//Info << "pf: " << pf << endl;
|
||||||
|
pf += pfCorr;
|
||||||
|
|
||||||
|
//- this was already commented
|
||||||
|
// Replace extrapolated values in pf
|
||||||
|
// forAll (ptc, pointI)
|
||||||
|
// {
|
||||||
|
// pf[ptc[pointI]] = pfCorr[ptc[pointI]];
|
||||||
|
// }
|
||||||
|
|
||||||
|
pf.correctBoundaryConditions();
|
||||||
|
|
||||||
|
//pf.write();
|
|
@ -0,0 +1,55 @@
|
||||||
|
if (runTime.outputTime())
|
||||||
|
{
|
||||||
|
// FAILS IN PARALLEL - FIX
|
||||||
|
// Info << "Print contact area" << endl;
|
||||||
|
//volScalarField ca = contact.contactArea();
|
||||||
|
//ca.write();
|
||||||
|
|
||||||
|
//-------------------------------------------------------------//
|
||||||
|
// I couldn't get tmp to return the pointScalarField correctly //
|
||||||
|
// so I had to make the pointScalarField here and pass it to //
|
||||||
|
// contactGapPoints and pointContactForce to populate //
|
||||||
|
//-------------------------------------------------------------//
|
||||||
|
//This is the point distance for each contact vertex
|
||||||
|
pointScalarField cGapPoints
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointContactGap",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedScalar("scalar", dimLength, 0.0),
|
||||||
|
"calculated"
|
||||||
|
);
|
||||||
|
|
||||||
|
contact.contactGapPoints(cGapPoints);
|
||||||
|
cGapPoints.write();
|
||||||
|
|
||||||
|
|
||||||
|
//- This is the point distance for each contact vertex
|
||||||
|
pointVectorField cPointForce
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointContactForce",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedVector("vector", dimForce, vector::zero),
|
||||||
|
"calculated"
|
||||||
|
);
|
||||||
|
contact.contactPointForce(cPointForce);
|
||||||
|
cPointForce.write();
|
||||||
|
|
||||||
|
//- this is the actual (sigma&n)&n) on the contact patches
|
||||||
|
//- SHOULD THIS BE A REF TO A TMP...?
|
||||||
|
volScalarField cPressure = contact.contactPressure();
|
||||||
|
cPressure.write();
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
//****************************************************//
|
||||||
|
// Read the contact tol and max contact correctors
|
||||||
|
//****************************************************//
|
||||||
|
const IOdictionary& contactControl =
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"contactProperties",
|
||||||
|
U.time().constant(),
|
||||||
|
U.db(),
|
||||||
|
IOobject::MUST_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//- The frequnecy the conatct is corrected inside the momentum loop
|
||||||
|
int uEqnContactCorrFreq(readInt(contactControl.lookup("innerContactCorrectFreq")));
|
|
@ -0,0 +1,9 @@
|
||||||
|
//- how explicit component of sigma is to be calculated
|
||||||
|
word divDSigmaExpMethod(mesh.solutionDict().subDict("stressedFoam").lookup("divDSigmaExp"));
|
||||||
|
Info << divDSigmaExpMethod << " method chosen for calculation of DSigmaExp" << endl;
|
||||||
|
if(divDSigmaExpMethod != "standard" && divDSigmaExpMethod != "surface" && divDSigmaExpMethod != "decompose" && divDSigmaExpMethod != "laplacian")
|
||||||
|
{
|
||||||
|
FatalError << "divDSigmaExp method " << divDSigmaExpMethod << " not found!" << nl
|
||||||
|
<< "valid methods are:\nstandard\nsurface\ndecompose\nlaplacian"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
//- the method used to calculate the explicit component of sigma
|
||||||
|
word divDSigmaLargeStrainExpMethod(mesh.solutionDict().subDict("stressedFoam").lookup("divDSigmaLargeStrainExp"));
|
||||||
|
Info << "divDSigmaLargeStrainExp calculation method: " << divDSigmaLargeStrainExpMethod << endl;
|
||||||
|
if(divDSigmaLargeStrainExpMethod != "standard"
|
||||||
|
&& divDSigmaLargeStrainExpMethod != "surface")
|
||||||
|
{
|
||||||
|
FatalError << "divDSigmaLargeStrainExp method " << divDSigmaLargeStrainExpMethod << " not found!" << nl
|
||||||
|
<< "valid methods are:\nstandard\nsurface"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
//- the method used to interpolate in cell centre displacements to the vertices to move the mesh
|
||||||
|
word moveMeshMethod(mesh.solutionDict().subDict("stressedFoam").lookup("moveMeshMethod"));
|
||||||
|
Info << "Move Mesh method: " << moveMeshMethod << endl;
|
||||||
|
if(moveMeshMethod != "inverseDistance"
|
||||||
|
&& moveMeshMethod != "leastSquares")
|
||||||
|
{
|
||||||
|
FatalError << "moveMeshMethod " << moveMeshMethod << " not found!" << nl
|
||||||
|
<< "valid methods are:\ninvreseDistance\nleastSquares"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
const dictionary& stressControl =
|
||||||
|
mesh.solutionDict().subDict("stressedFoam");
|
||||||
|
|
||||||
|
int nCorr(readInt(stressControl.lookup("nCorrectors")));
|
||||||
|
scalar convergenceTolerance(readScalar(stressControl.lookup("DU")));
|
|
@ -0,0 +1,24 @@
|
||||||
|
//--------------------------------------------------//
|
||||||
|
//- rotate fields
|
||||||
|
//--------------------------------------------------//
|
||||||
|
{
|
||||||
|
Info << "Rotating fields" << endl;
|
||||||
|
|
||||||
|
F = I + DF;
|
||||||
|
|
||||||
|
U += DU;
|
||||||
|
|
||||||
|
epsilon += DEpsilon;
|
||||||
|
|
||||||
|
sigma += DSigma;
|
||||||
|
|
||||||
|
volTensorField Finv = inv(F);
|
||||||
|
|
||||||
|
J = det(F);
|
||||||
|
|
||||||
|
rho = rho/J;
|
||||||
|
|
||||||
|
epsilon = symm(Finv.T() & epsilon & Finv);
|
||||||
|
|
||||||
|
sigma = 1/J * symm(F & sigma & F.T());
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
// * * * * * * * * * * * * * * * * NET FORCES * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
vectorField netForces(mesh.boundary().size(), vector::zero);
|
||||||
|
|
||||||
|
Info << nl;
|
||||||
|
forAll(netForces, patchI)
|
||||||
|
{
|
||||||
|
netForces[patchI] = gSum(mesh.Sf().boundaryField()[patchI] & sigma.boundaryField()[patchI]);
|
||||||
|
|
||||||
|
Info << "patch " << mesh.boundary()[patchI].name() << " net force is "
|
||||||
|
<< netForces[patchI] << " N" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
@ -0,0 +1,36 @@
|
||||||
|
if (runTime.outputTime())
|
||||||
|
{
|
||||||
|
volScalarField epsilonEq
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"epsilonEq",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
sqrt((2.0/3.0)*magSqr(dev(epsilon)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< "Max epsilonEq = " << max(epsilonEq).value()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
volScalarField sigmaEq
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"sigmaEq",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
sqrt((3.0/2.0)*magSqr(dev(sigma)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< "Max sigmaEq = " << max(sigmaEq).value()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
runTime.write();
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
elasticContactSolidFoam.C
|
||||||
|
|
||||||
|
EXE = $(FOAM_USER_APPBIN)/elasticContactSolidFoam
|
|
@ -0,0 +1,14 @@
|
||||||
|
EXE_INC = \
|
||||||
|
-I$(FOAM_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/meshTools/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/lagrangian/basic/lnInclude \
|
||||||
|
-I../solidModels/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/VectorN/lnInclude
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) -lsolidModels \
|
||||||
|
-lfiniteVolume \
|
||||||
|
-llduSolvers \
|
||||||
|
-lmeshTools \
|
||||||
|
-llagrangian \
|
||||||
|
-lVectorN
|
|
@ -0,0 +1,15 @@
|
||||||
|
EXE_INC = \
|
||||||
|
// -I../../../myLibraries/finiteVolume/lnInclude \
|
||||||
|
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||||
|
-I../materialModels/lnInclude \
|
||||||
|
-I./solidInterface
|
||||||
|
// -I./patchToPatchInterpolation
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) \
|
||||||
|
// -lfiniteVolume_philipc \
|
||||||
|
// -lfiniteVolume \
|
||||||
|
-lmaterialModels_philipc \
|
||||||
|
-llduSolvers \
|
||||||
|
-lmeshTools
|
|
@ -0,0 +1,9 @@
|
||||||
|
EXE_INC = \
|
||||||
|
-I$(FOAM_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/dynamicMesh/lnInclude \
|
||||||
|
-I../materialModels/lnInclude
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) \
|
||||||
|
-lfiniteVolume \
|
||||||
|
-lmaterialModels_philipc
|
|
@ -0,0 +1,47 @@
|
||||||
|
if(divSigmaExpMethod == "standard")
|
||||||
|
{
|
||||||
|
divSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
mu*gradU.T() + lambda*(I*tr(gradU)) - (mu + lambda)*gradU,
|
||||||
|
"div(sigma)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divSigmaExpMethod == "surface")
|
||||||
|
{
|
||||||
|
divSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
muf*(mesh.Sf() & fvc::interpolate(gradU.T()))
|
||||||
|
+ lambdaf*(mesh.Sf() & I*fvc::interpolate(tr(gradU)))
|
||||||
|
- (muf + lambdaf)*(mesh.Sf() & fvc::interpolate(gradU))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divSigmaExpMethod == "decompose")
|
||||||
|
{
|
||||||
|
surfaceTensorField shearGradU =
|
||||||
|
((I - n*n)&fvc::interpolate(gradU));
|
||||||
|
|
||||||
|
divSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
mesh.magSf()
|
||||||
|
*(
|
||||||
|
- (muf + lambdaf)*(snGradU&(I - n*n))
|
||||||
|
+ lambdaf*tr(shearGradU&(I - n*n))*n
|
||||||
|
+ muf*(shearGradU&n)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divSigmaExpMethod == "expLaplacian")
|
||||||
|
{
|
||||||
|
divSigmaExp =
|
||||||
|
- fvc::laplacian(mu + lambda, U, "laplacian(U,U)")
|
||||||
|
+ fvc::div
|
||||||
|
(
|
||||||
|
mu*gradU.T()
|
||||||
|
+ lambda*(I*tr(gradU)),
|
||||||
|
"div(sigma)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalError << "divSigmaExp method " << divSigmaExpMethod << " not found!" << endl;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
epsilon = symm(gradU);
|
||||||
|
|
||||||
|
sigma = 2*mu*epsilon + lambda*(I*tr(epsilon));
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
scalarField magU = mag(U.internalField() - U.oldTime().internalField());
|
||||||
|
|
||||||
|
forAll(magU, cellI)
|
||||||
|
{
|
||||||
|
if (magU[cellI] < SMALL)
|
||||||
|
{
|
||||||
|
magU[cellI] = SMALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relativeResidual =
|
||||||
|
gMax
|
||||||
|
(
|
||||||
|
mag
|
||||||
|
(
|
||||||
|
U.internalField()
|
||||||
|
- U.prevIter().internalField()
|
||||||
|
)
|
||||||
|
/magU
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
correctGlobalFaceZoneMesh.H
|
||||||
|
|
||||||
|
When there is a globalFaceZone and the mesh is moved by interpolating U to the
|
||||||
|
vertices with volPointInterpolation, then there are two problems:
|
||||||
|
-some points on the patch with the faceZone are moved incorrectly, I think
|
||||||
|
it is because the faceZone has no U and causes an incorrect interpolation,
|
||||||
|
-the faceZones points not on the proc cells are not moved at all because
|
||||||
|
they have no U.
|
||||||
|
|
||||||
|
So the points on the patch with the faceZone need to be fixed and also all the
|
||||||
|
faceZone points need to be moved and synchronised so each proc has the same
|
||||||
|
full faceZone mesh.
|
||||||
|
|
||||||
|
The mapping of procs faceZone order of points to the master procs faceZone point
|
||||||
|
order is kept in procToGlobalFZmap, which is calculated at the start of the run
|
||||||
|
in the createGlobalToLocalFaceZonePointMap.H header file.
|
||||||
|
|
||||||
|
Note: DU is used for updated Lagrangian solver instead of U
|
||||||
|
|
||||||
|
philipc
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//- this is only needed in a parallel runs
|
||||||
|
if(Pstream::parRun())
|
||||||
|
{
|
||||||
|
//***** FIX INCORRECT POINT ON PATCHES WITH FACEZONE *****//
|
||||||
|
contactPatchPairList& contacts = contact;
|
||||||
|
|
||||||
|
forAll(contacts, contactI)
|
||||||
|
{
|
||||||
|
label masterID = contacts[contactI].masterPatch().index();
|
||||||
|
label slaveID = contacts[contactI].slavePatch().index();
|
||||||
|
|
||||||
|
primitivePatchInterpolation masterInterpolator
|
||||||
|
(mesh.boundaryMesh()[masterID]);
|
||||||
|
primitivePatchInterpolation slaveInterpolator
|
||||||
|
(mesh.boundaryMesh()[slaveID]);
|
||||||
|
|
||||||
|
//- U must be interpolated to the vertices, this ignores the faceZone
|
||||||
|
//- points with no U (unlike volPointInterpolation)
|
||||||
|
vectorField correctMasterPointU =
|
||||||
|
masterInterpolator.faceToPointInterpolate<vector>
|
||||||
|
(
|
||||||
|
U.boundaryField()[masterID]
|
||||||
|
);
|
||||||
|
vectorField correctSlavePointU =
|
||||||
|
slaveInterpolator.faceToPointInterpolate<vector>
|
||||||
|
(
|
||||||
|
U.boundaryField()[slaveID]
|
||||||
|
);
|
||||||
|
|
||||||
|
vectorField oldMasterPoints =
|
||||||
|
mesh.boundaryMesh()[masterID].localPoints();
|
||||||
|
vectorField oldSlavePoints =
|
||||||
|
mesh.boundaryMesh()[slaveID].localPoints();
|
||||||
|
|
||||||
|
labelList masterPointLabels =
|
||||||
|
mesh.boundaryMesh()[masterID].meshPoints();
|
||||||
|
labelList slavePointLabels =
|
||||||
|
mesh.boundaryMesh()[slaveID].meshPoints();
|
||||||
|
|
||||||
|
//- correct the patch newPoints
|
||||||
|
forAll(masterPointLabels, pointI)
|
||||||
|
{
|
||||||
|
label pointGlobalLabel = masterPointLabels[pointI];
|
||||||
|
newPoints[pointGlobalLabel] =
|
||||||
|
oldMasterPoints[pointI]
|
||||||
|
+
|
||||||
|
correctMasterPointU[pointI];
|
||||||
|
}
|
||||||
|
forAll(slavePointLabels, pointI)
|
||||||
|
{
|
||||||
|
label pointGlobalLabel = slavePointLabels[pointI];
|
||||||
|
newPoints[pointGlobalLabel] =
|
||||||
|
oldSlavePoints[pointI]
|
||||||
|
+
|
||||||
|
correctSlavePointU[pointI];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//***** NOW FIX AND SYNCHRONISE ALL THE FACEZONE POINTS *****//
|
||||||
|
|
||||||
|
forAll(mesh.faceZones(), faceZoneI)
|
||||||
|
{
|
||||||
|
//- find the patch corresponding to this faceZone
|
||||||
|
//- assuming that the FZ is called <patch_name>FaceZone
|
||||||
|
string faceZoneName = mesh.faceZones().names()[faceZoneI];
|
||||||
|
//- remove the string FaceZone from the end of the face zone name to get the patch name
|
||||||
|
string patchName = faceZoneName.substr(0, (faceZoneName.size()-8));
|
||||||
|
label patchID = mesh.boundaryMesh().findPatchID(patchName);
|
||||||
|
if(patchID == -1)
|
||||||
|
{
|
||||||
|
FatalError << "Patch " << patchName << " not found corresponding for faceZone"
|
||||||
|
<< faceZoneName << exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
vectorField globalFZpoints =
|
||||||
|
mesh.faceZones()[faceZoneI]().localPoints();
|
||||||
|
|
||||||
|
//- new points for the face zone
|
||||||
|
vectorField globalFZnewPoints(globalFZpoints.size(), vector::zero);
|
||||||
|
|
||||||
|
//- inter-proc points are shared by multiple procs
|
||||||
|
//- pointNumProc is the number of procs which a point lies on
|
||||||
|
scalarField pointNumProcs(globalFZpoints.size(), 0.0);
|
||||||
|
|
||||||
|
forAll(globalFZnewPoints, globalPointI)
|
||||||
|
{
|
||||||
|
label localPoint = procToGlobalFZmap[faceZoneI][globalPointI];
|
||||||
|
|
||||||
|
//if(localPoint < mesh.boundaryMesh()[patchID].localPoints().size())
|
||||||
|
if(pointOnLocalProcPatch[faceZoneI][localPoint])
|
||||||
|
{
|
||||||
|
label procPoint =
|
||||||
|
mesh.faceZones()[faceZoneI]().meshPoints()[localPoint];
|
||||||
|
globalFZnewPoints[globalPointI] =
|
||||||
|
newPoints[procPoint];
|
||||||
|
pointNumProcs[globalPointI] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce(globalFZnewPoints, sumOp<vectorField>());
|
||||||
|
reduce(pointNumProcs, sumOp<scalarField>());
|
||||||
|
|
||||||
|
//- now average the newPoints between all procs
|
||||||
|
if(min(pointNumProcs) < 1)
|
||||||
|
{
|
||||||
|
FatalError << "pointNumProc has not been set for all points" << exit(FatalError);
|
||||||
|
}
|
||||||
|
globalFZnewPoints /= pointNumProcs;
|
||||||
|
|
||||||
|
//- the globalFZnewPoints now contains the correct FZ new points in
|
||||||
|
//- a global order, now convert them back into the local proc order
|
||||||
|
|
||||||
|
vectorField procFZnewPoints(globalFZpoints.size(), vector::zero);
|
||||||
|
|
||||||
|
forAll(globalFZnewPoints, globalPointI)
|
||||||
|
{
|
||||||
|
label localPoint = procToGlobalFZmap[faceZoneI][globalPointI];
|
||||||
|
|
||||||
|
procFZnewPoints[localPoint] =
|
||||||
|
globalFZnewPoints[globalPointI];
|
||||||
|
}
|
||||||
|
|
||||||
|
//- now fix the newPoints points on the globalFaceZones
|
||||||
|
labelList procFZmeshPoints =
|
||||||
|
mesh.faceZones()[faceZoneI]().meshPoints();
|
||||||
|
|
||||||
|
forAll(procFZmeshPoints, pointI)
|
||||||
|
{
|
||||||
|
label procPoint = procFZmeshPoints[pointI];
|
||||||
|
newPoints[procPoint] =
|
||||||
|
procFZnewPoints[pointI];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
Info<< "Reading field U\n" << endl;
|
||||||
|
volVectorField U
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"U",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::MUST_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh
|
||||||
|
);
|
||||||
|
|
||||||
|
volTensorField gradU = fvc::grad(U);
|
||||||
|
surfaceVectorField snGradU = fvc::snGrad(U);
|
||||||
|
|
||||||
|
volVectorField V
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"V",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
fvc::ddt(U)
|
||||||
|
);
|
||||||
|
|
||||||
|
volTensorField gradV = fvc::ddt(gradU);
|
||||||
|
surfaceVectorField snGradV = (snGradU - snGradU.oldTime())/runTime.deltaT();
|
||||||
|
|
||||||
|
volSymmTensorField epsilon
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"epsilon",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimless, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField sigma
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"sigma",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimForce/dimArea, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volVectorField divSigmaExp
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"divSigmaExp",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedVector("zero", dimensionSet(1,-2,-2,0,0,0,0), vector::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// read rheology properties
|
||||||
|
rheologyModel rheology(sigma);
|
||||||
|
|
||||||
|
volScalarField rho = rheology.rho();
|
||||||
|
|
||||||
|
volScalarField mu = rheology.mu();
|
||||||
|
volScalarField lambda = rheology.lambda();
|
||||||
|
surfaceScalarField muf = fvc::interpolate(mu, "mu");
|
||||||
|
surfaceScalarField lambdaf = fvc::interpolate(lambda, "lambda");
|
||||||
|
|
||||||
|
surfaceVectorField n = mesh.Sf()/mesh.magSf();
|
||||||
|
|
||||||
|
|
||||||
|
//- create contact problem
|
||||||
|
contactProblem contact(U);
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
createGlobalToLocalFaceZonePointMap.H
|
||||||
|
|
||||||
|
I could not figure out the order of the points on a globalFaceZone, they is a
|
||||||
|
different order for each processor where the processors own points come first.
|
||||||
|
|
||||||
|
So I decide that the master proc order is the global order and I find the map
|
||||||
|
from this order to each proc order here by just commparing actual point
|
||||||
|
coordinates.
|
||||||
|
|
||||||
|
This map is then used to correct and synchronise the globalFaceZone points on
|
||||||
|
all the procs when the mesh is moved, in header file correctGlobalFaceZoneMesh.H.
|
||||||
|
|
||||||
|
philipc
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//- procToGlobalFZmap is a map from the current proc faceZone point order to the
|
||||||
|
//- master proc point order
|
||||||
|
//- these are read if present to allow restarting of contact cases
|
||||||
|
IOList<labelList> procToGlobalFZmap
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"procToGlobalFZmap",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh.faceZones().size()
|
||||||
|
);
|
||||||
|
|
||||||
|
IOList<labelList> pointOnLocalProcPatch
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointOnLocalProcPatch",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh.faceZones().size()
|
||||||
|
);
|
||||||
|
|
||||||
|
//- if they have been read then don't recalculate it
|
||||||
|
bool globalFaceZoneMappingSet = false;
|
||||||
|
if(gMax(procToGlobalFZmap[0]) > 0 && gMax(pointOnLocalProcPatch[0]) > 0)
|
||||||
|
{
|
||||||
|
Info << "Reading procToGlobalFZmap and pointOnLocalProcPatch allowing restart of contact cases"
|
||||||
|
<< endl;
|
||||||
|
globalFaceZoneMappingSet = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info << "procToGlobalFZmap and pointOnLocalProcPatch will be calculated as it has not been found" << nl
|
||||||
|
<< "this message should only appear starting a new analysis" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- this is only needed in a parallel runs
|
||||||
|
if(Pstream::parRun())
|
||||||
|
{
|
||||||
|
if(!globalFaceZoneMappingSet)
|
||||||
|
{
|
||||||
|
forAll(mesh.faceZones(), faceZoneI)
|
||||||
|
{
|
||||||
|
vectorField globalFZpoints = mesh.faceZones()[faceZoneI]().localPoints();
|
||||||
|
|
||||||
|
procToGlobalFZmap[faceZoneI].setSize(globalFZpoints.size(), 0);
|
||||||
|
|
||||||
|
//- set all slave points to zero because only the master order is used
|
||||||
|
if(!Pstream::master())
|
||||||
|
globalFZpoints *= 0.0;
|
||||||
|
|
||||||
|
//- pass points to all procs
|
||||||
|
reduce(globalFZpoints, sumOp<vectorField>());
|
||||||
|
|
||||||
|
|
||||||
|
//- now every proc has the master's list of FZ points
|
||||||
|
//- every proc must now find the mapping from their local FZpoints to
|
||||||
|
//- the globalFZpoints
|
||||||
|
|
||||||
|
vectorField procFZpoints = mesh.faceZones()[faceZoneI]().localPoints();
|
||||||
|
|
||||||
|
forAll(globalFZpoints, globalPointI)
|
||||||
|
{
|
||||||
|
forAll(procFZpoints, procPointI)
|
||||||
|
{
|
||||||
|
if(procFZpoints[procPointI] == globalFZpoints[globalPointI])
|
||||||
|
{
|
||||||
|
procToGlobalFZmap[faceZoneI][globalPointI] = procPointI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//- procToGlobalFZmap now contains the local FZpoint label for each
|
||||||
|
//- global FZ point label - for each faceZone
|
||||||
|
|
||||||
|
//- check what points are on the current proc patch
|
||||||
|
pointOnLocalProcPatch[faceZoneI].setSize(globalFZpoints.size(), 0);
|
||||||
|
|
||||||
|
//- find corresponding patch
|
||||||
|
string faceZoneName = mesh.faceZones().names()[faceZoneI];
|
||||||
|
//- remove the string FaceZone from the end of the face zone name to get the patch name
|
||||||
|
string patchName = faceZoneName.substr(0, (faceZoneName.size()-8));
|
||||||
|
label patchID = mesh.boundaryMesh().findPatchID(patchName);
|
||||||
|
if(patchID == -1)
|
||||||
|
{
|
||||||
|
FatalError << "Patch " << patchName << " not found corresponding for faceZone"
|
||||||
|
<< faceZoneName << exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
forAll(mesh.faceZones()[faceZoneI]().localPoints(), fzpi)
|
||||||
|
{
|
||||||
|
forAll(mesh.boundaryMesh()[patchID].localPoints(), pi)
|
||||||
|
{
|
||||||
|
if(mesh.faceZones()[faceZoneI]().localPoints()[fzpi] == mesh.boundaryMesh()[patchID].localPoints()[pi])
|
||||||
|
{
|
||||||
|
pointOnLocalProcPatch[faceZoneI][fzpi] = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} //- end if(!globalFaceZoneMappingSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
//- write to disk to allow restart of cases
|
||||||
|
//- because it is not possible to calculate the
|
||||||
|
//- mapping after the meshes have moved
|
||||||
|
if(!globalFaceZoneMappingSet)
|
||||||
|
{
|
||||||
|
procToGlobalFZmap.write();
|
||||||
|
pointOnLocalProcPatch.write();
|
||||||
|
}
|
|
@ -0,0 +1,206 @@
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2004-2007 Hrvoje Jasak
|
||||||
|
\\/ 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
|
||||||
|
|
||||||
|
Application
|
||||||
|
elasticContactSolidFoam
|
||||||
|
|
||||||
|
Description
|
||||||
|
Transient/steady-state segregated finite-volume solver for small strain
|
||||||
|
elastic solid bodies in contact, using an total strain total Lagrangian
|
||||||
|
approach.
|
||||||
|
|
||||||
|
Works in parallel but mesh.movePoints sometimes fails for some unknown
|
||||||
|
reason depending on the decomposition.
|
||||||
|
|
||||||
|
Solves for the displacement increment vector field DU, also generating the
|
||||||
|
stress tensor field sigma.
|
||||||
|
|
||||||
|
It is only for frictionless contact, friction not implemented yet.
|
||||||
|
|
||||||
|
Author
|
||||||
|
Philip Cardiff
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "fvCFD.H"
|
||||||
|
#include "rheologyModel.H"
|
||||||
|
#include "contactProblem.H"
|
||||||
|
|
||||||
|
#include "volPointInterpolation.H"
|
||||||
|
#include "pointPatchInterpolation.H"
|
||||||
|
#include "primitivePatchInterpolation.H"
|
||||||
|
#include "fixedValuePointPatchFields.H"
|
||||||
|
#include "pointFields.H"
|
||||||
|
#include "pointMesh.H"
|
||||||
|
#include "pointBoundaryMesh.H"
|
||||||
|
#include "primitivePatchInterpolation.H"
|
||||||
|
#include "twoDPointCorrector.H"
|
||||||
|
#include "plane.H"
|
||||||
|
#include "meshSearch.H"
|
||||||
|
//#include "leastSquaresVolPointInterpolation.H"
|
||||||
|
|
||||||
|
#include "OFstream.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
# include "setRootCase.H"
|
||||||
|
|
||||||
|
# include "createTime.H"
|
||||||
|
|
||||||
|
# include "createMesh.H"
|
||||||
|
|
||||||
|
# include "createFields.H"
|
||||||
|
|
||||||
|
# include "readDivSigmaExpMethod.H"
|
||||||
|
|
||||||
|
# include "createGlobalToLocalFaceZonePointMap.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Info<< "\nStarting time loop\n" << endl;
|
||||||
|
|
||||||
|
for (runTime++; !runTime.end(); runTime++)
|
||||||
|
{
|
||||||
|
Info<< "Time: " << runTime.timeName() << endl;
|
||||||
|
|
||||||
|
# include "readContactControls.H"
|
||||||
|
|
||||||
|
# include "readStressedFoamControls.H"
|
||||||
|
|
||||||
|
//-- for moving the mesh and then back again
|
||||||
|
vectorField oldMeshPoints = mesh.allPoints();
|
||||||
|
|
||||||
|
int iCorr = 0;
|
||||||
|
lduMatrix::solverPerformance solverPerf;
|
||||||
|
word solverName;
|
||||||
|
lduMatrix::debug = 0;
|
||||||
|
scalar residual = GREAT;
|
||||||
|
scalar initialResidual = 0;
|
||||||
|
scalar relativeResidual = GREAT;
|
||||||
|
|
||||||
|
//- Predictor step
|
||||||
|
if (predictor)
|
||||||
|
{
|
||||||
|
Info << "\nPredicting U, gradU and snGradU based on V, gradV and snGradV\n" << endl;
|
||||||
|
U += V*runTime.deltaT();
|
||||||
|
gradU += gradV*runTime.deltaT();
|
||||||
|
snGradU += snGradV*runTime.deltaT();
|
||||||
|
}
|
||||||
|
|
||||||
|
do //- start of momentum loop
|
||||||
|
{
|
||||||
|
U.storePrevIter();
|
||||||
|
|
||||||
|
//- correct the contact boundaries
|
||||||
|
if(iCorr % uEqnContactCorrFreq == 0)
|
||||||
|
{
|
||||||
|
Info << "\t\tCorrecting contact in the momentum loop "
|
||||||
|
<< "iteration: " << iCorr
|
||||||
|
<< ", residual: " << residual
|
||||||
|
<< endl;
|
||||||
|
//# include "moveMeshLeastSquares.H"
|
||||||
|
# include "moveSolidMesh.H"
|
||||||
|
contact.correct();
|
||||||
|
mesh.movePoints(oldMeshPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
# include "calculateDivSigmaExp.H"
|
||||||
|
|
||||||
|
fvVectorMatrix UEqn
|
||||||
|
(
|
||||||
|
fvm::d2dt2(rho, U)
|
||||||
|
==
|
||||||
|
fvm::laplacian(2*mu + lambda, U, "laplacian(DU,U)")
|
||||||
|
+ divSigmaExp
|
||||||
|
);
|
||||||
|
|
||||||
|
solverPerf = UEqn.solve();
|
||||||
|
|
||||||
|
U.relax();
|
||||||
|
|
||||||
|
solverName = solverPerf.solverName();
|
||||||
|
|
||||||
|
gradU = fvc::grad(U);
|
||||||
|
snGradU = fvc::snGrad(U);
|
||||||
|
|
||||||
|
residual = solverPerf.initialResidual();
|
||||||
|
|
||||||
|
if(iCorr == 0)
|
||||||
|
{
|
||||||
|
initialResidual = solverPerf.initialResidual();
|
||||||
|
}
|
||||||
|
|
||||||
|
# include "calculateRelativeResidual.H"
|
||||||
|
|
||||||
|
Info << "\tTime " << runTime.value()
|
||||||
|
<< ", Corrector " << iCorr
|
||||||
|
<< ", Solving for " << U.name()
|
||||||
|
<< " using " << solverPerf.solverName()
|
||||||
|
<< ", residual = " << solverPerf.initialResidual()
|
||||||
|
<< ", relative residual = " << relativeResidual << endl;
|
||||||
|
} //- end of momentum loop
|
||||||
|
while
|
||||||
|
(
|
||||||
|
//relativeResidual > convergenceTolerance
|
||||||
|
residual > convergenceTolerance
|
||||||
|
&&
|
||||||
|
++iCorr < nCorr
|
||||||
|
);
|
||||||
|
|
||||||
|
// Print out info per contact iteration
|
||||||
|
Info << "\t\tSolving for " << U.name()
|
||||||
|
<< " using " << solverName
|
||||||
|
<< ", Initial residual = " << initialResidual
|
||||||
|
<< ", Final residual = " << solverPerf.initialResidual()
|
||||||
|
<< ", No outer iterations " << iCorr << endl;
|
||||||
|
|
||||||
|
lduMatrix::debug = 1;
|
||||||
|
|
||||||
|
V = fvc::ddt(U);
|
||||||
|
gradV = fvc::ddt(gradU);
|
||||||
|
snGradV = (snGradU - snGradU.oldTime())/runTime.deltaT();
|
||||||
|
|
||||||
|
# include "calculateEpsilonSigma.H"
|
||||||
|
|
||||||
|
# include "writeFields.H"
|
||||||
|
|
||||||
|
//# include "moveMeshLeastSquares.H"
|
||||||
|
//# include "moveSolidMesh.H"
|
||||||
|
//# include "printContactResults.H"
|
||||||
|
//mesh.movePoints(oldMeshPoints);
|
||||||
|
|
||||||
|
Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
|
||||||
|
<< " ClockTime = " << runTime.elapsedClockTime() << " s"
|
||||||
|
<< endl << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< "End\n" << endl;
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
|
@ -0,0 +1,56 @@
|
||||||
|
//--------------------------------------------------//
|
||||||
|
//- move mesh
|
||||||
|
//--------------------------------------------------//
|
||||||
|
if(min(J.internalField()) > 0)
|
||||||
|
{
|
||||||
|
Info << "Moving mesh using least squares interpolation" << endl;
|
||||||
|
|
||||||
|
leastSquaresVolPointInterpolation pointInterpolation(mesh);
|
||||||
|
|
||||||
|
// Create point mesh
|
||||||
|
pointMesh pMesh(mesh);
|
||||||
|
|
||||||
|
wordList types
|
||||||
|
(
|
||||||
|
pMesh.boundary().size(),
|
||||||
|
calculatedFvPatchVectorField::typeName
|
||||||
|
);
|
||||||
|
|
||||||
|
pointVectorField pointDU
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointDU",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedVector("zero", dimLength, vector::zero),
|
||||||
|
types
|
||||||
|
);
|
||||||
|
|
||||||
|
pointInterpolation.interpolate(DU, pointDU);
|
||||||
|
|
||||||
|
const vectorField& pointDUI =
|
||||||
|
pointDU.internalField();
|
||||||
|
|
||||||
|
//- Move mesh
|
||||||
|
vectorField newPoints = mesh.allPoints();
|
||||||
|
|
||||||
|
forAll (pointDUI, pointI)
|
||||||
|
{
|
||||||
|
newPoints[pointI] += pointDUI[pointI];
|
||||||
|
}
|
||||||
|
|
||||||
|
twoDPointCorrector twoDCorrector(mesh);
|
||||||
|
twoDCorrector.correctPoints(newPoints);
|
||||||
|
mesh.movePoints(newPoints);
|
||||||
|
mesh.V00();
|
||||||
|
mesh.moving(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalErrorIn(args.executable())
|
||||||
|
<< "Negative Jacobian"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
// Create point interpolation
|
||||||
|
volPointInterpolation pointInterpolation(mesh);
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate mesh points displacement
|
||||||
|
pointVectorField pointU = pointInterpolation.interpolate(U);
|
||||||
|
|
||||||
|
// const vectorField& pointUI = pointU.internalField();
|
||||||
|
vectorField pointUI = pointU.internalField();
|
||||||
|
|
||||||
|
|
||||||
|
// Move mesh
|
||||||
|
vectorField newPoints = mesh.allPoints();
|
||||||
|
|
||||||
|
forAll (pointUI, pointI)
|
||||||
|
{
|
||||||
|
newPoints[pointI] += pointUI[pointI];
|
||||||
|
}
|
||||||
|
|
||||||
|
# include "correctGlobalFaceZoneMesh.H"
|
||||||
|
|
||||||
|
twoDPointCorrector twoDCorrector(mesh);
|
||||||
|
twoDCorrector.correctPoints(newPoints);
|
||||||
|
|
||||||
|
mesh.movePoints(newPoints);
|
||||||
|
// pMesh.movePoints(newPoints);
|
||||||
|
mesh.V00();
|
||||||
|
mesh.moving(false);
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
if (runTime.outputTime())
|
||||||
|
{
|
||||||
|
// FAILS IN PARALLEL - FIX
|
||||||
|
// Info << "Print contact area" << endl;
|
||||||
|
//volScalarField ca = contact.contactArea();
|
||||||
|
//ca.write();
|
||||||
|
|
||||||
|
//-------------------------------------------------------------//
|
||||||
|
// I couldn't get tmp to return the pointScalarField correctly //
|
||||||
|
// so I had to make the pointScalarField here and pass it to //
|
||||||
|
// contactGapPoints and pointContactForce to populate //
|
||||||
|
//-------------------------------------------------------------//
|
||||||
|
//This is the point distance for each contact vertex
|
||||||
|
pointScalarField cGapPoints
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointContactGap",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedScalar("scalar", dimLength, 0.0),
|
||||||
|
"calculated"
|
||||||
|
);
|
||||||
|
|
||||||
|
contact.contactGapPoints(cGapPoints);
|
||||||
|
cGapPoints.write();
|
||||||
|
|
||||||
|
|
||||||
|
//- This is the point distance for each contact vertex
|
||||||
|
pointVectorField cPointForce
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"pointContactForce",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
pMesh,
|
||||||
|
dimensionedVector("vector", dimForce, vector::zero),
|
||||||
|
"calculated"
|
||||||
|
);
|
||||||
|
contact.contactPointForce(cPointForce);
|
||||||
|
cPointForce.write();
|
||||||
|
|
||||||
|
//- this is the actual (sigma&n)&n) on the contact patches
|
||||||
|
//- SHOULD THIS BE A REF TO A TMP...?
|
||||||
|
volScalarField cPressure = contact.contactPressure();
|
||||||
|
cPressure.write();
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
//****************************************************//
|
||||||
|
// Read the contact tol and max contact correctors
|
||||||
|
//****************************************************//
|
||||||
|
const IOdictionary& contactControl =
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"contactProperties",
|
||||||
|
U.time().constant(),
|
||||||
|
U.db(),
|
||||||
|
IOobject::MUST_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//- The frequnecy the conatct is corrected inside the momentum loop
|
||||||
|
int uEqnContactCorrFreq(readInt(contactControl.lookup("innerContactCorrectFreq")));
|
|
@ -0,0 +1,9 @@
|
||||||
|
//- how explicit component of sigma is to be calculated
|
||||||
|
word divSigmaExpMethod(mesh.solutionDict().subDict("stressedFoam").lookup("divSigmaExp"));
|
||||||
|
Info << divSigmaExpMethod << " method chosen for calculation of sigmaExp" << endl;
|
||||||
|
if(divSigmaExpMethod != "standard" && divSigmaExpMethod != "surface" && divSigmaExpMethod != "decompose" && divSigmaExpMethod != "laplacian")
|
||||||
|
{
|
||||||
|
FatalError << "divSigmaExp method " << divSigmaExpMethod << " not found!" << nl
|
||||||
|
<< "valid methods are:\nstandard\nsurface\ndecompose\nlaplacian"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
const dictionary& stressControl =
|
||||||
|
mesh.solutionDict().subDict("stressedFoam");
|
||||||
|
|
||||||
|
int nCorr(readInt(stressControl.lookup("nCorrectors")));
|
||||||
|
scalar convergenceTolerance(readScalar(stressControl.lookup("U")));
|
||||||
|
|
||||||
|
Switch predictor(stressControl.lookup("predictor"));
|
|
@ -0,0 +1,14 @@
|
||||||
|
// * * * * * * * * * * * * * * * * NET FORCES * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
vectorField netForces(mesh.boundary().size(), vector::zero);
|
||||||
|
|
||||||
|
Info << nl;
|
||||||
|
forAll(netForces, patchI)
|
||||||
|
{
|
||||||
|
netForces[patchI] = gSum(mesh.Sf().boundaryField()[patchI] & sigma.boundaryField()[patchI]);
|
||||||
|
|
||||||
|
Info << "patch\t" << mesh.boundary()[patchI].name() << "\t\tnet force is\t"
|
||||||
|
<< netForces[patchI] << " N" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
@ -0,0 +1,36 @@
|
||||||
|
if (runTime.outputTime())
|
||||||
|
{
|
||||||
|
volScalarField epsilonEq
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"epsilonEq",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
sqrt((2.0/3.0)*magSqr(dev(epsilon)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< "Max epsilonEq = " << max(epsilonEq).value()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
volScalarField sigmaEq
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"sigmaEq",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
sqrt((3.0/2.0)*magSqr(dev(sigma)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< "Max sigmaEq = " << max(sigmaEq).value()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
runTime.write();
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
elasticGravitySolidFoam.C
|
||||||
|
|
||||||
|
EXE = $(FOAM_USER_APPBIN)/elasticGravitySolidFoam
|
|
@ -0,0 +1,12 @@
|
||||||
|
EXE_INC = \
|
||||||
|
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/meshTools/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/lagrangian/basic/lnInclude \
|
||||||
|
-I../solidModels/lnInclude
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) -lsolidModels \
|
||||||
|
-lfiniteVolume \
|
||||||
|
-llduSolvers \
|
||||||
|
-lmeshTools \
|
||||||
|
-llagrangian
|
|
@ -0,0 +1,47 @@
|
||||||
|
if(divSigmaExpMethod == "standard")
|
||||||
|
{
|
||||||
|
divSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
mu*gradU.T() + lambda*(I*tr(gradU)) - (mu + lambda)*gradU,
|
||||||
|
"div(sigma)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divSigmaExpMethod == "surface")
|
||||||
|
{
|
||||||
|
divSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
muf*(mesh.Sf() & fvc::interpolate(gradU.T()))
|
||||||
|
+ lambdaf*(mesh.Sf() & I*fvc::interpolate(tr(gradU)))
|
||||||
|
- (muf + lambdaf)*(mesh.Sf() & fvc::interpolate(gradU))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divSigmaExpMethod == "decompose")
|
||||||
|
{
|
||||||
|
surfaceTensorField shearGradU =
|
||||||
|
((I - n*n)&fvc::interpolate(gradU));
|
||||||
|
|
||||||
|
divSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
mesh.magSf()
|
||||||
|
*(
|
||||||
|
- (muf + lambdaf)*(fvc::snGrad(U)&(I - n*n))
|
||||||
|
+ lambdaf*tr(shearGradU&(I - n*n))*n
|
||||||
|
+ muf*(shearGradU&n)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divSigmaExpMethod == "expLaplacian")
|
||||||
|
{
|
||||||
|
divSigmaExp =
|
||||||
|
- fvc::laplacian(mu + lambda, U, "laplacian(DU,U)")
|
||||||
|
+ fvc::div
|
||||||
|
(
|
||||||
|
mu*gradU.T()
|
||||||
|
+ lambda*(I*tr(gradU)),
|
||||||
|
"div(sigma)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalError << "divSigmaExp method " << divSigmaExpMethod << " not found!" << endl;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
epsilon = symm(gradU);
|
||||||
|
|
||||||
|
sigma = 2*mu*epsilon + lambda*(I*tr(epsilon));
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
scalarField magU = mag(U.internalField() - U.oldTime().internalField());
|
||||||
|
|
||||||
|
forAll(magU, cellI)
|
||||||
|
{
|
||||||
|
if (magU[cellI] < SMALL)
|
||||||
|
{
|
||||||
|
magU[cellI] = SMALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relativeResidual =
|
||||||
|
gMax
|
||||||
|
(
|
||||||
|
mag
|
||||||
|
(
|
||||||
|
U.internalField()
|
||||||
|
- U.prevIter().internalField()
|
||||||
|
)
|
||||||
|
/magU
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
Info<< "Reading field U\n" << endl;
|
||||||
|
volVectorField U
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"U",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::MUST_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh
|
||||||
|
);
|
||||||
|
|
||||||
|
volTensorField gradU = fvc::grad(U);
|
||||||
|
|
||||||
|
volSymmTensorField epsilon
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"epsilon",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimless, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField sigma
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"sigma",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimForce/dimArea, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volVectorField divSigmaExp
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"divSigmaExp",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedVector("zero", dimensionSet(1,-2,-2,0,0,0,0), vector::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
rheologyModel rheology(sigma);
|
||||||
|
|
||||||
|
volScalarField rho = rheology.rho();
|
||||||
|
|
||||||
|
volScalarField mu = rheology.mu();
|
||||||
|
volScalarField lambda = rheology.lambda();
|
||||||
|
surfaceScalarField muf = fvc::interpolate(mu, "mu");
|
||||||
|
surfaceScalarField lambdaf = fvc::interpolate(lambda, "lambda");
|
||||||
|
|
||||||
|
surfaceVectorField n = mesh.Sf()/mesh.magSf();
|
|
@ -0,0 +1,24 @@
|
||||||
|
Switch solidInterfaceCorr(false);
|
||||||
|
|
||||||
|
solidInterface* solidInterfacePtr(NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
const dictionary& stressControl =
|
||||||
|
mesh.solutionDict().subDict("stressedFoam");
|
||||||
|
|
||||||
|
solidInterfaceCorr = Switch(stressControl.lookup("solidInterface"));
|
||||||
|
|
||||||
|
if(solidInterfaceCorr)
|
||||||
|
{
|
||||||
|
Info << "Creating solid interface correction" << endl;
|
||||||
|
solidInterfacePtr = new solidInterface(mesh, rheology);
|
||||||
|
solidInterfacePtr->modifyProperties(muf, lambdaf);
|
||||||
|
|
||||||
|
//- solidInterface needs muf and lambdaf to be used for divSigmaExp
|
||||||
|
if(divSigmaExpMethod != "surface" && divSigmaExpMethod != "decompose")
|
||||||
|
{
|
||||||
|
FatalError << "divSigmaExp must be decompose or surface when solidInterface is on"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2004-2007 Hrvoje Jasak
|
||||||
|
\\/ 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
|
||||||
|
|
||||||
|
Application
|
||||||
|
elasticGravitySolidFoam
|
||||||
|
|
||||||
|
Description
|
||||||
|
Transient/steady-state segregated finite-volume solver for small strain
|
||||||
|
elastic solid bodies.
|
||||||
|
|
||||||
|
Displacement field U is solved for using a total Lagrangian approach,
|
||||||
|
also generating the strain tensor field epsilon and stress tensor
|
||||||
|
field sigma.
|
||||||
|
|
||||||
|
With optional multi-material solid interface correction ensuring
|
||||||
|
correct tractions on multi-material interfaces.
|
||||||
|
|
||||||
|
Graivty added as a body force.
|
||||||
|
|
||||||
|
Author
|
||||||
|
Philip Cardiff
|
||||||
|
multi-material by Tukovic et al. 2012
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "fvCFD.H"
|
||||||
|
#include "rheologyModel.H"
|
||||||
|
#include "solidInterface.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
# include "setRootCase.H"
|
||||||
|
|
||||||
|
# include "createTime.H"
|
||||||
|
|
||||||
|
# include "createMesh.H"
|
||||||
|
|
||||||
|
# include "createFields.H"
|
||||||
|
|
||||||
|
# include "readDivSigmaExpMethod.H"
|
||||||
|
|
||||||
|
# include "createSolidInterface.H"
|
||||||
|
|
||||||
|
# include "readGravity.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Info<< "\nCalculating displacement field\n" << endl;
|
||||||
|
|
||||||
|
while(runTime.loop())
|
||||||
|
{
|
||||||
|
Info<< "Time: " << runTime.timeName() << nl << endl;
|
||||||
|
|
||||||
|
# include "readStressedFoamControls.H"
|
||||||
|
|
||||||
|
int iCorr = 0;
|
||||||
|
scalar initialResidual = 0;
|
||||||
|
lduMatrix::solverPerformance solverPerf;
|
||||||
|
scalar relativeResidual = GREAT;
|
||||||
|
|
||||||
|
lduMatrix::debug=0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
U.storePrevIter();
|
||||||
|
|
||||||
|
# include "calculateDivSigmaExp.H"
|
||||||
|
|
||||||
|
//- linear momentum equation
|
||||||
|
fvVectorMatrix UEqn
|
||||||
|
(
|
||||||
|
fvm::d2dt2(rho, U)
|
||||||
|
==
|
||||||
|
fvm::laplacian(2*muf + lambdaf, U, "laplacian(DU,U)")
|
||||||
|
+ divSigmaExp
|
||||||
|
+ rho*gravity
|
||||||
|
);
|
||||||
|
|
||||||
|
if(solidInterfaceCorr)
|
||||||
|
{
|
||||||
|
solidInterfacePtr->correct(UEqn);
|
||||||
|
}
|
||||||
|
|
||||||
|
solverPerf = UEqn.solve();
|
||||||
|
|
||||||
|
if(iCorr == 0)
|
||||||
|
{
|
||||||
|
initialResidual = solverPerf.initialResidual();
|
||||||
|
}
|
||||||
|
|
||||||
|
U.relax();
|
||||||
|
|
||||||
|
if(solidInterfaceCorr)
|
||||||
|
{
|
||||||
|
gradU = solidInterfacePtr->grad(U);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gradU = fvc::grad(U);
|
||||||
|
}
|
||||||
|
|
||||||
|
# include "calculateRelativeResidual.H"
|
||||||
|
|
||||||
|
Info << "\tTime " << runTime.value()
|
||||||
|
<< ", Corrector " << iCorr
|
||||||
|
<< ", Solving for " << U.name()
|
||||||
|
<< " using " << solverPerf.solverName()
|
||||||
|
<< ", residual = " << solverPerf.initialResidual()
|
||||||
|
<< ", relative residual = " << relativeResidual << endl;
|
||||||
|
}
|
||||||
|
while
|
||||||
|
(
|
||||||
|
//solverPerf.initialResidual() > convergenceTolerance
|
||||||
|
relativeResidual > convergenceTolerance
|
||||||
|
&&
|
||||||
|
++iCorr < nCorr
|
||||||
|
);
|
||||||
|
|
||||||
|
Info << nl << "Time " << runTime.value() << ", Solving for " << U.name()
|
||||||
|
<< ", Initial residual = " << initialResidual
|
||||||
|
<< ", Final residual = " << solverPerf.initialResidual()
|
||||||
|
<< ", Relative residual = " << relativeResidual
|
||||||
|
<< ", No outer iterations " << iCorr
|
||||||
|
<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
|
||||||
|
<< " ClockTime = " << runTime.elapsedClockTime() << " s"
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
lduMatrix::debug=0;
|
||||||
|
|
||||||
|
# include "calculateEpsilonSigma.H"
|
||||||
|
|
||||||
|
# include "writeFields.H"
|
||||||
|
|
||||||
|
Info<< "ExecutionTime = "
|
||||||
|
<< runTime.elapsedCpuTime()
|
||||||
|
<< " s\n\n" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< "End\n" << endl;
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
|
@ -0,0 +1,9 @@
|
||||||
|
//- how explicit component of sigma is to be calculated
|
||||||
|
word divSigmaExpMethod(mesh.solutionDict().subDict("stressedFoam").lookup("divSigmaExp"));
|
||||||
|
Info << "Selecting divSigmaExp calculation method " << divSigmaExpMethod << endl;
|
||||||
|
if(divSigmaExpMethod != "standard" && divSigmaExpMethod != "surface" && divSigmaExpMethod != "decompose" && divSigmaExpMethod != "laplacian")
|
||||||
|
{
|
||||||
|
FatalError << "divSigmaExp method " << divSigmaExpMethod << " not found!" << nl
|
||||||
|
<< "valid methods are:\nstandard\nsurface\ndecompose\nlaplacian"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
dimensionedVector gravity(mesh.solutionDict().subDict("stressedFoam").lookup("gravity"));
|
|
@ -0,0 +1,5 @@
|
||||||
|
const dictionary& stressControl =
|
||||||
|
mesh.solutionDict().subDict("stressedFoam");
|
||||||
|
|
||||||
|
int nCorr(readInt(stressControl.lookup("nCorrectors")));
|
||||||
|
scalar convergenceTolerance(readScalar(stressControl.lookup("U")));
|
|
@ -0,0 +1,36 @@
|
||||||
|
if (runTime.outputTime())
|
||||||
|
{
|
||||||
|
volScalarField epsilonEq
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"epsilonEq",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
sqrt((2.0/3.0)*magSqr(dev(epsilon)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< "Max epsilonEq = " << max(epsilonEq).value()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
volScalarField sigmaEq
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"sigmaEq",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
sqrt((3.0/2.0)*magSqr(dev(sigma)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< "Max sigmaEq = " << max(sigmaEq).value()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
runTime.write();
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
elasticIncrSolidFoam.C
|
||||||
|
|
||||||
|
EXE = $(FOAM_USER_APPBIN)/elasticIncrSolidFoam
|
|
@ -0,0 +1,14 @@
|
||||||
|
EXE_INC = \
|
||||||
|
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/meshTools/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/lagrangian/basic/lnInclude \
|
||||||
|
-I../solidModels/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/VectorN/lnInclude
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) -lsolidModels \
|
||||||
|
-lfiniteVolume \
|
||||||
|
-llduSolvers \
|
||||||
|
-lmeshTools \
|
||||||
|
-llagrangian \
|
||||||
|
-lVectorN
|
|
@ -0,0 +1,3 @@
|
||||||
|
DEpsilon = symm(gradDU);
|
||||||
|
|
||||||
|
DSigma = 2*mu*DEpsilon + lambda*(I*tr(DEpsilon));
|
|
@ -0,0 +1,47 @@
|
||||||
|
if(divDSigmaExpMethod == "standard")
|
||||||
|
{
|
||||||
|
divDSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
mu*gradDU.T() + lambda*(I*tr(gradDU)) - (mu + lambda)*gradDU,
|
||||||
|
"div(sigma)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divDSigmaExpMethod == "surface")
|
||||||
|
{
|
||||||
|
divDSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
muf*(mesh.Sf() & fvc::interpolate(gradDU.T()))
|
||||||
|
+ lambdaf*(mesh.Sf() & I*fvc::interpolate(tr(gradDU)))
|
||||||
|
- (muf + lambdaf)*(mesh.Sf() & fvc::interpolate(gradDU))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divDSigmaExpMethod == "decompose")
|
||||||
|
{
|
||||||
|
surfaceTensorField shearGradDU =
|
||||||
|
((I - n*n)&fvc::interpolate(gradDU));
|
||||||
|
|
||||||
|
divDSigmaExp = fvc::div
|
||||||
|
(
|
||||||
|
mesh.magSf()
|
||||||
|
*(
|
||||||
|
- (muf + lambdaf)*(fvc::snGrad(DU)&(I - n*n))
|
||||||
|
+ lambdaf*tr(shearGradDU&(I - n*n))*n
|
||||||
|
+ muf*(shearGradDU&n)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(divDSigmaExpMethod == "laplacian")
|
||||||
|
{
|
||||||
|
divDSigmaExp =
|
||||||
|
- fvc::laplacian(mu + lambda, DU, "laplacian(DDU,DU)")
|
||||||
|
+ fvc::div
|
||||||
|
(
|
||||||
|
mu*gradDU.T()
|
||||||
|
+ lambda*(I*tr(gradDU)),
|
||||||
|
"div(sigma)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalError << "divDSigmaExp method " << divDSigmaExpMethod << " not found!" << endl;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
//- net forces on boundary patches
|
||||||
|
|
||||||
|
vectorField netForces(mesh.boundary().size(), vector::zero);
|
||||||
|
|
||||||
|
Info << nl;
|
||||||
|
forAll(netForces, patchI)
|
||||||
|
{
|
||||||
|
netForces[patchI] = gSum(mesh.Sf().boundaryField()[patchI] & sigma.boundaryField()[patchI]);
|
||||||
|
|
||||||
|
Info << "patch\t" << mesh.boundary()[patchI].name() << "\t\tnet force is\t"
|
||||||
|
<< netForces[patchI] << " N" << endl;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
scalarField magDU = mag(DU.internalField());
|
||||||
|
|
||||||
|
forAll(magDU, cellI)
|
||||||
|
{
|
||||||
|
if (magDU[cellI] < SMALL)
|
||||||
|
{
|
||||||
|
magDU[cellI] = SMALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relativeResidual =
|
||||||
|
gMax
|
||||||
|
(
|
||||||
|
mag
|
||||||
|
(
|
||||||
|
DU.internalField()
|
||||||
|
- DU.prevIter().internalField()
|
||||||
|
)
|
||||||
|
/magDU
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
Info<< "Reading field DU\n" << endl;
|
||||||
|
volVectorField DU
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"DU",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::MUST_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh
|
||||||
|
);
|
||||||
|
volTensorField gradDU = fvc::grad(DU);
|
||||||
|
|
||||||
|
volVectorField U
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"U",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedVector("zero", dimLength, vector::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField DEpsilon
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"DEpsilon",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimless, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField epsilon
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"epsilon",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimless, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField DSigma
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"DSigma",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimForce/dimArea, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volSymmTensorField sigma
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"sigma",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::READ_IF_PRESENT,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedSymmTensor("zero", dimForce/dimArea, symmTensor::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
volVectorField divDSigmaExp
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"divDSigmaExp",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
),
|
||||||
|
mesh,
|
||||||
|
dimensionedVector("zero", dimensionSet(1,-2,-2,0,0,0,0), vector::zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
rheologyModel rheology(sigma);
|
||||||
|
|
||||||
|
volScalarField rho = rheology.rho();
|
||||||
|
|
||||||
|
volScalarField mu = rheology.mu();
|
||||||
|
volScalarField lambda = rheology.lambda();
|
||||||
|
surfaceScalarField muf = fvc::interpolate(mu, "mu");
|
||||||
|
surfaceScalarField lambdaf = fvc::interpolate(lambda, "lambda");
|
||||||
|
|
||||||
|
surfaceVectorField n = mesh.Sf()/mesh.magSf();
|
|
@ -0,0 +1,24 @@
|
||||||
|
Switch solidInterfaceCorr(false);
|
||||||
|
|
||||||
|
solidInterface* solidInterfacePtr(NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
const dictionary& stressControl =
|
||||||
|
mesh.solutionDict().subDict("stressedFoam");
|
||||||
|
|
||||||
|
solidInterfaceCorr = Switch(stressControl.lookup("solidInterface"));
|
||||||
|
|
||||||
|
if(solidInterfaceCorr)
|
||||||
|
{
|
||||||
|
Info << "Creating solid interface correction" << endl;
|
||||||
|
solidInterfacePtr = new solidInterface(mesh, rheology);
|
||||||
|
solidInterfacePtr->modifyProperties(muf, lambdaf);
|
||||||
|
|
||||||
|
//- solidInterface needs muf and lambdaf to be used for divDSigmaExp
|
||||||
|
if(divDSigmaExpMethod != "surface" && divDSigmaExpMethod != "decompose")
|
||||||
|
{
|
||||||
|
FatalError << "divDSigmaExp must be decompose or surface when solidInterface is on"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,169 @@
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2004-2007 Hrvoje Jasak
|
||||||
|
\\/ 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
|
||||||
|
|
||||||
|
Application
|
||||||
|
elasticIncrSolidFoam
|
||||||
|
|
||||||
|
Description
|
||||||
|
Transient/steady-state segregated finite-volume solver for small strain
|
||||||
|
elastic solid bodies.
|
||||||
|
|
||||||
|
Displacement Increment field DU is solved for using a incremental total
|
||||||
|
Lagrangian approach,
|
||||||
|
also generating the strain tensor field epsilon and stress tensor
|
||||||
|
field sigma.
|
||||||
|
|
||||||
|
With optional multi-material solid interface correction ensuring
|
||||||
|
correct tractions on multi-material interfaces
|
||||||
|
|
||||||
|
Author
|
||||||
|
Philip Cardiff
|
||||||
|
multi-material by Tukovic et al. 2012
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "fvCFD.H"
|
||||||
|
#include "rheologyModel.H"
|
||||||
|
#include "solidInterface.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
# include "setRootCase.H"
|
||||||
|
|
||||||
|
# include "createTime.H"
|
||||||
|
|
||||||
|
# include "createMesh.H"
|
||||||
|
|
||||||
|
# include "createFields.H"
|
||||||
|
|
||||||
|
# include "readDivDSigmaExpMethod.H"
|
||||||
|
|
||||||
|
# include "createSolidInterface.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Info<< "\nCalculating displacement field\n" << endl;
|
||||||
|
|
||||||
|
while(runTime.loop())
|
||||||
|
{
|
||||||
|
Info<< "Time: " << runTime.timeName() << nl << endl;
|
||||||
|
|
||||||
|
# include "readStressedFoamControls.H"
|
||||||
|
|
||||||
|
int iCorr = 0;
|
||||||
|
scalar initialResidual = 0;
|
||||||
|
scalar relativeResidual = GREAT;
|
||||||
|
lduMatrix::solverPerformance solverPerf;
|
||||||
|
lduMatrix::debug = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
DU.storePrevIter();
|
||||||
|
|
||||||
|
# include "calculateDivDSigmaExp.H"
|
||||||
|
|
||||||
|
//- linear momentum equation
|
||||||
|
fvVectorMatrix DUEqn
|
||||||
|
(
|
||||||
|
fvm::d2dt2(rho, DU)
|
||||||
|
==
|
||||||
|
fvm::laplacian(2*muf + lambdaf, DU, "laplacian(DDU,DU)")
|
||||||
|
+ divDSigmaExp
|
||||||
|
);
|
||||||
|
|
||||||
|
if(solidInterfaceCorr)
|
||||||
|
{
|
||||||
|
solidInterfacePtr->correct(DUEqn);
|
||||||
|
}
|
||||||
|
|
||||||
|
solverPerf = DUEqn.solve();
|
||||||
|
|
||||||
|
if(iCorr == 0)
|
||||||
|
{
|
||||||
|
initialResidual = solverPerf.initialResidual();
|
||||||
|
}
|
||||||
|
|
||||||
|
DU.relax();
|
||||||
|
|
||||||
|
if(solidInterfaceCorr)
|
||||||
|
{
|
||||||
|
gradDU = solidInterfacePtr->grad(DU);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gradDU = fvc::grad(DU);
|
||||||
|
}
|
||||||
|
|
||||||
|
# include "calculateRelativeResidual.H"
|
||||||
|
|
||||||
|
Info << "\tTime " << runTime.value()
|
||||||
|
<< ", Corrector " << iCorr
|
||||||
|
<< ", Solving for " << DU.name()
|
||||||
|
<< " using " << solverPerf.solverName()
|
||||||
|
<< ", residual = " << solverPerf.initialResidual()
|
||||||
|
<< ", relative residual = " << relativeResidual << endl;
|
||||||
|
}
|
||||||
|
while
|
||||||
|
(
|
||||||
|
//solverPerf.initialResidual() > convergenceTolerance
|
||||||
|
relativeResidual > convergenceTolerance
|
||||||
|
&&
|
||||||
|
++iCorr < nCorr
|
||||||
|
);
|
||||||
|
|
||||||
|
Info << nl << "Time " << runTime.value() << ", Solving for " << DU.name()
|
||||||
|
<< ", Initial residual = " << initialResidual
|
||||||
|
<< ", Final residual = " << solverPerf.initialResidual()
|
||||||
|
<< ", Relative residual = " << relativeResidual
|
||||||
|
<< ", No outer iterations " << iCorr
|
||||||
|
<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
|
||||||
|
<< " ClockTime = " << runTime.elapsedClockTime() << " s"
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
lduMatrix::debug=0;
|
||||||
|
|
||||||
|
# include "calculateDEpsilonDSigma.H"
|
||||||
|
|
||||||
|
U += DU;
|
||||||
|
sigma += DSigma;
|
||||||
|
epsilon += DEpsilon;
|
||||||
|
|
||||||
|
# include "writeFields.H"
|
||||||
|
|
||||||
|
# include "calculateNetForces.H"
|
||||||
|
|
||||||
|
Info<< "ExecutionTime = "
|
||||||
|
<< runTime.elapsedCpuTime()
|
||||||
|
<< " s\n\n" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< "End\n" << endl;
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
|
@ -0,0 +1,9 @@
|
||||||
|
//- how explicit component of sigma is to be calculated
|
||||||
|
word divDSigmaExpMethod(mesh.solutionDict().subDict("stressedFoam").lookup("divDSigmaExp"));
|
||||||
|
Info << "Selecting divDSigmaExp calculation method " << divDSigmaExpMethod << endl;
|
||||||
|
if(divDSigmaExpMethod != "standard" && divDSigmaExpMethod != "surface" && divDSigmaExpMethod != "decompose" && divDSigmaExpMethod != "laplacian")
|
||||||
|
{
|
||||||
|
FatalError << "divDSigmaExp method " << divDSigmaExpMethod << " not found!" << nl
|
||||||
|
<< "valid methods are:\nstandard\nsurface\ndecompose\nlaplacian"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
const dictionary& stressControl =
|
||||||
|
mesh.solutionDict().subDict("stressedFoam");
|
||||||
|
|
||||||
|
int nCorr(readInt(stressControl.lookup("nCorrectors")));
|
||||||
|
scalar convergenceTolerance(readScalar(stressControl.lookup("DU")));
|
|
@ -0,0 +1,36 @@
|
||||||
|
if (runTime.outputTime())
|
||||||
|
{
|
||||||
|
volScalarField epsilonEq
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"epsilonEq",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
sqrt((2.0/3.0)*magSqr(dev(epsilon)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< "Max epsilonEq = " << max(epsilonEq).value()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
volScalarField sigmaEq
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"sigmaEq",
|
||||||
|
runTime.timeName(),
|
||||||
|
mesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
sqrt((3.0/2.0)*magSqr(dev(sigma)))
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< "Max sigmaEq = " << max(sigmaEq).value()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
runTime.write();
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
//- write force displacement to file
|
||||||
|
|
||||||
|
label leftPatchID = mesh.boundaryMesh().findPatchID("leftClamp");
|
||||||
|
if(leftPatchID == -1)
|
||||||
|
{
|
||||||
|
FatalError << "Cannot find patch left for calculating force" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- calculate force in x direction on leftClamp patch
|
||||||
|
scalar leftForce = gSum(
|
||||||
|
vector(1, 0, 0) &
|
||||||
|
(mesh.boundary()[leftPatchID].Sf() & sigma.boundaryField()[leftPatchID])
|
||||||
|
);
|
||||||
|
|
||||||
|
//- patchIntegrate utility integrates it this way but this is worng because the sigma tensor should
|
||||||
|
//- be dotted with the surface normal to give the actual traction/force
|
||||||
|
//- you cannot just take the component of the sigma tensor
|
||||||
|
//scalar leftForcePatchIntegrateMethod = gSum(
|
||||||
|
// mesh.magSf().boundaryField()[leftPatchID]
|
||||||
|
// *sigma.boundaryField()[leftPatchID].component(symmTensor::XY)
|
||||||
|
// );
|
||||||
|
|
||||||
|
vector gaugeU1 = vector::zero;
|
||||||
|
vector gaugeU2 = vector::zero;
|
||||||
|
if(gaugeFaceID1 != -1)
|
||||||
|
{
|
||||||
|
gaugeU1 = U.boundaryField()[gaugeFacePatchID1][gaugeFaceID1];
|
||||||
|
}
|
||||||
|
if(gaugeFaceID2 != -1)
|
||||||
|
{
|
||||||
|
gaugeU2 = U.boundaryField()[gaugeFacePatchID2][gaugeFaceID2];
|
||||||
|
}
|
||||||
|
|
||||||
|
//- reduce across procs
|
||||||
|
reduce(gaugeU1, sumOp<vector>());
|
||||||
|
reduce(gaugeU2, sumOp<vector>());
|
||||||
|
|
||||||
|
Pout << "gaugeU1 is " << gaugeU1 << nl
|
||||||
|
<< "gaugeU2 is " << gaugeU2 << endl;
|
||||||
|
|
||||||
|
scalar gaugeDisp = mag(gaugeU1 - gaugeU2);
|
||||||
|
|
||||||
|
//- write to file
|
||||||
|
if(Pstream::master())
|
||||||
|
{
|
||||||
|
OFstream& forceDispFile = *filePtr;
|
||||||
|
forceDispFile << 1000*gaugeDisp << "\t" << -1*leftForce << endl;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
elasticNonLinTLSolidFoam.C
|
||||||
|
|
||||||
|
EXE = $(FOAM_USER_APPBIN)/elasticNonLinTLSolidFoam
|
|
@ -0,0 +1,15 @@
|
||||||
|
EXE_INC = \
|
||||||
|
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/meshTools/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/lagrangian/basic/lnInclude \
|
||||||
|
-I../solidModels/lnInclude \
|
||||||
|
-I$(FOAM_SRC)/VectorN/lnInclude
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-L$(FOAM_USER_LIBBIN) -lsolidModels \
|
||||||
|
-lfiniteVolume \
|
||||||
|
-llduSolvers \
|
||||||
|
-lmeshTools \
|
||||||
|
-llagrangian \
|
||||||
|
-lVectorN
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
//- Green finite strain tensor
|
||||||
|
epsilon = symm(gradU) + 0.5*symm(gradU & gradU.T());
|
||||||
|
|
||||||
|
//- second Piola-Kirchhoff stress tensor
|
||||||
|
sigma = 2*mu*epsilon + lambda*(I*tr(epsilon));
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
scalarField magU = mag(U.internalField() - U.oldTime().internalField());
|
||||||
|
|
||||||
|
forAll(magU, cellI)
|
||||||
|
{
|
||||||
|
if (magU[cellI] < SMALL)
|
||||||
|
{
|
||||||
|
magU[cellI] = SMALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relativeResidual =
|
||||||
|
gMax
|
||||||
|
(
|
||||||
|
mag
|
||||||
|
(
|
||||||
|
U.internalField()
|
||||||
|
- U.prevIter().internalField()
|
||||||
|
)
|
||||||
|
/magU
|
||||||
|
);
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue