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 #include "CompressibleNonlinearElasticitySolver.hpp"
00044 #include "LinearBasisFunction.hpp"
00045 #include "QuadraticBasisFunction.hpp"
00046 #include <algorithm>
00047
00048 template<size_t DIM>
00049 void CompressibleNonlinearElasticitySolver<DIM>::AssembleSystem(bool assembleResidual,
00050 bool assembleJacobian)
00051 {
00052
00053 assert(assembleResidual || assembleJacobian);
00054 assert(this->mCurrentSolution.size()==this->mNumDofs);
00055
00056
00057 if (assembleResidual)
00058 {
00059 PetscVecTools::Zero(this->mResidualVector);
00060 }
00061 if (assembleJacobian)
00062 {
00063 PetscMatTools::Zero(this->mJacobianMatrix);
00064 PetscMatTools::Zero(this->mPreconditionMatrix);
00065 }
00066
00067 c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem;
00068
00069
00070 c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem_precond;
00071 c_vector<double, STENCIL_SIZE> b_elem;
00072
00074
00076 for (typename AbstractTetrahedralMesh<DIM, DIM>::ElementIterator iter = this->mpQuadMesh->GetElementIteratorBegin();
00077 iter != this->mpQuadMesh->GetElementIteratorEnd();
00078 ++iter)
00079 {
00080 #ifdef MECH_VERY_VERBOSE
00081 if (assembleJacobian)
00082 {
00083 std::cout << "\r[" << PetscTools::GetMyRank() << "]: Element " << (*iter).GetIndex() << " of " << this->mpQuadMesh->GetNumElements() << std::flush;
00084 }
00085 #endif
00086
00087 Element<DIM, DIM>& element = *iter;
00088
00089 if (element.GetOwnership() == true)
00090 {
00091 AssembleOnElement(element, a_elem, a_elem_precond, b_elem, assembleResidual, assembleJacobian);
00092
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 unsigned p_indices[STENCIL_SIZE];
00106 for (unsigned i=0; i<NUM_NODES_PER_ELEMENT; i++)
00107 {
00108 for (unsigned j=0; j<DIM; j++)
00109 {
00110 p_indices[DIM*i+j] = DIM*element.GetNodeGlobalIndex(i) + j;
00111 }
00112 }
00113
00114 if (assembleJacobian)
00115 {
00116 PetscMatTools::AddMultipleValues<STENCIL_SIZE>(this->mJacobianMatrix, p_indices, a_elem);
00117 PetscMatTools::AddMultipleValues<STENCIL_SIZE>(this->mPreconditionMatrix, p_indices, a_elem_precond);
00118 }
00119
00120 if (assembleResidual)
00121 {
00122 PetscVecTools::AddMultipleValues<STENCIL_SIZE>(this->mResidualVector, p_indices, b_elem);
00123 }
00124 }
00125 }
00126
00128
00129
00131 c_vector<double, BOUNDARY_STENCIL_SIZE> b_boundary_elem;
00132 c_matrix<double, BOUNDARY_STENCIL_SIZE, BOUNDARY_STENCIL_SIZE> a_boundary_elem;
00133 if (this->mBoundaryElements.size()>0)
00134 {
00135 for (unsigned i=0; i<this->mBoundaryElements.size(); i++)
00136 {
00137 BoundaryElement<DIM-1,DIM>& r_boundary_element = *(this->mBoundaryElements[i]);
00138 AssembleOnBoundaryElement(r_boundary_element, a_boundary_elem, b_boundary_elem, this->mSurfaceTractions[i], assembleResidual, assembleJacobian);
00139
00140 unsigned p_indices[BOUNDARY_STENCIL_SIZE];
00141 for (unsigned i=0; i<NUM_NODES_PER_BOUNDARY_ELEMENT; i++)
00142 {
00143 for (unsigned j=0; j<DIM; j++)
00144 {
00145 p_indices[DIM*i+j] = DIM*r_boundary_element.GetNodeGlobalIndex(i) + j;
00146 }
00147 }
00148
00149 if (assembleJacobian)
00150 {
00151 PetscMatTools::AddMultipleValues<BOUNDARY_STENCIL_SIZE>(this->mJacobianMatrix, p_indices, a_boundary_elem);
00152 PetscMatTools::AddMultipleValues<BOUNDARY_STENCIL_SIZE>(this->mPreconditionMatrix, p_indices, a_boundary_elem);
00153 }
00154
00155 if (assembleResidual)
00156 {
00157 PetscVecTools::AddMultipleValues<BOUNDARY_STENCIL_SIZE>(this->mResidualVector, p_indices, b_boundary_elem);
00158 }
00159 }
00160 }
00161
00162 this->FinishAssembleSystem(assembleResidual, assembleJacobian);
00163 }
00164
00165 template<size_t DIM>
00166 void CompressibleNonlinearElasticitySolver<DIM>::AssembleOnElement(
00167 Element<DIM, DIM>& rElement,
00168 c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElem,
00169 c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElemPrecond,
00170 c_vector<double, STENCIL_SIZE>& rBElem,
00171 bool assembleResidual,
00172 bool assembleJacobian)
00173 {
00174 static c_matrix<double,DIM,DIM> jacobian;
00175 static c_matrix<double,DIM,DIM> inverse_jacobian;
00176 double jacobian_determinant;
00177
00178 this->mpQuadMesh->GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
00179
00180 if (assembleJacobian)
00181 {
00182 rAElem.clear();
00183 rAElemPrecond.clear();
00184 }
00185
00186 if (assembleResidual)
00187 {
00188 rBElem.clear();
00189 }
00190
00192
00194 static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
00195 for (unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
00196 {
00197 for (unsigned JJ=0; JJ<DIM; JJ++)
00198 {
00199 element_current_displacements(JJ,II) = this->mCurrentSolution[DIM*rElement.GetNodeGlobalIndex(II) + JJ];
00200 }
00201 }
00202
00203
00204 static c_vector<double, NUM_VERTICES_PER_ELEMENT> linear_phi;
00205 static c_vector<double, NUM_NODES_PER_ELEMENT> quad_phi;
00206 static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi;
00207 static c_matrix<double, NUM_NODES_PER_ELEMENT, DIM> trans_grad_quad_phi;
00208
00209
00210
00211 AbstractCompressibleMaterialLaw<DIM>* p_material_law;
00212 if (this->mMaterialLaws.size()==1)
00213 {
00214
00215 p_material_law = this->mMaterialLaws[0];
00216 }
00217 else
00218 {
00219
00220 #define COVERAGE_IGNORE // not going to have tests in cts for everything
00221 p_material_law = this->mMaterialLaws[rElement.GetIndex()];
00222 #undef COVERAGE_IGNORE
00223 }
00224
00225
00226 static c_matrix<double,DIM,DIM> grad_u;
00227
00228 static c_matrix<double,DIM,DIM> F;
00229 static c_matrix<double,DIM,DIM> C;
00230 static c_matrix<double,DIM,DIM> inv_C;
00231 static c_matrix<double,DIM,DIM> inv_F;
00232 static c_matrix<double,DIM,DIM> T;
00233
00234 static c_matrix<double,DIM,DIM> F_T;
00235 static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> F_T_grad_quad_phi;
00236
00237 c_vector<double,DIM> body_force;
00238
00239 static FourthOrderTensor<DIM,DIM,DIM,DIM> dTdE;
00240 static FourthOrderTensor<DIM,DIM,DIM,DIM> dSdF;
00241
00242 static FourthOrderTensor<NUM_NODES_PER_ELEMENT,DIM,DIM,DIM> temp_tensor;
00243 static FourthOrderTensor<NUM_NODES_PER_ELEMENT,DIM,NUM_NODES_PER_ELEMENT,DIM> dSdF_quad_quad;
00244
00245 static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> temp_matrix;
00246 static c_matrix<double,NUM_NODES_PER_ELEMENT,DIM> grad_quad_phi_times_invF;
00247
00248
00249
00255 for (unsigned quadrature_index=0; quadrature_index < this->mpQuadratureRule->GetNumQuadPoints(); quadrature_index++)
00256 {
00257
00258 unsigned current_quad_point_global_index = rElement.GetIndex()*this->mpQuadratureRule->GetNumQuadPoints()
00259 + quadrature_index;
00260
00261 double wJ = jacobian_determinant * this->mpQuadratureRule->GetWeight(quadrature_index);
00262
00263 const ChastePoint<DIM>& quadrature_point = this->mpQuadratureRule->rGetQuadPoint(quadrature_index);
00264
00266
00268 LinearBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, linear_phi);
00269 QuadraticBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, quad_phi);
00270 QuadraticBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_quad_phi);
00271 trans_grad_quad_phi = trans(grad_quad_phi);
00272
00273
00275
00277
00278 if(assembleResidual)
00279 {
00280 if (this->mUsingBodyForceFunction)
00281 {
00282 c_vector<double,DIM> X = zero_vector<double>(DIM);
00283
00284 for (unsigned node_index=0; node_index<NUM_VERTICES_PER_ELEMENT; node_index++)
00285 {
00286 X += linear_phi(node_index)*this->mpQuadMesh->GetNode( rElement.GetNodeGlobalIndex(node_index) )->rGetLocation();
00287 }
00288 body_force = (*(this->mpBodyForceFunction))(X, this->mCurrentTime);
00289 }
00290 else
00291 {
00292 body_force = this->mBodyForce;
00293 }
00294 }
00295
00297
00299 grad_u = zero_matrix<double>(DIM,DIM);
00300
00301 for (unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++)
00302 {
00303 for (unsigned i=0; i<DIM; i++)
00304 {
00305 for (unsigned M=0; M<DIM; M++)
00306 {
00307 grad_u(i,M) += grad_quad_phi(M,node_index)*element_current_displacements(i,node_index);
00308 }
00309 }
00310 }
00311
00312
00314
00316 for (unsigned i=0; i<DIM; i++)
00317 {
00318 for (unsigned M=0; M<DIM; M++)
00319 {
00320 F(i,M) = (i==M?1:0) + grad_u(i,M);
00321 }
00322 }
00323
00324 C = prod(trans(F),F);
00325 inv_C = Inverse(C);
00326 inv_F = Inverse(F);
00327
00328 this->ComputeStressAndStressDerivative(p_material_law, C, inv_C, 0.0, rElement.GetIndex(), current_quad_point_global_index,
00329 T, dTdE, assembleJacobian);
00330
00331
00333
00335 if (assembleResidual)
00336 {
00337 F_T = prod(F,T);
00338 F_T_grad_quad_phi = prod(F_T, grad_quad_phi);
00339
00340 for (unsigned index=0; index<NUM_NODES_PER_ELEMENT*DIM; index++)
00341 {
00342 unsigned spatial_dim = index%DIM;
00343 unsigned node_index = (index-spatial_dim)/DIM;
00344
00345 rBElem(index) += - this->mDensity
00346 * body_force(spatial_dim)
00347 * quad_phi(node_index)
00348 * wJ;
00349
00350
00351 rBElem(index) += F_T_grad_quad_phi(spatial_dim,node_index)
00352 * wJ;
00353 }
00354 }
00355
00356
00358
00360 if (assembleJacobian)
00361 {
00362
00363 grad_quad_phi_times_invF = prod(trans_grad_quad_phi, inv_F);
00364
00366
00367
00368
00369
00370
00371
00372
00373
00374
00376
00377
00378 for (unsigned M=0; M<DIM; M++)
00379 {
00380 for (unsigned N=0; N<DIM; N++)
00381 {
00382 for (unsigned P=0; P<DIM; P++)
00383 {
00384 for (unsigned Q=0; Q<DIM; Q++)
00385 {
00386
00387 dSdF(M,N,P,Q) = 0.5*(dTdE(M,N,P,Q) + dTdE(M,N,Q,P));
00388 }
00389 }
00390 }
00391 }
00392
00393 dTdE.template SetAsContractionOnSecondDimension<DIM>(F, dSdF);
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
00409
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00422 temp_tensor.template SetAsContractionOnFirstDimension<DIM>( trans_grad_quad_phi, dSdF );
00423 dSdF_quad_quad.template SetAsContractionOnThirdDimension<DIM>( trans_grad_quad_phi, temp_tensor );
00424
00425
00426
00427
00428 for (unsigned index1=0; index1<NUM_NODES_PER_ELEMENT*DIM; index1++)
00429 {
00430 unsigned spatial_dim1 = index1%DIM;
00431 unsigned node_index1 = (index1-spatial_dim1)/DIM;
00432
00433
00434 for (unsigned index2=0; index2<NUM_NODES_PER_ELEMENT*DIM; index2++)
00435 {
00436 unsigned spatial_dim2 = index2%DIM;
00437 unsigned node_index2 = (index2-spatial_dim2)/DIM;
00438
00439
00440 rAElem(index1,index2) += dSdF_quad_quad(node_index1,spatial_dim1,node_index2,spatial_dim2)
00441 * wJ;
00442 }
00443 }
00444 }
00445 }
00446
00447 rAElemPrecond.clear();
00448 if (assembleJacobian)
00449 {
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461 rAElemPrecond = rAElem;
00462 }
00463 }
00464
00465
00466
00467 template<size_t DIM>
00468 void CompressibleNonlinearElasticitySolver<DIM>::AssembleOnBoundaryElement(
00469 BoundaryElement<DIM-1,DIM>& rBoundaryElement,
00470 c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
00471 c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
00472 c_vector<double,DIM>& rTraction,
00473 bool assembleResidual,
00474 bool assembleJacobian)
00475 {
00476 rAelem.clear();
00477 rBelem.clear();
00478
00479 if (assembleJacobian && !assembleResidual)
00480 {
00481
00482 return;
00483 }
00484
00485 c_vector<double, DIM> weighted_direction;
00486 double jacobian_determinant;
00487 this->mpQuadMesh->GetWeightedDirectionForBoundaryElement(rBoundaryElement.GetIndex(), weighted_direction, jacobian_determinant);
00488
00489 c_vector<double,NUM_NODES_PER_BOUNDARY_ELEMENT> phi;
00490
00491 for (unsigned quad_index=0; quad_index<this->mpBoundaryQuadratureRule->GetNumQuadPoints(); quad_index++)
00492 {
00493 double wJ = jacobian_determinant * this->mpBoundaryQuadratureRule->GetWeight(quad_index);
00494
00495 const ChastePoint<DIM-1>& quad_point = this->mpBoundaryQuadratureRule->rGetQuadPoint(quad_index);
00496
00497 QuadraticBasisFunction<DIM-1>::ComputeBasisFunctions(quad_point, phi);
00498
00499
00500
00501 c_vector<double,DIM> traction = zero_vector<double>(DIM);
00502 if (this->mUsingTractionBoundaryConditionFunction)
00503 {
00504 c_vector<double,DIM> X = zero_vector<double>(DIM);
00505 for (unsigned node_index=0; node_index<NUM_NODES_PER_BOUNDARY_ELEMENT; node_index++)
00506 {
00507 X += phi(node_index)*this->mpQuadMesh->GetNode( rBoundaryElement.GetNodeGlobalIndex(node_index) )->rGetLocation();
00508 }
00509 traction = (*(this->mpTractionBoundaryConditionFunction))(X, this->mCurrentTime);
00510 }
00511 else
00512 {
00513 traction = rTraction;
00514 }
00515
00516
00517 for (unsigned index=0; index<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index++)
00518 {
00519 unsigned spatial_dim = index%DIM;
00520 unsigned node_index = (index-spatial_dim)/DIM;
00521
00522 assert(node_index < NUM_NODES_PER_BOUNDARY_ELEMENT);
00523
00524 rBelem(index) -= traction(spatial_dim)
00525 * phi(node_index)
00526 * wJ;
00527 }
00528 }
00529 }
00530
00531
00532
00533 template<size_t DIM>
00534 CompressibleNonlinearElasticitySolver<DIM>::CompressibleNonlinearElasticitySolver(
00535 QuadraticMesh<DIM>* pQuadMesh,
00536 AbstractMaterialLaw<DIM>* pMaterialLaw,
00537 c_vector<double,DIM> bodyForce,
00538 double density,
00539 std::string outputDirectory,
00540 std::vector<unsigned>& fixedNodes,
00541 std::vector<c_vector<double,DIM> >* pFixedNodeLocations)
00542 : AbstractNonlinearElasticitySolver<DIM>(pQuadMesh,
00543 bodyForce, density,
00544 outputDirectory, fixedNodes,
00545 COMPRESSIBLE)
00546 {
00547 assert(pMaterialLaw != NULL);
00548
00549 AbstractCompressibleMaterialLaw<DIM>* p_law = dynamic_cast<AbstractCompressibleMaterialLaw<DIM>*>(pMaterialLaw);
00550 if(!p_law)
00551 {
00552 EXCEPTION("CompressibleNonlinearElasticitySolver must take in a compressible material law (ie of type AbstractCompressibleMaterialLaw)");
00553 }
00554 mMaterialLaws.push_back(p_law);
00555
00556 Initialise(pFixedNodeLocations);
00557 }
00558
00559
00560 template<size_t DIM>
00561 CompressibleNonlinearElasticitySolver<DIM>::CompressibleNonlinearElasticitySolver(
00562 QuadraticMesh<DIM>* pQuadMesh,
00563 std::vector<AbstractMaterialLaw<DIM>*>& rMaterialLaws,
00564 c_vector<double,DIM> bodyForce,
00565 double density,
00566 std::string outputDirectory,
00567 std::vector<unsigned>& fixedNodes,
00568 std::vector<c_vector<double,DIM> >* pFixedNodeLocations)
00569 : AbstractNonlinearElasticitySolver<DIM>(pQuadMesh,
00570 bodyForce, density,
00571 outputDirectory, fixedNodes,
00572 COMPRESSIBLE)
00573 {
00574 mMaterialLaws.resize(rMaterialLaws.size(), NULL);
00575 for (unsigned i=0; i<mMaterialLaws.size(); i++)
00576 {
00577 AbstractCompressibleMaterialLaw<DIM>* p_law = dynamic_cast<AbstractCompressibleMaterialLaw<DIM>*>(rMaterialLaws[i]);
00578 if(!p_law)
00579 {
00580 EXCEPTION("CompressibleNonlinearElasticitySolver must take in a compressible material law (ie of type AbstractCompressibleMaterialLaw)");
00581 }
00582 assert(rMaterialLaws[i] != NULL);
00583 mMaterialLaws[i] = p_law;
00584 }
00585
00586 assert(rMaterialLaws.size()==pQuadMesh->GetNumElements());
00587 Initialise(pFixedNodeLocations);
00588 }
00589
00590
00591 template<size_t DIM>
00592 CompressibleNonlinearElasticitySolver<DIM>::~CompressibleNonlinearElasticitySolver()
00593 {
00594 }
00596
00598
00599
00600 template class CompressibleNonlinearElasticitySolver<2>;
00601 template class CompressibleNonlinearElasticitySolver<3>;