Chaste Release::3.1
AbstractMesh.cpp
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>;