Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, University of Oxford. 00004 All rights reserved. 00005 00006 University of Oxford means the Chancellor, Masters and Scholars of the 00007 University of Oxford, having an administrative office at Wellington 00008 Square, Oxford OX1 2JD, UK. 00009 00010 This file is part of Chaste. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 * Redistributions of source code must retain the above copyright notice, 00015 this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright notice, 00017 this list of conditions and the following disclaimer in the documentation 00018 and/or other materials provided with the distribution. 00019 * Neither the name of the University of Oxford nor the names of its 00020 contributors may be used to endorse or promote products derived from this 00021 software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 */ 00035 00036 #include "UblasCustomFunctions.hpp" 00037 #include "AbstractTetrahedralElement.hpp" 00038 #include "Exception.hpp" 00039 00040 #include <cassert> 00041 00043 // Implementation 00045 00046 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00047 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::RefreshJacobian(c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian) 00048 { 00049 if (this->mIsDeleted) 00050 { 00051 EXCEPTION("Attempting to Refresh a deleted element"); 00052 } 00053 for (unsigned i=0; i<SPACE_DIM; i++) 00054 { 00055 for (unsigned j=0; j!=ELEMENT_DIM; j++) // Does a j<ELEMENT_DIM without ever having to test j<0U (#186: pointless comparison of unsigned integer with zero) 00056 { 00057 rJacobian(i,j) = this->GetNodeLocation(j+1,i) - this->GetNodeLocation(0,i); 00058 } 00059 } 00060 } 00061 00062 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00063 AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::AbstractTetrahedralElement(unsigned index, const std::vector<Node<SPACE_DIM>*>& rNodes) 00064 : AbstractElement<ELEMENT_DIM, SPACE_DIM>(index, rNodes) 00065 { 00066 // Sanity checking 00067 unsigned num_vectices = ELEMENT_DIM+1; 00068 00069 double det; 00070 00071 if (SPACE_DIM == ELEMENT_DIM) 00072 { 00073 // This is so we know it's the first time of asking 00074 // Create Jacobian 00075 c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian; 00076 try 00077 { 00078 CalculateJacobian(jacobian, det); 00079 } 00080 catch (Exception) 00081 { 00082 // if the Jacobian is negative the orientation of the element is probably 00083 // wrong, so swap the last two nodes around. 00084 00085 this->mNodes[num_vectices-1] = rNodes[num_vectices-2]; 00086 this->mNodes[num_vectices-2] = rNodes[num_vectices-1]; 00087 00088 CalculateJacobian(jacobian, det); 00089 // If determinant < 0 then element nodes are listed clockwise. 00090 // We want them anticlockwise. 00091 assert(det > 0.0); 00092 } 00093 } 00094 else 00095 { 00096 //This is not a full-dimensional element 00097 c_vector<double, SPACE_DIM> weighted_direction; 00098 double det; 00099 CalculateWeightedDirection(weighted_direction, det); 00100 } 00101 00102 } 00103 00104 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00105 AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::AbstractTetrahedralElement(unsigned index) 00106 : AbstractElement<ELEMENT_DIM,SPACE_DIM>(index) 00107 {} 00108 00109 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00110 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateJacobian(c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian, double& rJacobianDeterminant) 00111 { 00112 00113 assert(ELEMENT_DIM <= SPACE_DIM); 00114 RefreshJacobian(rJacobian); 00115 00116 { 00117 rJacobianDeterminant = Determinant(rJacobian); 00118 if (rJacobianDeterminant <= DBL_EPSILON) 00119 { 00120 EXCEPTION("Jacobian determinant is non-positive: " 00121 << "determinant = " << rJacobianDeterminant 00122 << " for element " << this->mIndex); 00123 } 00124 } 00125 } 00126 00127 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00128 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateWeightedDirection(c_vector<double, SPACE_DIM>& rWeightedDirection, double& rJacobianDeterminant) 00129 { 00130 00131 if (ELEMENT_DIM >= SPACE_DIM) 00132 { 00133 assert(ELEMENT_DIM == SPACE_DIM); 00134 EXCEPTION("WeightedDirection undefined for fully dimensional element"); 00135 } 00136 00137 c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian; 00138 RefreshJacobian(jacobian); 00139 00140 /* 00141 * At this point we're only dealing with subspace (ELEMENT_DIM < SPACE_DIM) elem. 00142 * We assume that the rWeightedDirection vector and rJacobianDeterminant (length 00143 * of vector) are the values from a previous call. 00144 */ 00145 00146 // This code is only used when ELEMENT_DIM<SPACE_DIM 00147 switch (ELEMENT_DIM) 00148 { 00149 case 0: 00150 // See specialised template for ELEMENT_DIM==0 00151 NEVER_REACHED; 00152 break; 00153 case 1: 00154 // Linear edge in a 2D plane or in 3D 00155 rWeightedDirection=matrix_column<c_matrix<double,SPACE_DIM,ELEMENT_DIM> >(jacobian, 0); 00156 break; 00157 case 2: 00158 // Surface triangle in a 3d mesh 00159 assert(SPACE_DIM == 3); 00160 rWeightedDirection(0) = -SubDeterminant(jacobian, 0, 2); 00161 rWeightedDirection(1) = SubDeterminant(jacobian, 1, 2); 00162 rWeightedDirection(2) = -SubDeterminant(jacobian, 2, 2); 00163 break; 00164 default: 00165 ; // Not going to happen 00166 } 00167 rJacobianDeterminant = norm_2(rWeightedDirection); 00168 00169 if (rJacobianDeterminant < DBL_EPSILON) 00170 { 00171 EXCEPTION("Jacobian determinant is zero"); 00172 } 00173 } 00174 00175 00176 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00177 c_vector<double, SPACE_DIM> AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateNormal() 00178 { 00179 if (ELEMENT_DIM == 1 && SPACE_DIM == 3) 00180 { 00181 EXCEPTION("Don't have enough information to calculate a normal vector"); 00182 } 00183 c_vector<double, SPACE_DIM> normal; 00184 double determinant; 00185 CalculateWeightedDirection(normal, determinant); 00186 normal /= determinant; 00187 if (ELEMENT_DIM == 1) 00188 { 00189 // Need to rotate so tangent becomes normal 00190 double x = normal[0]; 00191 normal[0] = normal[1]; 00192 normal[1] = -x; 00193 } 00194 return normal; 00195 } 00196 00197 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00198 c_vector<double, SPACE_DIM> AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateCentroid() const 00199 { 00200 c_vector<double, SPACE_DIM> centroid = zero_vector<double>(SPACE_DIM); 00201 for (unsigned i=0; i<=ELEMENT_DIM; i++) 00202 { 00203 centroid += this->mNodes[i]->rGetLocation(); 00204 } 00205 return centroid/((double)(ELEMENT_DIM + 1)); 00206 } 00207 00208 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00209 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateInverseJacobian(c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian, double& rJacobianDeterminant, c_matrix<double, ELEMENT_DIM, SPACE_DIM>& rInverseJacobian) 00210 { 00211 assert(ELEMENT_DIM <= SPACE_DIM); 00212 CalculateJacobian(rJacobian, rJacobianDeterminant); 00213 00214 // CalculateJacobian should make sure that the determinant is not close to zero (or, in fact, negative) 00215 assert(rJacobianDeterminant > 0.0); 00216 rInverseJacobian = Inverse(rJacobian); 00217 } 00218 00219 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00220 double AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::GetVolume(double determinant) const 00221 { 00222 assert(SPACE_DIM == ELEMENT_DIM); 00223 00224 if (this->mIsDeleted) 00225 { 00226 return 0.0; 00227 } 00228 00229 double scale_factor = 1.0; 00230 00231 if (ELEMENT_DIM == 2) 00232 { 00233 scale_factor = 2.0; // both the volume of the canonical triangle is 1/2 00234 } 00235 else if (ELEMENT_DIM == 3) 00236 { 00237 scale_factor = 6.0; // both the volume of the canonical triangle is 1/6 00238 } 00239 return determinant/scale_factor; 00240 } 00241 00242 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00243 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::GetStiffnessMatrixGlobalIndices(unsigned problemDim, unsigned* pIndices) const 00244 { 00245 for (unsigned local_index=0; local_index<ELEMENT_DIM+1; local_index++) 00246 { 00247 unsigned node = this->GetNodeGlobalIndex(local_index); 00248 00249 for (unsigned problem_index=0; problem_index<problemDim; problem_index++) 00250 { 00251 //std::cout << local_index*problemDim + problem_index << std::endl; 00252 pIndices[local_index*problemDim + problem_index] = node*problemDim + problem_index; 00253 } 00254 } 00255 } 00256 00257 00259 // Specialization for 0d elements // 00261 00266 template<unsigned SPACE_DIM> 00267 AbstractTetrahedralElement<0, SPACE_DIM>::AbstractTetrahedralElement(unsigned index, const std::vector<Node<SPACE_DIM>*>& rNodes) 00268 : AbstractElement<0, SPACE_DIM>(index, rNodes) 00269 { 00270 // Sanity checking 00271 //unsigned total_nodes = 1; 00272 assert(this->mNodes.size() == 1); 00273 assert(SPACE_DIM > 0); 00274 00275 // This is so we know it's the first time of asking 00276 // Create Jacobian 00277 c_vector<double, SPACE_DIM> weighted_direction; 00278 double det; 00279 00280 CalculateWeightedDirection(weighted_direction, det); 00281 00282 // If determinant < 0 then element nodes are listed clockwise. 00283 // We want them anticlockwise. 00284 assert(det > 0.0); 00285 } 00286 00287 template<unsigned SPACE_DIM> 00288 AbstractTetrahedralElement<0, SPACE_DIM>::AbstractTetrahedralElement(unsigned index) 00289 : AbstractElement<0, SPACE_DIM>(index) 00290 { 00291 } 00292 00293 template<unsigned SPACE_DIM> 00294 void AbstractTetrahedralElement<0, SPACE_DIM>::CalculateWeightedDirection( 00295 c_vector<double, SPACE_DIM>& rWeightedDirection, 00296 double& rJacobianDeterminant) 00297 { 00298 assert(SPACE_DIM > 0); 00299 00300 // End point of a line 00301 rWeightedDirection = zero_vector<double>(SPACE_DIM); 00302 rWeightedDirection(0) = 1.0; 00303 00304 rJacobianDeterminant = 1.0; 00305 } 00306 00307 template<unsigned SPACE_DIM> 00308 c_vector<double, SPACE_DIM> AbstractTetrahedralElement<0, SPACE_DIM>::CalculateNormal() 00309 { 00310 assert(SPACE_DIM > 0); 00311 00312 // End point of a line 00313 c_vector<double, SPACE_DIM> normal = zero_vector<double>(SPACE_DIM); 00315 return normal; 00316 } 00317 00318 template<unsigned SPACE_DIM> 00319 c_vector<double, SPACE_DIM> AbstractTetrahedralElement<0, SPACE_DIM>::CalculateCentroid() const 00320 { 00321 c_vector<double, SPACE_DIM> centroid = this->mNodes[0]->rGetLocation(); 00322 return centroid; 00323 } 00324 00325 template<unsigned SPACE_DIM> 00326 void AbstractTetrahedralElement<0, SPACE_DIM>::GetStiffnessMatrixGlobalIndices(unsigned problemDim, unsigned* pIndices) const 00327 { 00328 for (unsigned local_index=0; local_index<1; local_index++) 00329 { 00330 unsigned node = this->GetNodeGlobalIndex(local_index); 00331 00332 for (unsigned problem_index=0; problem_index<problemDim; problem_index++) 00333 { 00334 //std::cout << local_index*problemDim + problem_index << std::endl; 00335 pIndices[local_index*problemDim + problem_index] = node*problemDim + problem_index; 00336 } 00337 } 00338 } 00339 00341 // Explicit instantiation 00343 00344 template class AbstractTetrahedralElement<0,1>; 00345 template class AbstractTetrahedralElement<1,1>; 00346 template class AbstractTetrahedralElement<0,2>; 00347 template class AbstractTetrahedralElement<1,2>; 00348 template class AbstractTetrahedralElement<2,2>; 00349 template class AbstractTetrahedralElement<0,3>; 00350 template class AbstractTetrahedralElement<1,3>; 00351 template class AbstractTetrahedralElement<2,3>; 00352 template class AbstractTetrahedralElement<3,3>;