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 "AbstractMesh.hpp" 00037 #include "Exception.hpp" 00038 00040 // Implementation 00042 00043 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00044 AbstractMesh<ELEMENT_DIM, SPACE_DIM>::AbstractMesh() 00045 : mpDistributedVectorFactory(NULL), 00046 mMeshFileBaseName(""), 00047 mMeshChangesDuringSimulation(false) 00048 { 00049 } 00050 00051 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00052 AbstractMesh<ELEMENT_DIM, SPACE_DIM>::~AbstractMesh() 00053 { 00054 // Iterate over nodes and free the memory 00055 for (unsigned i=0; i<mNodes.size(); i++) 00056 { 00057 delete mNodes[i]; 00058 } 00059 if (mpDistributedVectorFactory) 00060 { 00061 delete mpDistributedVectorFactory; 00062 } 00063 } 00064 00065 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00066 unsigned AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetNumNodes() const 00067 { 00068 return mNodes.size(); 00069 } 00070 00071 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00072 unsigned AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetNumBoundaryNodes() const 00073 { 00074 return mBoundaryNodes.size(); 00075 } 00076 00077 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00078 unsigned AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetNumAllNodes() const 00079 { 00080 return mNodes.size(); 00081 } 00082 00083 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00084 Node<SPACE_DIM>* AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetNode(unsigned index) const 00085 { 00086 unsigned local_index = SolveNodeMapping(index); 00087 return mNodes[local_index]; 00088 } 00089 00090 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00091 Node<SPACE_DIM>* AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetNodeOrHaloNode(unsigned index) const 00092 { 00093 return GetNode(index); 00094 } 00095 00096 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00097 Node<SPACE_DIM>* AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetNodeFromPrePermutationIndex(unsigned index) const 00098 { 00099 if (mNodesPermutation.empty()) 00100 { 00101 return GetNode(index); 00102 } 00103 else 00104 { 00105 return GetNode(mNodesPermutation[index]); 00106 } 00107 } 00108 00109 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00110 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::ReadNodesPerProcessorFile(const std::string& rNodesPerProcessorFile) 00111 { 00112 NEVER_REACHED; 00113 } 00114 00115 00116 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00117 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::SetElementOwnerships() 00118 { 00119 //Does nothing, since an AbstractMesh has no elements 00120 } 00121 00122 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00123 DistributedVectorFactory* AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetDistributedVectorFactory() 00124 { 00125 if (mpDistributedVectorFactory == NULL) 00126 { 00127 mpDistributedVectorFactory = new DistributedVectorFactory(GetNumNodes()); 00128 if (PetscTools::IsParallel()) 00129 { 00130 SetElementOwnerships(); // So any parallel implementation with shared mesh has owners set 00131 } 00132 } 00133 return mpDistributedVectorFactory; 00134 } 00135 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00136 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::SetDistributedVectorFactory(DistributedVectorFactory *pFactory) 00137 { 00138 if (mpDistributedVectorFactory) 00139 { 00140 EXCEPTION("Cannot change the mesh's distributed vector factory once it has been set."); 00141 } 00142 if (pFactory->GetNumProcs() != PetscTools::GetNumProcs()) 00143 { 00144 EXCEPTION("The distributed vector factory provided to the mesh is for the wrong number of processes."); 00145 } 00146 mpDistributedVectorFactory = pFactory; 00147 } 00148 00149 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00150 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::PermuteNodes() 00151 { 00152 NEVER_REACHED; 00153 } 00154 00155 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00156 typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryNodeIterator AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetBoundaryNodeIteratorBegin() const 00157 { 00158 return mBoundaryNodes.begin(); 00159 } 00160 00161 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00162 typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryNodeIterator AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetBoundaryNodeIteratorEnd() const 00163 { 00164 return mBoundaryNodes.end(); 00165 } 00166 00167 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00168 std::string AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetMeshFileBaseName() const 00169 { 00170 if (!IsMeshOnDisk()) 00171 { 00172 EXCEPTION("This mesh was not constructed from a file."); 00173 } 00174 00175 return mMeshFileBaseName; 00176 } 00177 00178 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00179 bool AbstractMesh<ELEMENT_DIM, SPACE_DIM>::IsMeshOnDisk() const 00180 { 00181 return (mMeshFileBaseName != ""); 00182 } 00183 00184 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00185 const std::vector<unsigned>& AbstractMesh<ELEMENT_DIM, SPACE_DIM>::rGetNodePermutation() const 00186 { 00187 return mNodesPermutation; 00188 } 00189 00190 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00191 c_vector<double, SPACE_DIM> AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetVectorFromAtoB( 00192 const c_vector<double, SPACE_DIM>& rLocationA, const c_vector<double, SPACE_DIM>& rLocationB) 00193 { 00194 c_vector<double, SPACE_DIM> vector = rLocationB - rLocationA; 00195 return vector; 00196 } 00197 00198 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00199 double AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetDistanceBetweenNodes(unsigned indexA, unsigned indexB) 00200 { 00201 c_vector<double, SPACE_DIM> vector = GetVectorFromAtoB(mNodes[indexA]->rGetLocation(), 00202 mNodes[indexB]->rGetLocation()); 00203 return norm_2(vector); 00204 } 00205 00206 00207 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00208 double AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetWidth(const unsigned& rDimension) const 00209 { 00210 assert(rDimension < SPACE_DIM); 00211 return CalculateBoundingBox().GetWidth(rDimension); 00212 } 00213 00214 00215 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00216 ChasteCuboid<SPACE_DIM> AbstractMesh<ELEMENT_DIM, SPACE_DIM>::CalculateBoundingBox() const 00217 { 00218 // Set min to DBL_MAX etc. 00219 c_vector<double, SPACE_DIM> minimum_point = scalar_vector<double>(SPACE_DIM, DBL_MAX); 00220 00221 // Set max to -DBL_MAX etc. 00222 c_vector<double, SPACE_DIM> maximum_point=-minimum_point; 00223 00224 // Iterate through nodes 00226 for (unsigned i=0; i<mNodes.size(); i++) 00227 { 00228 if (!mNodes[i]->IsDeleted()) 00229 { 00230 c_vector<double, SPACE_DIM> position = mNodes[i]->rGetLocation(); 00231 00232 // Update max/min 00233 for (unsigned i=0; i<SPACE_DIM; i++) 00234 { 00235 if (position[i] < minimum_point[i]) 00236 { 00237 minimum_point[i] = position[i]; 00238 } 00239 if (position[i] > maximum_point[i]) 00240 { 00241 maximum_point[i] = position[i]; 00242 } 00243 } 00244 } 00245 } 00246 ChastePoint<SPACE_DIM> min(minimum_point); 00247 ChastePoint<SPACE_DIM> max(maximum_point); 00248 00249 return ChasteCuboid<SPACE_DIM>(min, max); 00250 } 00251 00252 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00253 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Scale(const double xScale, const double yScale, const double zScale) 00254 { 00255 unsigned num_nodes = mNodes.size(); 00256 00257 for (unsigned i=0; i<num_nodes; i++) 00258 { 00259 c_vector<double, SPACE_DIM>& r_location = mNodes[i]->rGetModifiableLocation(); 00260 if (SPACE_DIM>=3) 00261 { 00262 r_location[2] *= zScale; 00263 } 00264 if (SPACE_DIM>=2) 00265 { 00266 r_location[1] *= yScale; 00267 } 00268 r_location[0] *= xScale; 00269 } 00270 00271 RefreshMesh(); 00272 } 00273 00274 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00275 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Translate( 00276 const double xMovement, 00277 const double yMovement, 00278 const double zMovement) 00279 { 00280 c_vector<double, SPACE_DIM> displacement; 00281 00282 switch (SPACE_DIM) 00283 { 00284 case 3: 00285 displacement[2] = zMovement; 00286 case 2: 00287 displacement[1] = yMovement; 00288 case 1: 00289 displacement[0] = xMovement; 00290 } 00291 00292 Translate(displacement); 00293 } 00294 00295 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00296 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Translate(const c_vector<double, SPACE_DIM>& rTransVec) 00297 { 00298 unsigned num_nodes = this->GetNumAllNodes(); 00299 00300 for (unsigned i=0; i<num_nodes; i++) 00301 { 00302 c_vector<double, SPACE_DIM>& r_location = this->mNodes[i]->rGetModifiableLocation(); 00303 r_location += rTransVec; 00304 } 00305 00306 RefreshMesh(); 00307 } 00308 00309 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00310 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(c_matrix<double , SPACE_DIM, SPACE_DIM> rotationMatrix) 00311 { 00312 unsigned num_nodes = this->GetNumAllNodes(); 00313 00314 for (unsigned i=0; i<num_nodes; i++) 00315 { 00316 c_vector<double, SPACE_DIM>& r_location = this->mNodes[i]->rGetModifiableLocation(); 00317 r_location = prod(rotationMatrix, r_location); 00318 } 00319 00320 RefreshMesh(); 00321 } 00322 00323 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00324 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(c_vector<double,3> axis, double angle) 00325 { 00326 assert(SPACE_DIM == 3); 00327 double norm = norm_2(axis); 00328 c_vector<double,3> unit_axis=axis/norm; 00329 00330 c_matrix<double, SPACE_DIM,SPACE_DIM> rotation_matrix; 00331 00332 double c = cos(angle); 00333 double s = sin(angle); 00334 00335 rotation_matrix(0,0) = unit_axis(0)*unit_axis(0)+c*(1-unit_axis(0)*unit_axis(0)); 00336 rotation_matrix(0,1) = unit_axis(0)*unit_axis(1)*(1-c) - unit_axis(2)*s; 00337 rotation_matrix(1,0) = unit_axis(0)*unit_axis(1)*(1-c) + unit_axis(2)*s; 00338 rotation_matrix(1,1) = unit_axis(1)*unit_axis(1)+c*(1-unit_axis(1)*unit_axis(1)); 00339 rotation_matrix(0,2) = unit_axis(0)*unit_axis(2)*(1-c)+unit_axis(1)*s; 00340 rotation_matrix(1,2) = unit_axis(1)*unit_axis(2)*(1-c)-unit_axis(0)*s; 00341 rotation_matrix(2,0) = unit_axis(0)*unit_axis(2)*(1-c)-unit_axis(1)*s; 00342 rotation_matrix(2,1) = unit_axis(1)*unit_axis(2)*(1-c)+unit_axis(0)*s; 00343 rotation_matrix(2,2) = unit_axis(2)*unit_axis(2)+c*(1-unit_axis(2)*unit_axis(2)); 00344 00345 Rotate(rotation_matrix); 00346 } 00347 00348 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00349 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::RotateX(const double theta) 00350 { 00351 if (SPACE_DIM != 3) 00352 { 00353 EXCEPTION("This rotation is only valid in 3D"); 00354 } 00355 c_matrix<double , SPACE_DIM, SPACE_DIM> x_rotation_matrix=identity_matrix<double>(SPACE_DIM); 00356 00357 x_rotation_matrix(1,1) = cos(theta); 00358 x_rotation_matrix(1,2) = sin(theta); 00359 x_rotation_matrix(2,1) = -sin(theta); 00360 x_rotation_matrix(2,2) = cos(theta); 00361 Rotate(x_rotation_matrix); 00362 } 00363 00364 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00365 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::RotateY(const double theta) 00366 { 00367 if (SPACE_DIM != 3) 00368 { 00369 EXCEPTION("This rotation is only valid in 3D"); 00370 } 00371 c_matrix<double , SPACE_DIM, SPACE_DIM> y_rotation_matrix=identity_matrix<double>(SPACE_DIM); 00372 00373 y_rotation_matrix(0,0) = cos(theta); 00374 y_rotation_matrix(0,2) = -sin(theta); 00375 y_rotation_matrix(2,0) = sin(theta); 00376 y_rotation_matrix(2,2) = cos(theta); 00377 00378 00379 Rotate(y_rotation_matrix); 00380 } 00381 00382 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00383 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::RotateZ(const double theta) 00384 { 00385 if (SPACE_DIM < 2) 00386 { 00387 EXCEPTION("This rotation is not valid in less than 2D"); 00388 } 00389 c_matrix<double , SPACE_DIM, SPACE_DIM> z_rotation_matrix=identity_matrix<double>(SPACE_DIM); 00390 00391 00392 z_rotation_matrix(0,0) = cos(theta); 00393 z_rotation_matrix(0,1) = sin(theta); 00394 z_rotation_matrix(1,0) = -sin(theta); 00395 z_rotation_matrix(1,1) = cos(theta); 00396 00397 Rotate(z_rotation_matrix); 00398 } 00399 00400 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00401 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(double theta) 00402 { 00403 RotateZ(theta); 00404 } 00405 00406 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00407 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::RefreshMesh() 00408 { 00409 } 00410 00411 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00412 bool AbstractMesh<ELEMENT_DIM, SPACE_DIM>::IsMeshChanging() const 00413 { 00414 return mMeshChangesDuringSimulation; 00415 } 00416 00417 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00418 unsigned AbstractMesh<ELEMENT_DIM, SPACE_DIM>::CalculateMaximumContainingElementsPerProcess() const 00419 { 00420 unsigned max_num=0u; 00421 for (unsigned local_node_index=0; local_node_index<mNodes.size(); local_node_index++) 00422 { 00423 unsigned num=mNodes[local_node_index]->GetNumContainingElements(); 00424 if (num>max_num) 00425 { 00426 max_num=num; 00427 } 00428 } 00429 return max_num; 00430 } 00431 00432 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00433 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::SetMeshHasChangedSinceLoading() 00434 { 00435 // We just forget what the original file was, which has the desired effect 00436 mMeshFileBaseName = ""; 00437 } 00438 00440 // Explicit instantiation 00442 00443 template class AbstractMesh<1,1>; 00444 template class AbstractMesh<1,2>; 00445 template class AbstractMesh<1,3>; 00446 template class AbstractMesh<2,2>; 00447 template class AbstractMesh<2,3>; 00448 template class AbstractMesh<3,3>;