00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #include "CompressibleNonlinearElasticitySolver.hpp"
00049 #include "LinearBasisFunction.hpp"
00050 #include "QuadraticBasisFunction.hpp"
00051 #include <algorithm>
00052
00053 template<size_t DIM>
00054 void CompressibleNonlinearElasticitySolver<DIM>::AssembleSystem(bool assembleResidual,
00055 bool assembleJacobian)
00056 {
00057
00058 assert(assembleResidual || assembleJacobian);
00059 assert(this->mCurrentSolution.size()==this->mNumDofs);
00060
00061
00062 if (assembleResidual)
00063 {
00064 PetscVecTools::Finalise(this->mResidualVector);
00065 PetscVecTools::Zero(this->mResidualVector);
00066 }
00067 if (assembleJacobian)
00068 {
00069 PetscMatTools::Zero(this->mrJacobianMatrix);
00070 PetscMatTools::Zero(this->mPreconditionMatrix);
00071 }
00072
00073 c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem;
00074
00075
00076 c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem_precond;
00077 c_vector<double, STENCIL_SIZE> b_elem;
00078
00079
00080 for (typename AbstractTetrahedralMesh<DIM, DIM>::ElementIterator iter = this->mrQuadMesh.GetElementIteratorBegin();
00081 iter != this->mrQuadMesh.GetElementIteratorEnd();
00082 ++iter)
00083 {
00084 Element<DIM, DIM>& element = *iter;
00085
00086 if (element.GetOwnership() == true)
00087 {
00088 #define COVERAGE_IGNORE
00089
00090 if(CommandLineArguments::Instance()->OptionExists("-mech_very_verbose") && assembleJacobian)
00091 {
00092 std::cout << "\r[" << PetscTools::GetMyRank() << "]: Element " << (*iter).GetIndex() << " of " << this->mrQuadMesh.GetNumElements() << std::flush;
00093 }
00094 #undef COVERAGE_IGNORE
00095
00096 AssembleOnElement(element, a_elem, a_elem_precond, b_elem, assembleResidual, assembleJacobian);
00097
00101
00102
00103
00104
00105
00106
00107
00108
00109 unsigned p_indices[STENCIL_SIZE];
00110 for (unsigned i=0; i<NUM_NODES_PER_ELEMENT; i++)
00111 {
00112 for (unsigned j=0; j<DIM; j++)
00113 {
00114 p_indices[DIM*i+j] = DIM*element.GetNodeGlobalIndex(i) + j;
00115 }
00116 }
00117
00118 if (assembleJacobian)
00119 {
00120 PetscMatTools::AddMultipleValues<STENCIL_SIZE>(this->mrJacobianMatrix, p_indices, a_elem);
00121 PetscMatTools::AddMultipleValues<STENCIL_SIZE>(this->mPreconditionMatrix, p_indices, a_elem_precond);
00122 }
00123
00124 if (assembleResidual)
00125 {
00126 PetscVecTools::AddMultipleValues<STENCIL_SIZE>(this->mResidualVector, p_indices, b_elem);
00127 }
00128 }
00129 }
00130
00131
00132 c_vector<double, BOUNDARY_STENCIL_SIZE> b_boundary_elem;
00133 c_matrix<double, BOUNDARY_STENCIL_SIZE, BOUNDARY_STENCIL_SIZE> a_boundary_elem;
00134 if (this->mrProblemDefinition.GetTractionBoundaryConditionType() != NO_TRACTIONS)
00135 {
00136 for (unsigned bc_index=0; bc_index<this->mrProblemDefinition.rGetTractionBoundaryElements().size(); bc_index++)
00137 {
00138 BoundaryElement<DIM-1,DIM>& r_boundary_element = *(this->mrProblemDefinition.rGetTractionBoundaryElements()[bc_index]);
00139
00140
00141
00142
00143
00144
00145
00146
00147 this->AssembleOnBoundaryElement(r_boundary_element, a_boundary_elem, b_boundary_elem, assembleResidual, assembleJacobian, bc_index);
00148
00149 unsigned p_indices[BOUNDARY_STENCIL_SIZE];
00150 for (unsigned i=0; i<NUM_NODES_PER_BOUNDARY_ELEMENT; i++)
00151 {
00152 for (unsigned j=0; j<DIM; j++)
00153 {
00154 p_indices[DIM*i+j] = DIM*r_boundary_element.GetNodeGlobalIndex(i) + j;
00155 }
00156 }
00157
00158 if (assembleJacobian)
00159 {
00160 PetscMatTools::AddMultipleValues<BOUNDARY_STENCIL_SIZE>(this->mrJacobianMatrix, p_indices, a_boundary_elem);
00161 PetscMatTools::AddMultipleValues<BOUNDARY_STENCIL_SIZE>(this->mPreconditionMatrix, p_indices, a_boundary_elem);
00162 }
00163
00164 if (assembleResidual)
00165 {
00166 PetscVecTools::AddMultipleValues<BOUNDARY_STENCIL_SIZE>(this->mResidualVector, p_indices, b_boundary_elem);
00167 }
00168 }
00169 }
00170
00171 this->FinishAssembleSystem(assembleResidual, assembleJacobian);
00172 }
00173
00174 template<size_t DIM>
00175 void CompressibleNonlinearElasticitySolver<DIM>::AssembleOnElement(
00176 Element<DIM, DIM>& rElement,
00177 c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElem,
00178 c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElemPrecond,
00179 c_vector<double, STENCIL_SIZE>& rBElem,
00180 bool assembleResidual,
00181 bool assembleJacobian)
00182 {
00183 static c_matrix<double,DIM,DIM> jacobian;
00184 static c_matrix<double,DIM,DIM> inverse_jacobian;
00185 double jacobian_determinant;
00186
00187 this->mrQuadMesh.GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
00188
00189 if (assembleJacobian)
00190 {
00191 rAElem.clear();
00192 rAElemPrecond.clear();
00193 }
00194
00195 if (assembleResidual)
00196 {
00197 rBElem.clear();
00198 }
00199
00200
00201 static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
00202 for (unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
00203 {
00204 for (unsigned JJ=0; JJ<DIM; JJ++)
00205 {
00206 element_current_displacements(JJ,II) = this->mCurrentSolution[DIM*rElement.GetNodeGlobalIndex(II) + JJ];
00207 }
00208 }
00209
00210
00211 static c_vector<double, NUM_VERTICES_PER_ELEMENT> linear_phi;
00212 static c_vector<double, NUM_NODES_PER_ELEMENT> quad_phi;
00213 static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi;
00214 static c_matrix<double, NUM_NODES_PER_ELEMENT, DIM> trans_grad_quad_phi;
00215
00216
00217 AbstractCompressibleMaterialLaw<DIM>* p_material_law
00218 = this->mrProblemDefinition.GetCompressibleMaterialLaw(rElement.GetIndex());
00219
00220
00221 static c_matrix<double,DIM,DIM> grad_u;
00222
00223 static c_matrix<double,DIM,DIM> F;
00224 static c_matrix<double,DIM,DIM> C;
00225 static c_matrix<double,DIM,DIM> inv_C;
00226 static c_matrix<double,DIM,DIM> inv_F;
00227 static c_matrix<double,DIM,DIM> T;
00228
00229 static c_matrix<double,DIM,DIM> F_T;
00230 static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> F_T_grad_quad_phi;
00231
00232 c_vector<double,DIM> body_force;
00233
00234 static FourthOrderTensor<DIM,DIM,DIM,DIM> dTdE;
00235 static FourthOrderTensor<DIM,DIM,DIM,DIM> dSdF;
00236
00237 static FourthOrderTensor<NUM_NODES_PER_ELEMENT,DIM,DIM,DIM> temp_tensor;
00238 static FourthOrderTensor<NUM_NODES_PER_ELEMENT,DIM,NUM_NODES_PER_ELEMENT,DIM> dSdF_quad_quad;
00239
00240 static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> temp_matrix;
00241 static c_matrix<double,NUM_NODES_PER_ELEMENT,DIM> grad_quad_phi_times_invF;
00242
00243 if(this->mSetComputeAverageStressPerElement)
00244 {
00245 this->mAverageStressesPerElement[rElement.GetIndex()] = zero_vector<double>(DIM*(DIM+1)/2);
00246 }
00247
00248
00249 for (unsigned quadrature_index=0; quadrature_index < this->mpQuadratureRule->GetNumQuadPoints(); quadrature_index++)
00250 {
00251
00252 unsigned current_quad_point_global_index = rElement.GetIndex()*this->mpQuadratureRule->GetNumQuadPoints()
00253 + quadrature_index;
00254
00255 double wJ = jacobian_determinant * this->mpQuadratureRule->GetWeight(quadrature_index);
00256
00257 const ChastePoint<DIM>& quadrature_point = this->mpQuadratureRule->rGetQuadPoint(quadrature_index);
00258
00259
00260 LinearBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, linear_phi);
00261 QuadraticBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, quad_phi);
00262 QuadraticBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_quad_phi);
00263 trans_grad_quad_phi = trans(grad_quad_phi);
00264
00265
00266 if (assembleResidual)
00267 {
00268 switch (this->mrProblemDefinition.GetBodyForceType())
00269 {
00270 case FUNCTIONAL_BODY_FORCE:
00271 {
00272 c_vector<double,DIM> X = zero_vector<double>(DIM);
00273
00274 for (unsigned node_index=0; node_index<NUM_VERTICES_PER_ELEMENT; node_index++)
00275 {
00276 X += linear_phi(node_index)*this->mrQuadMesh.GetNode( rElement.GetNodeGlobalIndex(node_index) )->rGetLocation();
00277 }
00278 body_force = this->mrProblemDefinition.EvaluateBodyForceFunction(X, this->mCurrentTime);
00279 break;
00280 }
00281 case CONSTANT_BODY_FORCE:
00282 {
00283 body_force = this->mrProblemDefinition.GetConstantBodyForce();
00284 break;
00285 }
00286 default:
00287 NEVER_REACHED;
00288 }
00289 }
00290
00291
00292 grad_u = zero_matrix<double>(DIM,DIM);
00293 for (unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++)
00294 {
00295 for (unsigned i=0; i<DIM; i++)
00296 {
00297 for (unsigned M=0; M<DIM; M++)
00298 {
00299 grad_u(i,M) += grad_quad_phi(M,node_index)*element_current_displacements(i,node_index);
00300 }
00301 }
00302 }
00303
00304
00305 for (unsigned i=0; i<DIM; i++)
00306 {
00307 for (unsigned M=0; M<DIM; M++)
00308 {
00309 F(i,M) = (i==M?1:0) + grad_u(i,M);
00310 }
00311 }
00312
00313 C = prod(trans(F),F);
00314 inv_C = Inverse(C);
00315 inv_F = Inverse(F);
00316
00317
00318 this->SetupChangeOfBasisMatrix(rElement.GetIndex(), current_quad_point_global_index);
00319 p_material_law->SetChangeOfBasisMatrix(this->mChangeOfBasisMatrix);
00320 p_material_law->ComputeStressAndStressDerivative(C, inv_C, 0.0, T, dTdE, assembleJacobian);
00321
00322 if(this->mIncludeActiveTension)
00323 {
00324
00325
00326 this->AddActiveStressAndStressDerivative(C, rElement.GetIndex(), current_quad_point_global_index,
00327 T, dTdE, assembleJacobian);
00328 }
00329
00330 if(this->mSetComputeAverageStressPerElement)
00331 {
00332 this->AddStressToAverageStressPerElement(T,rElement.GetIndex());
00333 }
00334
00335
00336 if (assembleResidual)
00337 {
00338 F_T = prod(F,T);
00339 F_T_grad_quad_phi = prod(F_T, grad_quad_phi);
00340
00341 for (unsigned index=0; index<NUM_NODES_PER_ELEMENT*DIM; index++)
00342 {
00343 unsigned spatial_dim = index%DIM;
00344 unsigned node_index = (index-spatial_dim)/DIM;
00345
00346 rBElem(index) += - this->mrProblemDefinition.GetDensity()
00347 * body_force(spatial_dim)
00348 * quad_phi(node_index)
00349 * wJ;
00350
00351
00352 rBElem(index) += F_T_grad_quad_phi(spatial_dim,node_index)
00353 * wJ;
00354 }
00355 }
00356
00357
00358 if (assembleJacobian)
00359 {
00360
00361 grad_quad_phi_times_invF = prod(trans_grad_quad_phi, inv_F);
00362
00364
00365
00366
00367
00368
00369
00370
00371
00372
00374
00375
00376 for (unsigned M=0; M<DIM; M++)
00377 {
00378 for (unsigned N=0; N<DIM; N++)
00379 {
00380 for (unsigned P=0; P<DIM; P++)
00381 {
00382 for (unsigned Q=0; Q<DIM; Q++)
00383 {
00384
00385 dSdF(M,N,P,Q) = 0.5*(dTdE(M,N,P,Q) + dTdE(M,N,Q,P));
00386 }
00387 }
00388 }
00389 }
00390
00391
00392 dTdE.template SetAsContractionOnSecondDimension<DIM>(F, dSdF);
00393
00394
00395 dSdF.template SetAsContractionOnFourthDimension<DIM>(F, dTdE);
00396
00397
00398 for (unsigned M=0; M<DIM; M++)
00399 {
00400 for (unsigned N=0; N<DIM; N++)
00401 {
00402 for (unsigned i=0; i<DIM; i++)
00403 {
00404 dSdF(M,i,N,i) += T(M,N);
00405 }
00406 }
00407 }
00408
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00421 temp_tensor.template SetAsContractionOnFirstDimension<DIM>(trans_grad_quad_phi, dSdF);
00422 dSdF_quad_quad.template SetAsContractionOnThirdDimension<DIM>(trans_grad_quad_phi, temp_tensor);
00423
00424 for (unsigned index1=0; index1<NUM_NODES_PER_ELEMENT*DIM; index1++)
00425 {
00426 unsigned spatial_dim1 = index1%DIM;
00427 unsigned node_index1 = (index1-spatial_dim1)/DIM;
00428
00429 for (unsigned index2=0; index2<NUM_NODES_PER_ELEMENT*DIM; index2++)
00430 {
00431 unsigned spatial_dim2 = index2%DIM;
00432 unsigned node_index2 = (index2-spatial_dim2)/DIM;
00433
00434
00435 rAElem(index1,index2) += dSdF_quad_quad(node_index1,spatial_dim1,node_index2,spatial_dim2)
00436 * wJ;
00437 }
00438 }
00439 }
00440 }
00441
00442 rAElemPrecond.clear();
00443 if (assembleJacobian)
00444 {
00445 rAElemPrecond = rAElem;
00446 }
00447
00448 if(this->mSetComputeAverageStressPerElement)
00449 {
00450 for(unsigned i=0; i<DIM*(DIM+1)/2; i++)
00451 {
00452 this->mAverageStressesPerElement[rElement.GetIndex()](i) /= this->mpQuadratureRule->GetNumQuadPoints();
00453 }
00454 }
00455
00456 }
00457
00458
00459 template<size_t DIM>
00460 CompressibleNonlinearElasticitySolver<DIM>::CompressibleNonlinearElasticitySolver(AbstractTetrahedralMesh<DIM,DIM>& rQuadMesh,
00461 SolidMechanicsProblemDefinition<DIM>& rProblemDefinition,
00462 std::string outputDirectory)
00463 : AbstractNonlinearElasticitySolver<DIM>(rQuadMesh,
00464 rProblemDefinition,
00465 outputDirectory,
00466 COMPRESSIBLE)
00467 {
00468 if(rProblemDefinition.GetCompressibilityType() != COMPRESSIBLE)
00469 {
00470 EXCEPTION("SolidMechanicsProblemDefinition object contains incompressible material laws");
00471 }
00472 }
00473
00474
00475 template<size_t DIM>
00476 CompressibleNonlinearElasticitySolver<DIM>::~CompressibleNonlinearElasticitySolver()
00477 {
00478 }
00479
00481
00483
00484 template class CompressibleNonlinearElasticitySolver<2>;
00485 template class CompressibleNonlinearElasticitySolver<3>;