AbstractMesh.cpp

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

Generated by  doxygen 1.6.2