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"
64 typedef enum StrainType_
66 DEFORMATION_GRADIENT_F = 0,
74 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
92 template<
unsigned DIM>
93 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeResidual(SNES snes,
98 #if ( PETSC_VERSION_MAJOR==3 && PETSC_VERSION_MINOR>=5 )
111 template<
unsigned DIM>
112 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeJacobian(SNES snes,
129 template<
unsigned DIM>
130 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeJacobian(SNES snes,
132 Mat* pGlobalJacobian,
133 Mat* pPreconditioner,
134 MatStructure* pMatStructure,
138 template <
unsigned DIM>
147 template<
unsigned DIM>
177 assert(localIndex == pElement->
GetIndex());
179 c_matrix<double, DIM, DIM> data =
mpSolver->GetAverageStressPerElement(localIndex);
180 for (
unsigned i=0; i<DIM; i++)
182 for (
unsigned j=0; j<DIM; j++)
184 rData[i*DIM+j] = data(i,j);
201 template<
unsigned DIM>
380 virtual void AssembleSystem(
bool assembleResidual,
bool assembleLinearSystem)=0;
409 c_matrix<double,DIM,DIM>& rDeformationGradient);
430 unsigned elementIndex,
431 unsigned currentQuadPointGlobalIndex,
432 c_matrix<double,DIM,DIM>& rT,
471 c_matrix<double, BOUNDARY_STENCIL_SIZE, BOUNDARY_STENCIL_SIZE>& rAelem,
472 c_vector<double, BOUNDARY_STENCIL_SIZE>& rBelem,
473 bool assembleResidual,
474 bool assembleJacobian,
475 unsigned boundaryConditionIndex);
514 c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
515 c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
516 bool assembleResidual,
517 bool assembleJacobian,
518 unsigned boundaryConditionIndex);
589 virtual void PostNewtonStep(
unsigned counter,
double normResidual);
643 std::string outputDirectory,
644 CompressibilityType compressibilityType);
656 void Solve(
double tol=-1.0);
698 assert(kspAbsoluteTolerance > 0);
770 void WriteCurrentStrains(StrainType strainType, std::string fileName,
int counterToAppend = -1);
822 template<
unsigned DIM>
825 std::string outputDirectory,
826 CompressibilityType compressibilityType)
828 mrProblemDefinition(rProblemDefinition),
829 mrJacobianMatrix(this->mSystemLhsMatrix),
831 mWriteOutputEachNewtonIteration(false),
832 mNumNewtonIterations(0),
834 mCheckedOutwardNormals(false),
835 mLastDampingValue(0.0),
836 mIncludeActiveTension(true),
837 mSetComputeAverageStressPerElement(false)
848 template<
unsigned DIM>
854 template<
unsigned DIM>
859 if (assembleJacobian)
864 VecCopy(this->mResidualVector, this->mLinearSystemRhsVector);
870 this->ApplyDirichletBoundaryConditions(NONLINEAR_PROBLEM_APPLY_TO_EVERYTHING, this->mCompressibilityType==COMPRESSIBLE);
872 else if (assembleResidual)
874 this->ApplyDirichletBoundaryConditions(NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY, this->mCompressibilityType==COMPRESSIBLE);
877 if (assembleResidual)
881 if (assembleJacobian)
890 template<
unsigned DIM>
893 this->mSpatialSolution.clear();
894 this->mSpatialSolution.resize(this->mrQuadMesh.GetNumNodes(), zero_vector<double>(DIM));
895 for (
unsigned i=0; i<this->mrQuadMesh.GetNumNodes(); i++)
897 for (
unsigned j=0; j<DIM; j++)
899 this->mSpatialSolution[i](j) = this->mrQuadMesh.GetNode(i)->rGetLocation()[j] + this->mCurrentSolution[this->mProblemDimension*i+j];
902 return this->mSpatialSolution;
905 template<
unsigned DIM>
908 return rGetSpatialSolution();
912 template<
unsigned DIM>
915 if (!this->mWriteOutput)
920 std::stringstream file_name;
921 file_name << fileName;
922 if (counterToAppend >= 0)
924 file_name <<
"_" << counterToAppend;
926 file_name <<
".strain";
928 out_stream p_file = this->mpOutputFileHandler->OpenOutputFile(file_name.str());
930 c_matrix<double,DIM,DIM> strain;
933 iter != this->mrQuadMesh.GetElementIteratorEnd();
936 GetElementCentroidStrain(strainType, *iter, strain);
937 for(
unsigned i=0; i<DIM; i++)
939 for(
unsigned j=0; j<DIM; j++)
941 *p_file << strain(i,j) <<
" ";
951 template<
unsigned DIM>
954 if (!this->mWriteOutput)
959 if(!mSetComputeAverageStressPerElement)
961 EXCEPTION(
"Call SetComputeAverageStressPerElementDuringSolve() before solve if calling WriteCurrentAverageElementStresses()");
964 std::stringstream file_name;
965 file_name << fileName;
966 if (counterToAppend >= 0)
968 file_name <<
"_" << counterToAppend;
970 file_name <<
".stress";
971 assert(mAverageStressesPerElement.size()==this->mrQuadMesh.GetNumElements());
974 stress_writer.WriteData(*(this->mpOutputFileHandler), file_name.str());
978 template<
unsigned DIM>
981 if (this->mOutputDirectory==
"")
983 EXCEPTION(
"No output directory was given so no output was written, cannot convert to cmgui format");
989 WRITE_QUADRATIC_MESH);
991 std::vector<c_vector<double,DIM> >& r_deformed_positions = this->rGetDeformedPosition();
997 template<
unsigned DIM>
1000 mSetComputeAverageStressPerElement = setComputeAverageStressPerElement;
1001 if(setComputeAverageStressPerElement && mAverageStressesPerElement.size()==0)
1003 mAverageStressesPerElement.resize(this->mrQuadMesh.GetNumElements(), zero_vector<double>(DIM*(DIM+1)/2));
1007 template<
unsigned DIM>
1010 assert(mSetComputeAverageStressPerElement);
1011 assert(elemIndex<this->mrQuadMesh.GetNumElements());
1021 for(
unsigned i=0; i<DIM*(DIM+1)/2; i++)
1032 row = i<=2 ? 0 : (i<=4? 1 : 2);
1033 col = i==0 ? 0 : (i==1 || i==3? 1 : 2);
1036 this->mAverageStressesPerElement[elemIndex](i) += rT(row,col);
1041 template<
unsigned DIM>
1044 if(!mSetComputeAverageStressPerElement)
1046 EXCEPTION(
"Call SetComputeAverageStressPerElementDuringSolve() before solve if calling GetAverageStressesPerElement()");
1048 assert(elementIndex<this->mrQuadMesh.GetNumElements());
1050 c_matrix<double,DIM,DIM> stress;
1062 stress(0,0) = mAverageStressesPerElement[elementIndex](0);
1063 stress(1,0) = stress(0,1) = mAverageStressesPerElement[elementIndex](1);
1064 stress(1,1) = mAverageStressesPerElement[elementIndex](2);
1068 stress(0,0) = mAverageStressesPerElement[elementIndex](0);
1069 stress(1,0) = stress(0,1) = mAverageStressesPerElement[elementIndex](1);
1070 stress(2,0) = stress(0,2) = mAverageStressesPerElement[elementIndex](2);
1071 stress(1,1) = mAverageStressesPerElement[elementIndex](3);
1072 stress(2,1) = stress(1,2) = mAverageStressesPerElement[elementIndex](4);
1073 stress(2,2) = mAverageStressesPerElement[elementIndex](5);
1084 template<
unsigned DIM>
1087 c_matrix<double,DIM,DIM>& rStrain)
1089 static c_matrix<double,DIM,DIM> jacobian;
1090 static c_matrix<double,DIM,DIM> inverse_jacobian;
1091 double jacobian_determinant;
1093 this->mrQuadMesh.GetInverseJacobianForElement(rElement.
GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
1096 static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
1097 for (
unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
1099 for (
unsigned JJ=0; JJ<DIM; JJ++)
1101 element_current_displacements(JJ,II) = this->mCurrentSolution[this->mProblemDimension*rElement.
GetNodeGlobalIndex(II) + JJ];
1106 static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi;
1107 static c_matrix<double,DIM,DIM> grad_u;
1128 grad_u = zero_matrix<double>(DIM,DIM);
1129 for (
unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++)
1131 for (
unsigned i=0; i<DIM; i++)
1133 for (
unsigned M=0; M<DIM; M++)
1135 grad_u(i,M) += grad_quad_phi(M,node_index)*element_current_displacements(i,node_index);
1140 c_matrix<double,DIM,DIM> deformation_gradient;
1142 for (
unsigned i=0; i<DIM; i++)
1144 for (
unsigned M=0; M<DIM; M++)
1146 deformation_gradient(i,M) = (i==M?1:0) + grad_u(i,M);
1152 case DEFORMATION_GRADIENT_F:
1154 rStrain = deformation_gradient;
1157 case DEFORMATION_TENSOR_C:
1159 rStrain = prod(trans(deformation_gradient),deformation_gradient);
1162 case LAGRANGE_STRAIN_E:
1164 c_matrix<double,DIM,DIM> C = prod(trans(deformation_gradient),deformation_gradient);
1165 for (
unsigned M=0; M<DIM; M++)
1167 for (
unsigned N=0; N<DIM; N++)
1169 rStrain(M,N) = 0.5* ( C(M,N)-(M==N?1:0) );
1184 template<
unsigned DIM>
1187 c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
1188 c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
1189 bool assembleResidual,
1190 bool assembleJacobian,
1191 unsigned boundaryConditionIndex)
1193 if( this->mrProblemDefinition.GetTractionBoundaryConditionType() == PRESSURE_ON_DEFORMED
1194 || this->mrProblemDefinition.GetTractionBoundaryConditionType() == FUNCTIONAL_PRESSURE_ON_DEFORMED)
1196 AssembleOnBoundaryElementForPressureOnDeformedBc(rBoundaryElement, rAelem, rBelem,
1197 assembleResidual, assembleJacobian, boundaryConditionIndex);
1204 if (assembleJacobian && !assembleResidual)
1210 c_vector<double, DIM> weighted_direction;
1211 double jacobian_determinant;
1212 this->mrQuadMesh.GetWeightedDirectionForBoundaryElement(rBoundaryElement.
GetIndex(), weighted_direction, jacobian_determinant);
1214 c_vector<double,NUM_NODES_PER_BOUNDARY_ELEMENT> phi;
1216 for (
unsigned quad_index=0; quad_index<this->mpBoundaryQuadratureRule->GetNumQuadPoints(); quad_index++)
1218 double wJ = jacobian_determinant * this->mpBoundaryQuadratureRule->GetWeight(quad_index);
1220 const ChastePoint<DIM-1>& quad_point = this->mpBoundaryQuadratureRule->rGetQuadPoint(quad_index);
1226 c_vector<double,DIM> traction = zero_vector<double>(DIM);
1227 switch (this->mrProblemDefinition.GetTractionBoundaryConditionType())
1229 case FUNCTIONAL_TRACTION:
1231 c_vector<double,DIM> X = zero_vector<double>(DIM);
1232 for (
unsigned node_index=0; node_index<NUM_NODES_PER_BOUNDARY_ELEMENT; node_index++)
1234 X += phi(node_index)*this->mrQuadMesh.GetNode( rBoundaryElement.
GetNodeGlobalIndex(node_index) )->rGetLocation();
1236 traction = this->mrProblemDefinition.EvaluateTractionFunction(X, this->mCurrentTime);
1239 case ELEMENTWISE_TRACTION:
1241 traction = this->mrProblemDefinition.rGetElementwiseTractions()[boundaryConditionIndex];
1249 for (
unsigned index=0; index<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index++)
1251 unsigned spatial_dim = index%DIM;
1252 unsigned node_index = (index-spatial_dim)/DIM;
1254 assert(node_index < NUM_NODES_PER_BOUNDARY_ELEMENT);
1256 rBelem(index) -= traction(spatial_dim)
1263 template<
unsigned DIM>
1281 return (mLastDampingValue >= 0.5);
1286 template<
unsigned DIM>
1289 c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
1290 c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
1291 bool assembleResidual,
1292 bool assembleJacobian,
1293 unsigned boundaryConditionIndex)
1295 assert( this->mrProblemDefinition.GetTractionBoundaryConditionType()==PRESSURE_ON_DEFORMED
1296 || this->mrProblemDefinition.GetTractionBoundaryConditionType()==FUNCTIONAL_PRESSURE_ON_DEFORMED);
1301 c_vector<double, DIM> weighted_direction;
1302 double jacobian_determinant;
1304 this->mrQuadMesh.GetWeightedDirectionForBoundaryElement(rBoundaryElement.
GetIndex(), weighted_direction, jacobian_determinant);
1314 std::set<unsigned> potential_elements = rBoundaryElement.
GetNode(0)->rGetContainingElementIndices();
1315 for(std::set<unsigned>::iterator iter = potential_elements.begin();
1316 iter != potential_elements.end();
1319 p_containing_vol_element = this->mrQuadMesh.GetElement(*iter);
1321 bool this_vol_ele_contains_surf_ele =
true;
1323 for(
unsigned i=1; i<NUM_NODES_PER_BOUNDARY_ELEMENT; i++)
1326 bool found_this_node =
false;
1327 for(
unsigned j=0; j<p_containing_vol_element->
GetNumNodes(); j++)
1330 if(surf_element_node_index == vol_element_node_index)
1332 found_this_node =
true;
1336 if(!found_this_node)
1338 this_vol_ele_contains_surf_ele =
false;
1342 if(this_vol_ele_contains_surf_ele)
1349 std::vector<unsigned> surf_to_vol_map(NUM_NODES_PER_BOUNDARY_ELEMENT);
1350 for(
unsigned i=0; i<NUM_NODES_PER_BOUNDARY_ELEMENT; i++)
1353 for(
unsigned j=0; j<NUM_NODES_PER_ELEMENT; j++)
1357 surf_to_vol_map[i] = j;
1366 static c_matrix<double,DIM,DIM> jacobian_vol_element;
1367 static c_matrix<double,DIM,DIM> inverse_jacobian_vol_element;
1368 double jacobian_determinant_vol_element;
1369 this->mrQuadMesh.GetInverseJacobianForElement(p_containing_vol_element->
GetIndex(), jacobian_vol_element, jacobian_determinant_vol_element, inverse_jacobian_vol_element);
1372 static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
1373 for (
unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
1375 for (
unsigned JJ=0; JJ<DIM; JJ++)
1377 element_current_displacements(JJ,II) = this->mCurrentSolution[this->mProblemDimension*p_containing_vol_element->
GetNodeGlobalIndex(II) + JJ];
1383 static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi_vol_element;
1385 c_vector<double,NUM_NODES_PER_BOUNDARY_ELEMENT> quad_phi_surf_element;
1387 static c_matrix<double, DIM, NUM_NODES_PER_BOUNDARY_ELEMENT> grad_quad_phi_surf_element;
1389 c_matrix<double,DIM,DIM> F;
1390 c_matrix<double,DIM,DIM> invF;
1393 c_matrix<double,1,DIM> normal_as_mat;
1394 for(
unsigned i=0; i<DIM; i++)
1396 normal_as_mat(0,i) = normal(i);
1399 double normal_pressure;
1400 switch (this->mrProblemDefinition.GetTractionBoundaryConditionType())
1402 case PRESSURE_ON_DEFORMED:
1403 normal_pressure = this->mrProblemDefinition.GetNormalPressure();
1405 case FUNCTIONAL_PRESSURE_ON_DEFORMED:
1406 normal_pressure = this->mrProblemDefinition.EvaluateNormalPressureFunction(this->mCurrentTime);
1414 for (
unsigned quad_index=0; quad_index<this->mpBoundaryQuadratureRule->GetNumQuadPoints(); quad_index++)
1416 double wJ = jacobian_determinant * this->mpBoundaryQuadratureRule->GetWeight(quad_index);
1420 const ChastePoint<DIM-1>& quadrature_point = this->mpBoundaryQuadratureRule->rGetQuadPoint(quad_index);
1427 c_vector<double,DIM> X = zero_vector<double>(DIM);
1428 for (
unsigned node_index=0; node_index<NUM_NODES_PER_BOUNDARY_ELEMENT; node_index++)
1430 X += quad_phi_surf_element(node_index)*rBoundaryElement.
GetNode(node_index)->rGetLocation();
1436 c_vector<double,DIM> xi;
1437 for(
unsigned i=0; i<DIM; i++)
1439 xi(i) = weight(i+1);
1445 assert( DIM!=2 || (fabs(weight(0))<1e-6) || (fabs(weight(1))<1e-6) || (fabs(weight(2))<1e-6) );
1449 #define COVERAGE_IGNORE
1450 assert( DIM!=3 || (fabs(weight(0))<1e-6) || (fabs(weight(1))<1e-6) || (fabs(weight(2))<1e-6) || (fabs(weight(3))<1e-6) );
1451 #undef COVERAGE_IGNORE
1457 F = identity_matrix<double>(DIM,DIM);
1458 for (
unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++)
1460 for (
unsigned i=0; i<DIM; i++)
1462 for (
unsigned M=0; M<DIM; M++)
1464 F(i,M) += grad_quad_phi_vol_element(M,node_index)*element_current_displacements(i,node_index);
1472 if(assembleResidual)
1474 c_vector<double,DIM> traction = detF*normal_pressure*prod(trans(invF),normal);
1477 for (
unsigned index=0; index<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index++)
1479 unsigned spatial_dim = index%DIM;
1480 unsigned node_index = (index-spatial_dim)/DIM;
1482 assert(node_index < NUM_NODES_PER_BOUNDARY_ELEMENT);
1484 rBelem(index) -= traction(spatial_dim)
1485 * quad_phi_surf_element(node_index)
1494 if(assembleJacobian && ShouldAssembleMatrixTermForPressureOnDeformedBc())
1496 for(
unsigned II=0; II<NUM_NODES_PER_BOUNDARY_ELEMENT; II++)
1498 for(
unsigned N=0; N<DIM; N++)
1500 grad_quad_phi_surf_element(N,II) = grad_quad_phi_vol_element(N,surf_to_vol_map[II]);
1505 for(
unsigned N=0; N<DIM; N++)
1507 for(
unsigned e=0; e<DIM; e++)
1509 for(
unsigned M=0; M<DIM; M++)
1511 for(
unsigned d=0; d<DIM; d++)
1513 tensor1(N,e,M,d) = invF(N,e)*invF(M,d) - invF(M,e)*invF(N,d);
1521 tensor2.template SetAsContractionOnFirstDimension<DIM>( trans(grad_quad_phi_surf_element), tensor1);
1526 tensor3.template SetAsContractionOnThirdDimension<DIM>( normal_as_mat, tensor2);
1528 for (
unsigned index1=0; index1<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index1++)
1530 unsigned spatial_dim1 = index1%DIM;
1531 unsigned node_index1 = (index1-spatial_dim1)/DIM;
1533 for (
unsigned index2=0; index2<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index2++)
1535 unsigned spatial_dim2 = index2%DIM;
1536 unsigned node_index2 = (index2-spatial_dim2)/DIM;
1538 rAelem(index1,index2) -= normal_pressure
1540 * tensor3(node_index2,spatial_dim2,0,spatial_dim1)
1541 * quad_phi_surf_element(node_index1)
1552 template<
unsigned DIM>
1557 mrProblemDefinition.Validate();
1564 if(mrProblemDefinition.GetTractionBoundaryConditionType()==PRESSURE_ON_DEFORMED && mCheckedOutwardNormals==
false)
1566 this->mrQuadMesh.CheckOutwardNormals();
1567 mCheckedOutwardNormals =
true;
1571 this->WriteCurrentSpatialSolution(
"initial",
"nodes");
1585 if(this->mCompressibilityType==INCOMPRESSIBLE)
1587 this->RemovePressureDummyValuesThroughLinearInterpolation();
1591 this->WriteCurrentSpatialSolution(
"solution",
"nodes");
1599 template<
unsigned DIM>
1610 KSPGetPC(solver, &pc);
1613 if (mPetscDirectSolve)
1615 if(this->mCompressibilityType==COMPRESSIBLE)
1617 KSPSetType(solver,KSPPREONLY);
1620 PCSetType(pc, PCLU);
1627 if (this->mCompressibilityType==COMPRESSIBLE)
1629 KSPSetType(solver,KSPCG);
1632 PCSetType(pc, PCICC);
1636 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later
1637 PetscOptionsSetValue(
"-pc_factor_shift_type",
"positive_definite");
1639 PetscOptionsSetValue(
"-pc_factor_shift_positive_definite",
"");
1644 PCSetType(pc, PCBJACOBI);
1649 unsigned num_restarts = 100;
1650 KSPSetType(solver,KSPGMRES);
1651 KSPGMRESSetRestart(solver,num_restarts);
1653 #ifndef MECH_USE_HYPRE
1654 PCSetType(pc, PCBJACOBI);
1660 PetscOptionsSetValue(
"-pc_hypre_type",
"boomeramg");
1664 PCSetType(pc, PCHYPRE);
1665 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >=2) //PETSc 3.2 or later
1666 KSPSetPCSide(solver, PC_RIGHT);
1668 KSPSetPreconditionerSide(solver, PC_RIGHT);
1688 template<
unsigned DIM>
1691 if (!allowException)
1694 AssembleSystem(
true,
false);
1701 AssembleSystem(
true,
false);
1711 return CalculateResidualNorm();
1714 template<
unsigned DIM>
1720 VecNorm(this->mResidualVector, NORM_2, &norm);
1721 return norm/this->mNumDofs;
1724 template<
unsigned DIM>
1728 std::vector<double>& rZ)
1730 assert(rX.size()==rY.
GetSize());
1731 assert(rY.
GetSize()==rZ.size());
1732 for (
unsigned i=0; i<rX.size(); i++)
1734 rZ[i] = rX[i] + a*rY[i];
1739 template<
unsigned DIM>
1751 AssembleSystem(
true,
true);
1764 VecDuplicate(this->mResidualVector,&solution);
1767 KSPCreate(PETSC_COMM_WORLD,&solver);
1769 #if ( PETSC_VERSION_MAJOR==3 && PETSC_VERSION_MINOR>=5 )
1770 KSPSetOperators(solver, mrJacobianMatrix, this->mPreconditionMatrix);
1772 KSPSetOperators(solver, mrJacobianMatrix, this->mPreconditionMatrix, DIFFERENT_NONZERO_PATTERN );
1776 SetKspSolverAndPcType(solver);
1781 KSPSetFromOptions(solver);
1788 if (mKspAbsoluteTol < 0)
1791 VecDuplicate(this->mResidualVector, &temp);
1793 VecDuplicate(this->mResidualVector, &temp2);
1794 Vec linsys_residual;
1795 VecDuplicate(this->mResidualVector, &linsys_residual);
1797 KSPInitialResidual(solver, solution, temp, temp2, linsys_residual, this->mLinearSystemRhsVector);
1798 double initial_resid_norm;
1799 VecNorm(linsys_residual, NORM_2, &initial_resid_norm);
1805 double ksp_rel_tol = 1e-6;
1806 double absolute_tol = ksp_rel_tol * initial_resid_norm;
1807 if(absolute_tol < 1e-12)
1809 absolute_tol = 1e-12;
1811 KSPSetTolerances(solver, 1e-16, absolute_tol, PETSC_DEFAULT, 1000 );
1815 KSPSetTolerances(solver, 1e-16, mKspAbsoluteTol, PETSC_DEFAULT, 1000 );
1823 KSPSolve(solver,this->mLinearSystemRhsVector,solution);
1849 KSPConvergedReason reason;
1850 KSPGetConvergedReason(solver,&reason);
1852 if(reason != KSP_DIVERGED_ITS)
1857 #define COVERAGE_IGNORE
1859 #undef COVERAGE_IGNORE
1869 #define COVERAGE_IGNORE
1870 WARN_ONCE_ONLY(
"Linear solve (within a mechanics solve) didn't converge, but this may not stop nonlinear solve converging")
1871 #undef COVERAGE_IGNORE
1876 KSPGetIterationNumber(solver, &num_iters);
1881 EXCEPTION(
"KSP Absolute tolerance was too high, linear system wasn't solved - there will be no decrease in Newton residual. Decrease KspAbsoluteTolerance");
1888 std::cout <<
"[" <<
PetscTools::GetMyRank() <<
"]: Num iterations = " << num_iters <<
"\n" << std::flush;
1907 double new_norm_resid = UpdateSolutionUsingLineSearch(solution);
1913 return new_norm_resid;
1917 template<
unsigned DIM>
1922 std::cout <<
"\tTesting s = " << s <<
", |f| = " << residNorm <<
"\n" << std::flush;
1926 template<
unsigned DIM>
1929 double initial_norm_resid = CalculateResidualNorm();
1932 std::cout <<
"\tInitial |f| [corresponding to s=0] is " << initial_norm_resid <<
"\n" << std::flush;
1937 std::vector<double> old_solution = this->mCurrentSolution;
1939 std::vector<double> damping_values;
1940 for (
unsigned i=10; i>=1; i--)
1942 damping_values.push_back((
double)i/10.0);
1944 damping_values.push_back(0.05);
1945 assert(damping_values.size()==11);
1950 VectorSum(old_solution, update, -damping_values[index], this->mCurrentSolution);
1951 double current_resid_norm = ComputeResidualAndGetNorm(
true);
1952 PrintLineSearchResult(damping_values[index], current_resid_norm);
1957 VectorSum(old_solution, update, -damping_values[index], this->mCurrentSolution);
1958 double next_resid_norm = ComputeResidualAndGetNorm(
true);
1959 PrintLineSearchResult(damping_values[index], next_resid_norm);
1964 while ( (next_resid_norm==DBL_MAX)
1965 || ( (next_resid_norm < current_resid_norm) && (index<damping_values.size()) ) )
1967 current_resid_norm = next_resid_norm;
1970 VectorSum(old_solution, update, -damping_values[index], this->mCurrentSolution);
1971 next_resid_norm = ComputeResidualAndGetNorm(
true);
1972 PrintLineSearchResult(damping_values[index], next_resid_norm);
1977 unsigned best_index;
1979 if (index==damping_values.size() && (next_resid_norm < current_resid_norm))
1986 #define COVERAGE_IGNORE
1989 current_resid_norm = next_resid_norm;
1990 best_index = index-1;
1991 #undef COVERAGE_IGNORE
1997 best_index = index-2;
2001 bool full_first_step = mTakeFullFirstNewtonStep && mFirstStep;
2005 if (initial_norm_resid < current_resid_norm && !full_first_step)
2007 #define COVERAGE_IGNORE
2008 EXCEPTION(
"Residual does not appear to decrease in newton direction, quitting");
2009 #undef COVERAGE_IGNORE
2017 std::cout <<
"\tTaking full first Newton step...\n";
2024 std::cout <<
"\tChoosing s = " << damping_values[best_index] <<
"\n" << std::flush;
2061 VectorSum(old_solution, update, -damping_values[best_index], this->mCurrentSolution);
2063 mLastDampingValue = damping_values[best_index];
2064 return current_resid_norm;
2067 template<
unsigned DIM>
2073 template<
unsigned DIM>
2076 mLastDampingValue = 0;
2078 if (mWriteOutputEachNewtonIteration)
2080 this->WriteCurrentSpatialSolution(
"newton_iteration",
"nodes", 0);
2084 double norm_resid = ComputeResidualAndGetNorm(
false);
2087 std::cout <<
"\nNorm of residual is " << norm_resid <<
"\n";
2090 mNumNewtonIterations = 0;
2091 unsigned iteration_number = 1;
2095 tol = NEWTON_REL_TOL*norm_resid;
2097 #define COVERAGE_IGNORE // not going to have tests in cts for everything
2098 if (tol > MAX_NEWTON_ABS_TOL)
2100 tol = MAX_NEWTON_ABS_TOL;
2102 if (tol < MIN_NEWTON_ABS_TOL)
2104 tol = MIN_NEWTON_ABS_TOL;
2106 #undef COVERAGE_IGNORE
2111 std::cout <<
"Solving with tolerance " << tol <<
"\n";
2114 while (norm_resid > tol)
2118 std::cout <<
"\n-------------------\n"
2119 <<
"Newton iteration " << iteration_number
2120 <<
":\n-------------------\n";
2124 mFirstStep = (iteration_number==1);
2125 norm_resid = TakeNewtonStep();
2129 std::cout <<
"Norm of residual is " << norm_resid <<
"\n";
2132 if (mWriteOutputEachNewtonIteration)
2134 this->WriteCurrentSpatialSolution(
"newton_iteration",
"nodes", iteration_number);
2137 mNumNewtonIterations = iteration_number;
2139 PostNewtonStep(iteration_number,norm_resid);
2142 if (iteration_number==20)
2144 #define COVERAGE_IGNORE
2145 EXCEPTION(
"Not converged after 20 newton iterations, quitting");
2146 #undef COVERAGE_IGNORE
2150 if (norm_resid > tol)
2152 #define COVERAGE_IGNORE
2154 #undef COVERAGE_IGNORE
2160 template<
unsigned DIM>
2163 return mNumNewtonIterations;
2173 template<
unsigned DIM>
2178 VecDuplicate(this->mResidualVector, &initial_guess);
2179 double* p_initial_guess;
2180 VecGetArray(initial_guess, &p_initial_guess);
2182 VecGetOwnershipRange(initial_guess, &lo, &hi);
2183 for (
int global_index=lo; global_index<hi; global_index++)
2185 int local_index = global_index - lo;
2186 p_initial_guess[local_index] = this->mCurrentSolution[global_index];
2188 VecRestoreArray(initial_guess, &p_initial_guess);
2191 Vec snes_residual_vec;
2192 VecDuplicate(this->mResidualVector, &snes_residual_vec);
2196 SNESCreate(PETSC_COMM_WORLD, &snes);
2197 SNESSetFunction(snes, snes_residual_vec, &AbstractNonlinearElasticitySolver_ComputeResidual<DIM>,
this);
2198 SNESSetJacobian(snes, mrJacobianMatrix, this->mPreconditionMatrix, &AbstractNonlinearElasticitySolver_ComputeJacobian<DIM>,
this);
2199 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 4) //PETSc 3.4 or later
2200 SNESSetType(snes, SNESNEWTONLS);
2202 SNESSetType(snes, SNESLS);
2204 SNESSetTolerances(snes,1e-5,1e-5,1e-5,PETSC_DEFAULT,PETSC_DEFAULT);
2205 SNESSetMaxLinearSolveFailures(snes,100);
2208 SNESGetKSP(snes, &ksp);
2210 KSPSetTolerances(ksp, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1000 );
2213 SetKspSolverAndPcType(ksp);
2217 PetscOptionsSetValue(
"-snes_monitor",
"");
2219 SNESSetFromOptions(snes);
2221 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
2222 PetscErrorCode err = SNESSolve(snes, initial_guess);
2224 PetscErrorCode err = SNESSolve(snes, PETSC_NULL, initial_guess);
2227 SNESConvergedReason reason;
2228 SNESGetConvergedReason(snes,&reason);
2230 #define COVERAGE_IGNORE
2233 std::stringstream err_stream;
2238 EXCEPTION(
"Nonlinear Solver failed. PETSc error code: "+err_stream.str()+
" .");
2243 std::stringstream reason_stream;
2244 reason_stream << reason;
2248 EXCEPTION(
"Nonlinear Solver did not converge. PETSc reason code: "+reason_stream.str()+
" .");
2250 #undef COVERAGE_IGNORE
2253 SNESGetIterationNumber(snes,&num_iters);
2254 mNumNewtonIterations = num_iters;
2262 template<
unsigned DIM>
2270 for(
unsigned i=0; i<guess_repl.
GetSize(); i++)
2272 this->mCurrentSolution[i] = guess_repl[i];
2274 AssembleSystem(
true,
false);
2275 VecCopy(this->mResidualVector, residualVector);
2278 template<
unsigned DIM>
2288 assert(mrJacobianMatrix==*pJacobian);
2289 assert(this->mPreconditionMatrix==*pPreconditioner);
2293 for(
unsigned i=0; i<guess_repl.
GetSize(); i++)
2295 this->mCurrentSolution[i] = guess_repl[i];
2298 AssembleSystem(
false,
true);
2304 template<
unsigned DIM>
2305 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeResidual(SNES snes,
2316 template<
unsigned DIM>
2317 #if ( PETSC_VERSION_MAJOR==3 && PETSC_VERSION_MINOR>=5 )
2318 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeJacobian(SNES snes,
2326 p_solver->
ComputeJacobian(currentGuess, &globalJacobian, &preconditioner);
2330 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeJacobian(SNES snes,
2332 Mat* pGlobalJacobian,
2333 Mat* pPreconditioner,
2334 MatStructure* pMatStructure,
2339 p_solver->
ComputeJacobian(currentGuess, pGlobalJacobian, pPreconditioner);
2347 template<
unsigned DIM>
2350 template<
unsigned DIM>
2353 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()