36 #ifndef ABSTRACTNONLINEARELASTICITYSOLVER_HPP_
37 #define ABSTRACTNONLINEARELASTICITYSOLVER_HPP_
41 #include "AbstractContinuumMechanicsSolver.hpp"
42 #include "LinearSystem.hpp"
43 #include "LogFile.hpp"
44 #include "MechanicsEventHandler.hpp"
45 #include "ReplicatableVector.hpp"
46 #include "FourthOrderTensor.hpp"
47 #include "CmguiDeformedSolutionsWriter.hpp"
48 #include "AbstractMaterialLaw.hpp"
49 #include "QuadraticBasisFunction.hpp"
50 #include "SolidMechanicsProblemDefinition.hpp"
52 #include "AbstractPerElementWriter.hpp"
53 #include "petscsnes.h"
61 typedef enum StrainType_
63 DEFORMATION_GRADIENT_F = 0,
69 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
86 template<
unsigned DIM>
87 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeResidual(SNES snes,
92 #if ((PETSC_VERSION_MAJOR==3) && (PETSC_VERSION_MINOR>=5))
105 template<
unsigned DIM>
106 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeJacobian(SNES snes,
123 template<
unsigned DIM>
124 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeJacobian(SNES snes,
126 Mat* pGlobalJacobian,
127 Mat* pPreconditioner,
128 MatStructure* pMatStructure,
132 template <
unsigned DIM>
141 template<
unsigned DIM>
171 assert(localIndex == pElement->
GetIndex());
173 c_matrix<double, DIM, DIM> data =
mpSolver->GetAverageStressPerElement(localIndex);
174 for (
unsigned i=0; i<DIM; i++)
176 for (
unsigned j=0; j<DIM; j++)
178 rData[i*DIM+j] = data(i,j);
195 template<
unsigned DIM>
374 virtual void AssembleSystem(
bool assembleResidual,
bool assembleLinearSystem)=0;
400 c_matrix<double,DIM,DIM>& rDeformationGradient);
421 unsigned elementIndex,
422 unsigned currentQuadPointGlobalIndex,
423 c_matrix<double,DIM,DIM>& rT,
460 c_matrix<double, BOUNDARY_STENCIL_SIZE, BOUNDARY_STENCIL_SIZE>& rAelem,
461 c_vector<double, BOUNDARY_STENCIL_SIZE>& rBelem,
462 bool assembleResidual,
463 bool assembleJacobian,
464 unsigned boundaryConditionIndex);
503 c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
504 c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
505 bool assembleResidual,
506 bool assembleJacobian,
507 unsigned boundaryConditionIndex);
578 virtual void PostNewtonStep(
unsigned counter,
double normResidual);
632 std::string outputDirectory,
633 CompressibilityType compressibilityType);
645 void Solve(
double tol=-1.0);
687 assert(kspAbsoluteTolerance > 0);
759 void WriteCurrentStrains(StrainType strainType, std::string fileName,
int counterToAppend = -1);
811 template<
unsigned DIM>
814 std::string outputDirectory,
815 CompressibilityType compressibilityType)
817 mrProblemDefinition(rProblemDefinition),
818 mrJacobianMatrix(this->mSystemLhsMatrix),
820 mWriteOutputEachNewtonIteration(false),
821 mNumNewtonIterations(0),
823 mCheckedOutwardNormals(false),
824 mLastDampingValue(0.0),
825 mIncludeActiveTension(true),
826 mSetComputeAverageStressPerElement(false)
837 template<
unsigned DIM>
842 template<
unsigned DIM>
847 if (assembleJacobian)
852 VecCopy(this->mResidualVector, this->mLinearSystemRhsVector);
856 if (assembleJacobian)
858 this->ApplyDirichletBoundaryConditions(NONLINEAR_PROBLEM_APPLY_TO_EVERYTHING, this->mCompressibilityType==COMPRESSIBLE);
860 else if (assembleResidual)
862 this->ApplyDirichletBoundaryConditions(NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY, this->mCompressibilityType==COMPRESSIBLE);
865 if (assembleResidual)
869 if (assembleJacobian)
877 template<
unsigned DIM>
880 this->mSpatialSolution.clear();
881 this->mSpatialSolution.resize(this->mrQuadMesh.GetNumNodes(), zero_vector<double>(DIM));
882 for (
unsigned i=0; i<this->mrQuadMesh.GetNumNodes(); i++)
884 for (
unsigned j=0; j<DIM; j++)
886 this->mSpatialSolution[i](j) = this->mrQuadMesh.GetNode(i)->rGetLocation()[j] + this->mCurrentSolution[this->mProblemDimension*i+j];
889 return this->mSpatialSolution;
892 template<
unsigned DIM>
895 return rGetSpatialSolution();
898 template<
unsigned DIM>
901 if (!this->mWriteOutput)
906 std::stringstream file_name;
907 file_name << fileName;
908 if (counterToAppend >= 0)
910 file_name <<
"_" << counterToAppend;
912 file_name <<
".strain";
914 out_stream p_file = this->mpOutputFileHandler->OpenOutputFile(file_name.str());
916 c_matrix<double,DIM,DIM> strain;
919 iter != this->mrQuadMesh.GetElementIteratorEnd();
922 GetElementCentroidStrain(strainType, *iter, strain);
923 for (
unsigned i=0; i<DIM; i++)
925 for (
unsigned j=0; j<DIM; j++)
927 *p_file << strain(i,j) <<
" ";
935 template<
unsigned DIM>
938 if (!this->mWriteOutput)
943 if (!mSetComputeAverageStressPerElement)
945 EXCEPTION(
"Call SetComputeAverageStressPerElementDuringSolve() before solve if calling WriteCurrentAverageElementStresses()");
948 std::stringstream file_name;
949 file_name << fileName;
950 if (counterToAppend >= 0)
952 file_name <<
"_" << counterToAppend;
954 file_name <<
".stress";
955 assert(mAverageStressesPerElement.size()==this->mrQuadMesh.GetNumElements());
958 stress_writer.WriteData(*(this->mpOutputFileHandler), file_name.str());
961 template<
unsigned DIM>
964 if (this->mOutputDirectory ==
"")
966 EXCEPTION(
"No output directory was given so no output was written, cannot convert to cmgui format");
972 WRITE_QUADRATIC_MESH);
974 std::vector<c_vector<double,DIM> >& r_deformed_positions = this->rGetDeformedPosition();
980 template<
unsigned DIM>
983 mSetComputeAverageStressPerElement = setComputeAverageStressPerElement;
984 if (setComputeAverageStressPerElement && mAverageStressesPerElement.size()==0)
986 mAverageStressesPerElement.resize(this->mrQuadMesh.GetNumElements(), zero_vector<double>(DIM*(DIM+1)/2));
990 template<
unsigned DIM>
993 assert(mSetComputeAverageStressPerElement);
994 assert(elemIndex<this->mrQuadMesh.GetNumElements());
1004 for (
unsigned i=0; i<DIM*(DIM+1)/2; i++)
1015 row = i<=2 ? 0 : (i<=4? 1 : 2);
1016 col = i==0 ? 0 : (i==1 || i==3? 1 : 2);
1019 this->mAverageStressesPerElement[elemIndex](i) += rT(row,col);
1023 template<
unsigned DIM>
1026 if (!mSetComputeAverageStressPerElement)
1028 EXCEPTION(
"Call SetComputeAverageStressPerElementDuringSolve() before solve if calling GetAverageStressesPerElement()");
1030 assert(elementIndex<this->mrQuadMesh.GetNumElements());
1032 c_matrix<double,DIM,DIM> stress;
1044 stress(0,0) = mAverageStressesPerElement[elementIndex](0);
1045 stress(1,0) = stress(0,1) = mAverageStressesPerElement[elementIndex](1);
1046 stress(1,1) = mAverageStressesPerElement[elementIndex](2);
1050 stress(0,0) = mAverageStressesPerElement[elementIndex](0);
1051 stress(1,0) = stress(0,1) = mAverageStressesPerElement[elementIndex](1);
1052 stress(2,0) = stress(0,2) = mAverageStressesPerElement[elementIndex](2);
1053 stress(1,1) = mAverageStressesPerElement[elementIndex](3);
1054 stress(2,1) = stress(1,2) = mAverageStressesPerElement[elementIndex](4);
1055 stress(2,2) = mAverageStressesPerElement[elementIndex](5);
1065 template<
unsigned DIM>
1068 c_matrix<double,DIM,DIM>& rStrain)
1070 static c_matrix<double,DIM,DIM> jacobian;
1071 static c_matrix<double,DIM,DIM> inverse_jacobian;
1072 double jacobian_determinant;
1074 this->mrQuadMesh.GetInverseJacobianForElement(rElement.
GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
1077 static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
1078 for (
unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
1080 for (
unsigned JJ=0; JJ<DIM; JJ++)
1082 element_current_displacements(JJ,II) = this->mCurrentSolution[this->mProblemDimension*rElement.
GetNodeGlobalIndex(II) + JJ];
1087 static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi;
1088 static c_matrix<double,DIM,DIM> grad_u;
1109 grad_u = zero_matrix<double>(DIM,DIM);
1110 for (
unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++)
1112 for (
unsigned i=0; i<DIM; i++)
1114 for (
unsigned M=0; M<DIM; M++)
1116 grad_u(i,M) += grad_quad_phi(M,node_index)*element_current_displacements(i,node_index);
1121 c_matrix<double,DIM,DIM> deformation_gradient;
1123 for (
unsigned i=0; i<DIM; i++)
1125 for (
unsigned M=0; M<DIM; M++)
1127 deformation_gradient(i,M) = (i==M?1:0) + grad_u(i,M);
1133 case DEFORMATION_GRADIENT_F:
1135 rStrain = deformation_gradient;
1138 case DEFORMATION_TENSOR_C:
1140 rStrain = prod(trans(deformation_gradient),deformation_gradient);
1143 case LAGRANGE_STRAIN_E:
1145 c_matrix<double,DIM,DIM> C = prod(trans(deformation_gradient),deformation_gradient);
1146 for (
unsigned M=0; M<DIM; M++)
1148 for (
unsigned N=0; N<DIM; N++)
1150 rStrain(M,N) = 0.5* ( C(M,N)-(M==N?1:0) );
1163 template<
unsigned DIM>
1166 c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
1167 c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
1168 bool assembleResidual,
1169 bool assembleJacobian,
1170 unsigned boundaryConditionIndex)
1172 if (this->mrProblemDefinition.GetTractionBoundaryConditionType() == PRESSURE_ON_DEFORMED
1173 || this->mrProblemDefinition.GetTractionBoundaryConditionType() == FUNCTIONAL_PRESSURE_ON_DEFORMED)
1175 AssembleOnBoundaryElementForPressureOnDeformedBc(rBoundaryElement, rAelem, rBelem,
1176 assembleResidual, assembleJacobian, boundaryConditionIndex);
1183 if (assembleJacobian && !assembleResidual)
1189 c_vector<double, DIM> weighted_direction;
1190 double jacobian_determinant;
1191 this->mrQuadMesh.GetWeightedDirectionForBoundaryElement(rBoundaryElement.
GetIndex(), weighted_direction, jacobian_determinant);
1193 c_vector<double,NUM_NODES_PER_BOUNDARY_ELEMENT> phi;
1195 for (
unsigned quad_index=0; quad_index<this->mpBoundaryQuadratureRule->GetNumQuadPoints(); quad_index++)
1197 double wJ = jacobian_determinant * this->mpBoundaryQuadratureRule->GetWeight(quad_index);
1199 const ChastePoint<DIM-1>& quad_point = this->mpBoundaryQuadratureRule->rGetQuadPoint(quad_index);
1205 c_vector<double,DIM> traction = zero_vector<double>(DIM);
1206 switch (this->mrProblemDefinition.GetTractionBoundaryConditionType())
1208 case FUNCTIONAL_TRACTION:
1210 c_vector<double,DIM> X = zero_vector<double>(DIM);
1211 for (
unsigned node_index=0; node_index<NUM_NODES_PER_BOUNDARY_ELEMENT; node_index++)
1213 X += phi(node_index)*this->mrQuadMesh.GetNode( rBoundaryElement.
GetNodeGlobalIndex(node_index) )->rGetLocation();
1215 traction = this->mrProblemDefinition.EvaluateTractionFunction(X, this->mCurrentTime);
1218 case ELEMENTWISE_TRACTION:
1220 traction = this->mrProblemDefinition.rGetElementwiseTractions()[boundaryConditionIndex];
1228 for (
unsigned index=0; index<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index++)
1230 unsigned spatial_dim = index%DIM;
1231 unsigned node_index = (index-spatial_dim)/DIM;
1233 assert(node_index < NUM_NODES_PER_BOUNDARY_ELEMENT);
1235 rBelem(index) -= traction(spatial_dim)
1242 template<
unsigned DIM>
1260 return (mLastDampingValue >= 0.5);
1264 template<
unsigned DIM>
1267 c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
1268 c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
1269 bool assembleResidual,
1270 bool assembleJacobian,
1271 unsigned boundaryConditionIndex)
1273 assert( this->mrProblemDefinition.GetTractionBoundaryConditionType()==PRESSURE_ON_DEFORMED
1274 || this->mrProblemDefinition.GetTractionBoundaryConditionType()==FUNCTIONAL_PRESSURE_ON_DEFORMED);
1279 c_vector<double, DIM> weighted_direction;
1280 double jacobian_determinant;
1282 this->mrQuadMesh.GetWeightedDirectionForBoundaryElement(rBoundaryElement.
GetIndex(), weighted_direction, jacobian_determinant);
1291 std::set<unsigned> potential_elements = rBoundaryElement.
GetNode(0)->rGetContainingElementIndices();
1292 for (std::set<unsigned>::iterator iter = potential_elements.begin();
1293 iter != potential_elements.end();
1296 p_containing_vol_element = this->mrQuadMesh.GetElement(*iter);
1298 bool this_vol_ele_contains_surf_ele =
true;
1300 for (
unsigned i=1; i<NUM_NODES_PER_BOUNDARY_ELEMENT; i++)
1303 bool found_this_node =
false;
1304 for (
unsigned j=0; j<p_containing_vol_element->
GetNumNodes(); j++)
1307 if (surf_element_node_index == vol_element_node_index)
1309 found_this_node =
true;
1313 if (!found_this_node)
1315 this_vol_ele_contains_surf_ele =
false;
1319 if (this_vol_ele_contains_surf_ele)
1326 std::vector<unsigned> surf_to_vol_map(NUM_NODES_PER_BOUNDARY_ELEMENT);
1327 for (
unsigned i=0; i<NUM_NODES_PER_BOUNDARY_ELEMENT; i++)
1330 for (
unsigned j=0; j<NUM_NODES_PER_ELEMENT; j++)
1334 surf_to_vol_map[i] = j;
1343 static c_matrix<double,DIM,DIM> jacobian_vol_element;
1344 static c_matrix<double,DIM,DIM> inverse_jacobian_vol_element;
1345 double jacobian_determinant_vol_element;
1346 this->mrQuadMesh.GetInverseJacobianForElement(p_containing_vol_element->
GetIndex(), jacobian_vol_element, jacobian_determinant_vol_element, inverse_jacobian_vol_element);
1349 static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
1350 for (
unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
1352 for (
unsigned JJ=0; JJ<DIM; JJ++)
1354 element_current_displacements(JJ,II) = this->mCurrentSolution[this->mProblemDimension*p_containing_vol_element->
GetNodeGlobalIndex(II) + JJ];
1360 static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi_vol_element;
1362 c_vector<double,NUM_NODES_PER_BOUNDARY_ELEMENT> quad_phi_surf_element;
1364 static c_matrix<double, DIM, NUM_NODES_PER_BOUNDARY_ELEMENT> grad_quad_phi_surf_element;
1366 c_matrix<double,DIM,DIM> F;
1367 c_matrix<double,DIM,DIM> invF;
1370 c_matrix<double,1,DIM> normal_as_mat;
1371 for (
unsigned i=0; i<DIM; i++)
1373 normal_as_mat(0,i) = normal(i);
1376 double normal_pressure;
1377 switch (this->mrProblemDefinition.GetTractionBoundaryConditionType())
1379 case PRESSURE_ON_DEFORMED:
1380 normal_pressure = this->mrProblemDefinition.GetNormalPressure();
1382 case FUNCTIONAL_PRESSURE_ON_DEFORMED:
1383 normal_pressure = this->mrProblemDefinition.EvaluateNormalPressureFunction(this->mCurrentTime);
1389 for (
unsigned quad_index=0; quad_index<this->mpBoundaryQuadratureRule->GetNumQuadPoints(); quad_index++)
1391 double wJ = jacobian_determinant * this->mpBoundaryQuadratureRule->GetWeight(quad_index);
1395 const ChastePoint<DIM-1>& quadrature_point = this->mpBoundaryQuadratureRule->rGetQuadPoint(quad_index);
1402 c_vector<double,DIM> X = zero_vector<double>(DIM);
1403 for (
unsigned node_index=0; node_index<NUM_NODES_PER_BOUNDARY_ELEMENT; node_index++)
1405 X += quad_phi_surf_element(node_index)*rBoundaryElement.
GetNode(node_index)->rGetLocation();
1411 c_vector<double,DIM> xi;
1412 for (
unsigned i=0; i<DIM; i++)
1414 xi(i) = weight(i+1);
1420 assert( DIM!=2 || (fabs(weight(0))<1e-6) || (fabs(weight(1))<1e-6) || (fabs(weight(2))<1e-6) );
1424 assert( DIM!=3 || (fabs(weight(0))<1e-6) || (fabs(weight(1))<1e-6) || (fabs(weight(2))<1e-6) || (fabs(weight(3))<1e-6) );
1430 F = identity_matrix<double>(DIM,DIM);
1431 for (
unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++)
1433 for (
unsigned i=0; i<DIM; i++)
1435 for (
unsigned M=0; M<DIM; M++)
1437 F(i,M) += grad_quad_phi_vol_element(M,node_index)*element_current_displacements(i,node_index);
1445 if (assembleResidual)
1447 c_vector<double,DIM> traction = detF*normal_pressure*prod(trans(invF),normal);
1450 for (
unsigned index=0; index<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index++)
1452 unsigned spatial_dim = index%DIM;
1453 unsigned node_index = (index-spatial_dim)/DIM;
1455 assert(node_index < NUM_NODES_PER_BOUNDARY_ELEMENT);
1457 rBelem(index) -= traction(spatial_dim)
1458 * quad_phi_surf_element(node_index)
1466 if (assembleJacobian && ShouldAssembleMatrixTermForPressureOnDeformedBc())
1468 for (
unsigned II=0; II<NUM_NODES_PER_BOUNDARY_ELEMENT; II++)
1470 for (
unsigned N=0; N<DIM; N++)
1472 grad_quad_phi_surf_element(N,II) = grad_quad_phi_vol_element(N,surf_to_vol_map[II]);
1477 for (
unsigned N=0; N<DIM; N++)
1479 for (
unsigned e=0; e<DIM; e++)
1481 for (
unsigned M=0; M<DIM; M++)
1483 for (
unsigned d=0; d<DIM; d++)
1485 tensor1(N,e,M,d) = invF(N,e)*invF(M,d) - invF(M,e)*invF(N,d);
1493 tensor2.template SetAsContractionOnFirstDimension<DIM>( trans(grad_quad_phi_surf_element), tensor1);
1498 tensor3.template SetAsContractionOnThirdDimension<DIM>( normal_as_mat, tensor2);
1500 for (
unsigned index1=0; index1<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index1++)
1502 unsigned spatial_dim1 = index1%DIM;
1503 unsigned node_index1 = (index1-spatial_dim1)/DIM;
1505 for (
unsigned index2=0; index2<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index2++)
1507 unsigned spatial_dim2 = index2%DIM;
1508 unsigned node_index2 = (index2-spatial_dim2)/DIM;
1510 rAelem(index1,index2) -= normal_pressure
1512 * tensor3(node_index2,spatial_dim2,0,spatial_dim1)
1513 * quad_phi_surf_element(node_index1)
1521 template<
unsigned DIM>
1525 mrProblemDefinition.Validate();
1532 if (mrProblemDefinition.GetTractionBoundaryConditionType()==PRESSURE_ON_DEFORMED && mCheckedOutwardNormals==
false)
1534 this->mrQuadMesh.CheckOutwardNormals();
1535 mCheckedOutwardNormals =
true;
1539 this->WriteCurrentSpatialSolution(
"initial",
"nodes");
1553 if (this->mCompressibilityType==INCOMPRESSIBLE)
1555 this->RemovePressureDummyValuesThroughLinearInterpolation();
1559 this->WriteCurrentSpatialSolution(
"solution",
"nodes");
1565 template<
unsigned DIM>
1576 KSPGetPC(solver, &pc);
1578 if (mPetscDirectSolve)
1580 if (this->mCompressibilityType==COMPRESSIBLE)
1582 KSPSetType(solver,KSPPREONLY);
1585 PCSetType(pc, PCLU);
1592 if (this->mCompressibilityType==COMPRESSIBLE)
1594 KSPSetType(solver,KSPCG);
1597 PCSetType(pc, PCICC);
1601 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later
1609 PCSetType(pc, PCBJACOBI);
1614 unsigned num_restarts = 100;
1615 KSPSetType(solver,KSPGMRES);
1616 KSPGMRESSetRestart(solver,num_restarts);
1618 #ifndef MECH_USE_HYPRE
1619 PCSetType(pc, PCBJACOBI);
1629 PCSetType(pc, PCHYPRE);
1630 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >=2) //PETSc 3.2 or later
1631 KSPSetPCSide(solver, PC_RIGHT);
1633 KSPSetPreconditionerSide(solver, PC_RIGHT);
1651 template<
unsigned DIM>
1654 if (!allowException)
1657 AssembleSystem(
true,
false);
1664 AssembleSystem(
true,
false);
1674 return CalculateResidualNorm();
1677 template<
unsigned DIM>
1683 VecNorm(this->mResidualVector, NORM_2, &norm);
1684 return norm/this->mNumDofs;
1687 template<
unsigned DIM>
1691 std::vector<double>& rZ)
1693 assert(rX.size()==rY.
GetSize());
1694 assert(rY.
GetSize()==rZ.size());
1695 for (
unsigned i=0; i<rX.size(); i++)
1697 rZ[i] = rX[i] + a*rY[i];
1701 template<
unsigned DIM>
1713 AssembleSystem(
true,
true);
1726 VecDuplicate(this->mResidualVector,&solution);
1729 KSPCreate(PETSC_COMM_WORLD,&solver);
1731 #if ((PETSC_VERSION_MAJOR==3) && (PETSC_VERSION_MINOR>=5))
1732 KSPSetOperators(solver, mrJacobianMatrix, this->mPreconditionMatrix);
1734 KSPSetOperators(solver, mrJacobianMatrix, this->mPreconditionMatrix, DIFFERENT_NONZERO_PATTERN );
1738 SetKspSolverAndPcType(solver);
1743 KSPSetFromOptions(solver);
1750 if (mKspAbsoluteTol < 0)
1753 VecDuplicate(this->mResidualVector, &temp);
1755 VecDuplicate(this->mResidualVector, &temp2);
1756 Vec linsys_residual;
1757 VecDuplicate(this->mResidualVector, &linsys_residual);
1759 KSPInitialResidual(solver, solution, temp, temp2, linsys_residual, this->mLinearSystemRhsVector);
1760 double initial_resid_norm;
1761 VecNorm(linsys_residual, NORM_2, &initial_resid_norm);
1767 double ksp_rel_tol = 1e-6;
1768 double absolute_tol = ksp_rel_tol * initial_resid_norm;
1769 if (absolute_tol < 1e-12)
1771 absolute_tol = 1e-12;
1773 KSPSetTolerances(solver, 1e-16, absolute_tol, PETSC_DEFAULT, 1000 );
1777 KSPSetTolerances(solver, 1e-16, mKspAbsoluteTol, PETSC_DEFAULT, 1000 );
1785 KSPSolve(solver,this->mLinearSystemRhsVector,solution);
1811 KSPConvergedReason reason;
1812 KSPGetConvergedReason(solver,&reason);
1814 if (reason != KSP_DIVERGED_ITS)
1832 WARN_ONCE_ONLY(
"Linear solve (within a mechanics solve) didn't converge, but this may not stop nonlinear solve converging")
1838 KSPGetIterationNumber(solver, &num_iters);
1843 EXCEPTION(
"KSP Absolute tolerance was too high, linear system wasn't solved - there will be no decrease in Newton residual. Decrease KspAbsoluteTolerance");
1850 std::cout <<
"[" <<
PetscTools::GetMyRank() <<
"]: Num iterations = " << num_iters <<
"\n" << std::flush;
1869 double new_norm_resid = UpdateSolutionUsingLineSearch(solution);
1875 return new_norm_resid;
1878 template<
unsigned DIM>
1883 std::cout <<
"\tTesting s = " << s <<
", |f| = " << residNorm <<
"\n" << std::flush;
1887 template<
unsigned DIM>
1890 double initial_norm_resid = CalculateResidualNorm();
1893 std::cout <<
"\tInitial |f| [corresponding to s=0] is " << initial_norm_resid <<
"\n" << std::flush;
1898 std::vector<double> old_solution = this->mCurrentSolution;
1900 std::vector<double> damping_values;
1901 for (
unsigned i=10; i>=1; i--)
1903 damping_values.push_back((
double)i/10.0);
1905 damping_values.push_back(0.05);
1906 assert(damping_values.size()==11);
1911 VectorSum(old_solution, update, -damping_values[index], this->mCurrentSolution);
1912 double current_resid_norm = ComputeResidualAndGetNorm(
true);
1913 PrintLineSearchResult(damping_values[index], current_resid_norm);
1918 VectorSum(old_solution, update, -damping_values[index], this->mCurrentSolution);
1919 double next_resid_norm = ComputeResidualAndGetNorm(
true);
1920 PrintLineSearchResult(damping_values[index], next_resid_norm);
1925 while ( (next_resid_norm==DBL_MAX)
1926 || ( (next_resid_norm < current_resid_norm) && (index<damping_values.size()) ) )
1928 current_resid_norm = next_resid_norm;
1931 VectorSum(old_solution, update, -damping_values[index], this->mCurrentSolution);
1932 next_resid_norm = ComputeResidualAndGetNorm(
true);
1933 PrintLineSearchResult(damping_values[index], next_resid_norm);
1938 unsigned best_index;
1940 if (index==damping_values.size() && (next_resid_norm < current_resid_norm))
1950 current_resid_norm = next_resid_norm;
1951 best_index = index-1;
1958 best_index = index-2;
1962 bool full_first_step = mTakeFullFirstNewtonStep && mFirstStep;
1966 if (initial_norm_resid < current_resid_norm && !full_first_step)
1969 EXCEPTION(
"Residual does not appear to decrease in newton direction, quitting");
1974 if (full_first_step)
1978 std::cout <<
"\tTaking full first Newton step...\n";
1985 std::cout <<
"\tChoosing s = " << damping_values[best_index] <<
"\n" << std::flush;
2020 VectorSum(old_solution, update, -damping_values[best_index], this->mCurrentSolution);
2022 mLastDampingValue = damping_values[best_index];
2023 return current_resid_norm;
2026 template<
unsigned DIM>
2031 template<
unsigned DIM>
2034 mLastDampingValue = 0;
2036 if (mWriteOutputEachNewtonIteration)
2038 this->WriteCurrentSpatialSolution(
"newton_iteration",
"nodes", 0);
2042 double norm_resid = ComputeResidualAndGetNorm(
false);
2045 std::cout <<
"\nNorm of residual is " << norm_resid <<
"\n";
2048 mNumNewtonIterations = 0;
2049 unsigned iteration_number = 1;
2053 tol = NEWTON_REL_TOL*norm_resid;
2056 if (tol > MAX_NEWTON_ABS_TOL)
2058 tol = MAX_NEWTON_ABS_TOL;
2060 if (tol < MIN_NEWTON_ABS_TOL)
2062 tol = MIN_NEWTON_ABS_TOL;
2069 std::cout <<
"Solving with tolerance " << tol <<
"\n";
2072 while (norm_resid > tol)
2076 std::cout <<
"\n-------------------\n"
2077 <<
"Newton iteration " << iteration_number
2078 <<
":\n-------------------\n";
2082 mFirstStep = (iteration_number==1);
2083 norm_resid = TakeNewtonStep();
2087 std::cout <<
"Norm of residual is " << norm_resid <<
"\n";
2090 if (mWriteOutputEachNewtonIteration)
2092 this->WriteCurrentSpatialSolution(
"newton_iteration",
"nodes", iteration_number);
2095 mNumNewtonIterations = iteration_number;
2097 PostNewtonStep(iteration_number,norm_resid);
2100 if (iteration_number==20)
2103 EXCEPTION(
"Not converged after 20 newton iterations, quitting");
2108 if (norm_resid > tol)
2116 template<
unsigned DIM>
2119 return mNumNewtonIterations;
2126 template<
unsigned DIM>
2131 VecDuplicate(this->mResidualVector, &initial_guess);
2132 double* p_initial_guess;
2133 VecGetArray(initial_guess, &p_initial_guess);
2135 VecGetOwnershipRange(initial_guess, &lo, &hi);
2136 for (
int global_index=lo; global_index<hi; global_index++)
2138 int local_index = global_index - lo;
2139 p_initial_guess[local_index] = this->mCurrentSolution[global_index];
2141 VecRestoreArray(initial_guess, &p_initial_guess);
2144 Vec snes_residual_vec;
2145 VecDuplicate(this->mResidualVector, &snes_residual_vec);
2149 SNESCreate(PETSC_COMM_WORLD, &snes);
2150 SNESSetFunction(snes, snes_residual_vec, &AbstractNonlinearElasticitySolver_ComputeResidual<DIM>,
this);
2151 SNESSetJacobian(snes, mrJacobianMatrix, this->mPreconditionMatrix, &AbstractNonlinearElasticitySolver_ComputeJacobian<DIM>,
this);
2152 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 4) //PETSc 3.4 or later
2153 SNESSetType(snes, SNESNEWTONLS);
2155 SNESSetType(snes, SNESLS);
2157 SNESSetTolerances(snes, 1e-5, 1e-5, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
2159 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR == 3) //PETSc 3.3
2160 SNESLineSearch linesearch;
2161 SNESGetSNESLineSearch(snes, &linesearch);
2163 SNESLineSearchSetType(linesearch,
"cp");
2164 #elif (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 4) //PETSc 3.4 or later
2165 SNESLineSearch linesearch;
2166 SNESGetLineSearch(snes, &linesearch);
2168 SNESLineSearchSetType(linesearch,
"cp");
2171 SNESSetMaxLinearSolveFailures(snes,100);
2174 SNESGetKSP(snes, &ksp);
2176 KSPSetTolerances(ksp, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1000 );
2179 SetKspSolverAndPcType(ksp);
2185 SNESSetFromOptions(snes);
2187 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
2188 PetscErrorCode err = SNESSolve(snes, initial_guess);
2190 PetscErrorCode err = SNESSolve(snes, PETSC_NULL, initial_guess);
2193 SNESConvergedReason reason;
2194 SNESGetConvergedReason(snes,&reason);
2199 std::stringstream err_stream;
2204 EXCEPTION(
"Nonlinear Solver failed. PETSc error code: "+err_stream.str()+
" .");
2209 std::stringstream reason_stream;
2210 reason_stream << reason;
2214 EXCEPTION(
"Nonlinear Solver did not converge. PETSc reason code: "+reason_stream.str()+
" .");
2219 SNESGetIterationNumber(snes,&num_iters);
2220 mNumNewtonIterations = num_iters;
2227 template<
unsigned DIM>
2235 for (
unsigned i=0; i<guess_repl.
GetSize(); i++)
2237 this->mCurrentSolution[i] = guess_repl[i];
2239 AssembleSystem(
true,
false);
2240 VecCopy(this->mResidualVector, residualVector);
2243 template<
unsigned DIM>
2253 assert(mrJacobianMatrix==*pJacobian);
2254 assert(this->mPreconditionMatrix==*pPreconditioner);
2258 for (
unsigned i=0; i<guess_repl.
GetSize(); i++)
2260 this->mCurrentSolution[i] = guess_repl[i];
2263 AssembleSystem(
false,
true);
2267 template<
unsigned DIM>
2268 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeResidual(SNES snes,
2279 template<
unsigned DIM>
2280 #if ((PETSC_VERSION_MAJOR==3) && (PETSC_VERSION_MINOR>=5))
2281 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeJacobian(SNES snes,
2289 p_solver->
ComputeJacobian(currentGuess, &globalJacobian, &preconditioner);
2293 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeJacobian(SNES snes,
2295 Mat* pGlobalJacobian,
2296 Mat* pPreconditioner,
2297 MatStructure* pMatStructure,
2302 p_solver->
ComputeJacobian(currentGuess, pGlobalJacobian, pPreconditioner);
2310 template<
unsigned DIM>
2313 template<
unsigned DIM>
2316 template<
unsigned DIM>
void SetComputeAverageStressPerElementDuringSolve(bool setComputeAverageStressPerElement=true)
ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
void GetElementCentroidStrain(StrainType strainType, Element< DIM, DIM > &rElement, c_matrix< double, DIM, DIM > &rDeformationGradient)
static double NEWTON_REL_TOL
c_vector< double, DIM > & rGetLocation()
boost::numeric::ublas::c_matrix< T, 1, 1 > Inverse(const boost::numeric::ublas::c_matrix< T, 1, 1 > &rM)
AbstractNonlinearElasticitySolver(AbstractTetrahedralMesh< DIM, DIM > &rQuadMesh, SolidMechanicsProblemDefinition< DIM > &rProblemDefinition, std::string outputDirectory, CompressibilityType compressibilityType)
unsigned GetNodeGlobalIndex(unsigned localIndex) const
void SetCurrentTime(double time)
unsigned GetNumNewtonIterations()
#define EXCEPTION(message)
static void BeginEvent(unsigned event)
virtual void AddActiveStressAndStressDerivative(c_matrix< double, DIM, DIM > &rC, unsigned elementIndex, unsigned currentQuadPointGlobalIndex, c_matrix< double, DIM, DIM > &rT, FourthOrderTensor< DIM, DIM, DIM, DIM > &rDTdE, bool addToDTdE)
std::vector< c_vector< double, DIM *(DIM+1)/2 > > mAverageStressesPerElement
static void ComputeTransformedBasisFunctionDerivatives(const ChastePoint< ELEMENT_DIM > &rPoint, const c_matrix< double, ELEMENT_DIM, ELEMENT_DIM > &rInverseJacobian, c_matrix< double, ELEMENT_DIM,(ELEMENT_DIM+1)*(ELEMENT_DIM+2)/2 > &rReturnValue)
T Determinant(const boost::numeric::ublas::c_matrix< T, 1, 1 > &rM)
bool mTakeFullFirstNewtonStep
c_matrix< double, DIM, DIM > GetAverageStressPerElement(unsigned elementIndex)
AbstractNonlinearElasticitySolver< DIM > * mpSolver
virtual void SetupChangeOfBasisMatrix(unsigned elementIndex, unsigned currentQuadPointGlobalIndex)
bool mCheckedOutwardNormals
static void PrintAndReset(std::string message)
void PrintLineSearchResult(double s, double residNorm)
bool OptionExists(const std::string &rOption)
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
void Visit(Element< DIM, DIM > *pElement, unsigned localIndex, c_vector< double, DIM *DIM > &rData)
static const size_t BOUNDARY_STENCIL_SIZE
static const size_t NUM_NODES_PER_ELEMENT
double CalculateResidualNorm()
void SetTakeFullFirstNewtonStep(bool takeFullFirstStep=true)
SolidMechanicsProblemDefinition< DIM > & mrProblemDefinition
virtual void AssembleSystem(bool assembleResidual, bool assembleLinearSystem)=0
StressPerElementWriter(AbstractTetrahedralMesh< DIM, DIM > *pMesh, AbstractNonlinearElasticitySolver< DIM > *pSolver)
virtual void PostNewtonStep(unsigned counter, double normResidual)
void SolveNonSnes(double tol=-1.0)
static double MAX_NEWTON_ABS_TOL
void SetKspAbsoluteTolerance(double kspAbsoluteTolerance)
static const size_t NUM_NODES_PER_BOUNDARY_ELEMENT
static void ComputeBasisFunctions(const ChastePoint< ELEMENT_DIM > &rPoint, c_vector< double,(ELEMENT_DIM+1)*(ELEMENT_DIM+2)/2 > &rReturnValue)
c_matrix< double, DIM, DIM > mChangeOfBasisMatrix
void Solve(double tol=-1.0)
virtual void SetKspSolverAndPcType(KSP solver)
unsigned GetNumNodes() const
bool mSetComputeAverageStressPerElement
virtual ~AbstractNonlinearElasticitySolver()
std::vector< c_vector< double, DIM > > & rGetSpatialSolution()
bool mIncludeActiveTension
void AssembleOnBoundaryElementForPressureOnDeformedBc(BoundaryElement< DIM-1, DIM > &rBoundaryElement, c_matrix< double, BOUNDARY_STENCIL_SIZE, BOUNDARY_STENCIL_SIZE > &rAelem, c_vector< double, BOUNDARY_STENCIL_SIZE > &rBelem, bool assembleResidual, bool assembleJacobian, unsigned boundaryConditionIndex)
double UpdateSolutionUsingLineSearch(Vec solution)
void ComputeResidual(Vec currentGuess, Vec residualVector)
void AssembleOnBoundaryElement(BoundaryElement< DIM-1, DIM > &rBoundaryElement, c_matrix< double, BOUNDARY_STENCIL_SIZE, BOUNDARY_STENCIL_SIZE > &rAelem, c_vector< double, BOUNDARY_STENCIL_SIZE > &rBelem, bool assembleResidual, bool assembleJacobian, unsigned boundaryConditionIndex)
bool mWriteOutputEachNewtonIteration
void AddStressToAverageStressPerElement(c_matrix< double, DIM, DIM > &rT, unsigned elementIndex)
c_vector< double, SPACE_DIM > CalculateNormal()
void VectorSum(std::vector< double > &rX, ReplicatableVector &rY, double a, std::vector< double > &rZ)
void WriteCurrentAverageElementStresses(std::string fileName, int counterToAppend=-1)
unsigned mNumNewtonIterations
void ComputeJacobian(Vec currentGuess, Mat *pJacobian, Mat *pPreconditioner)
unsigned GetIndex() const
void SetWriteOutputEachNewtonIteration(bool writeOutputEachNewtonIteration=true)
static CommandLineArguments * Instance()
static double MIN_NEWTON_ABS_TOL
virtual void FinishAssembleSystem(bool assembleResidual, bool assembleLinearSystem)
static void EndEvent(unsigned event)
void SetIncludeActiveTension(bool includeActiveTension=true)
void WriteCurrentStrains(StrainType strainType, std::string fileName, int counterToAppend=-1)
bool ShouldAssembleMatrixTermForPressureOnDeformedBc()
c_vector< double, SPACE_DIM+1 > CalculateInterpolationWeights(const ChastePoint< SPACE_DIM > &rTestPoint)
void SetUsePetscDirectSolve(bool usePetscDirectSolve=true)
FourthOrderTensor< DIM, DIM, DIM, DIM > dTdE
double ComputeResidualAndGetNorm(bool allowException)
static const size_t NUM_VERTICES_PER_ELEMENT
std::vector< c_vector< double, DIM > > & rGetDeformedPosition()