AbstractMesh.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 unsigned AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetNearestNodeIndex(const ChastePoint<SPACE_DIM>& rTestPoint)
00282 {
00283     if (mNodes.empty())
00284     {
00285         // This happens in parallel if a process isn't assigned any nodes.
00286         return UINT_MAX;
00287     }
00288     // Hold the best distance from node to point found so far
00289     // and the (local) node at which this was recorded
00290     unsigned best_node_index = 0u;
00291     double best_node_point_distance = DBL_MAX;
00292 
00293     c_vector<double, SPACE_DIM> test_location = rTestPoint.rGetLocation();
00294     // Now loop through the nodes, calculating the distance and updating best_node_point_distance
00295     for (unsigned node_index = 0; node_index < mNodes.size(); node_index++)
00296     {
00297         // Calculate the distance from the chosen point to the current node
00298         double node_point_distance = norm_2( GetVectorFromAtoB(mNodes[node_index]->rGetLocation(), test_location) );
00299         // Update the "best" distance and node index if necessary
00300         if (node_point_distance < best_node_point_distance)
00301         {
00302             best_node_index = node_index;
00303             best_node_point_distance = node_point_distance;
00304         }
00305     }
00306 
00307     // Return the global index of the closest node to the point
00308     // (which differs from the local index "best_node_index" in parallel)
00309     // In the distributed case, we'll have to do an AllReduce next
00310     return mNodes[best_node_index]->GetIndex();
00311 }
00312 
00313 
00314 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00315 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Scale(const double xScale, const double yScale, const double zScale)
00316 {
00317     unsigned num_nodes = mNodes.size();
00318 
00319     for (unsigned i=0; i<num_nodes; i++)
00320     {
00321         c_vector<double, SPACE_DIM>& r_location = mNodes[i]->rGetModifiableLocation();
00322         if (SPACE_DIM>=3)
00323         {
00324             r_location[2] *= zScale;
00325         }
00326         if (SPACE_DIM>=2)
00327         {
00328             r_location[1] *= yScale;
00329         }
00330         r_location[0] *= xScale;
00331     }
00332 
00333     RefreshMesh();
00334 }
00335 
00336 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00337 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Translate(
00338     const double xMovement,
00339     const double yMovement,
00340     const double zMovement)
00341 {
00342     c_vector<double, SPACE_DIM> displacement;
00343 
00344     switch (SPACE_DIM)
00345     {
00346         case 3:
00347             displacement[2] = zMovement;
00348         case 2:
00349             displacement[1] = yMovement;
00350         case 1:
00351             displacement[0] = xMovement;
00352     }
00353 
00354     Translate(displacement);
00355 }
00356 
00357 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00358 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Translate(const c_vector<double, SPACE_DIM>& rTransVec)
00359 {
00360     unsigned num_nodes = this->GetNumAllNodes();
00361 
00362     for (unsigned i=0; i<num_nodes; i++)
00363     {
00364         c_vector<double, SPACE_DIM>& r_location = this->mNodes[i]->rGetModifiableLocation();
00365         r_location += rTransVec;
00366     }
00367 
00368     RefreshMesh();
00369 }
00370 
00371 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00372 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(c_matrix<double , SPACE_DIM, SPACE_DIM> rotationMatrix)
00373 {
00374     unsigned num_nodes = this->GetNumAllNodes();
00375 
00376     for (unsigned i=0; i<num_nodes; i++)
00377     {
00378         c_vector<double, SPACE_DIM>& r_location = this->mNodes[i]->rGetModifiableLocation();
00379         r_location = prod(rotationMatrix, r_location);
00380     }
00381 
00382     RefreshMesh();
00383 }
00384 
00385 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00386 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(c_vector<double,3> axis, double angle)
00387 {
00388     assert(SPACE_DIM == 3);
00389     double norm = norm_2(axis);
00390     c_vector<double,3> unit_axis=axis/norm;
00391 
00392     c_matrix<double, SPACE_DIM,SPACE_DIM> rotation_matrix;
00393 
00394     double c = cos(angle);
00395     double s = sin(angle);
00396 
00397     rotation_matrix(0,0) = unit_axis(0)*unit_axis(0)+c*(1-unit_axis(0)*unit_axis(0));
00398     rotation_matrix(0,1) = unit_axis(0)*unit_axis(1)*(1-c) - unit_axis(2)*s;
00399     rotation_matrix(1,0) = unit_axis(0)*unit_axis(1)*(1-c) + unit_axis(2)*s;
00400     rotation_matrix(1,1) = unit_axis(1)*unit_axis(1)+c*(1-unit_axis(1)*unit_axis(1));
00401     rotation_matrix(0,2) = unit_axis(0)*unit_axis(2)*(1-c)+unit_axis(1)*s;
00402     rotation_matrix(1,2) = unit_axis(1)*unit_axis(2)*(1-c)-unit_axis(0)*s;
00403     rotation_matrix(2,0) = unit_axis(0)*unit_axis(2)*(1-c)-unit_axis(1)*s;
00404     rotation_matrix(2,1) = unit_axis(1)*unit_axis(2)*(1-c)+unit_axis(0)*s;
00405     rotation_matrix(2,2) = unit_axis(2)*unit_axis(2)+c*(1-unit_axis(2)*unit_axis(2));
00406 
00407     Rotate(rotation_matrix);
00408 }
00409 
00410 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00411 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::RotateX(const double theta)
00412 {
00413     if (SPACE_DIM != 3)
00414     {
00415         EXCEPTION("This rotation is only valid in 3D");
00416     }
00417     c_matrix<double , SPACE_DIM, SPACE_DIM> x_rotation_matrix=identity_matrix<double>(SPACE_DIM);
00418 
00419     x_rotation_matrix(1,1) = cos(theta);
00420     x_rotation_matrix(1,2) = sin(theta);
00421     x_rotation_matrix(2,1) = -sin(theta);
00422     x_rotation_matrix(2,2) = cos(theta);
00423     Rotate(x_rotation_matrix);
00424 }
00425 
00426 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00427 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::RotateY(const double theta)
00428 {
00429     if (SPACE_DIM != 3)
00430     {
00431         EXCEPTION("This rotation is only valid in 3D");
00432     }
00433     c_matrix<double , SPACE_DIM, SPACE_DIM> y_rotation_matrix=identity_matrix<double>(SPACE_DIM);
00434 
00435     y_rotation_matrix(0,0) = cos(theta);
00436     y_rotation_matrix(0,2) = -sin(theta);
00437     y_rotation_matrix(2,0) = sin(theta);
00438     y_rotation_matrix(2,2) = cos(theta);
00439 
00440 
00441     Rotate(y_rotation_matrix);
00442 }
00443 
00444 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00445 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::RotateZ(const double theta)
00446 {
00447     if (SPACE_DIM < 2)
00448     {
00449         EXCEPTION("This rotation is not valid in less than 2D");
00450     }
00451     c_matrix<double , SPACE_DIM, SPACE_DIM> z_rotation_matrix=identity_matrix<double>(SPACE_DIM);
00452 
00453 
00454     z_rotation_matrix(0,0) = cos(theta);
00455     z_rotation_matrix(0,1) = sin(theta);
00456     z_rotation_matrix(1,0) = -sin(theta);
00457     z_rotation_matrix(1,1) = cos(theta);
00458 
00459     Rotate(z_rotation_matrix);
00460 }
00461 
00462 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00463 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(double theta)
00464 {
00465     RotateZ(theta);
00466 }
00467 
00468 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00469 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::RefreshMesh()
00470 {
00471 }
00472 
00473 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00474 bool AbstractMesh<ELEMENT_DIM, SPACE_DIM>::IsMeshChanging() const
00475 {
00476     return mMeshChangesDuringSimulation;
00477 }
00478 
00479 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00480 unsigned AbstractMesh<ELEMENT_DIM, SPACE_DIM>::CalculateMaximumContainingElementsPerProcess() const
00481 {
00482     unsigned max_num=0u;
00483     for (unsigned local_node_index=0; local_node_index<mNodes.size(); local_node_index++)
00484     {
00485         unsigned num=mNodes[local_node_index]->GetNumContainingElements();
00486         if (num>max_num)
00487         {
00488             max_num=num;
00489         }
00490     }
00491     return max_num;
00492 }
00493 
00494 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00495 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::SetMeshHasChangedSinceLoading()
00496 {
00497     // We just forget what the original file was, which has the desired effect
00498     mMeshFileBaseName = "";
00499 }
00500 
00502 // Explicit instantiation
00504 
00505 template class AbstractMesh<1,1>;
00506 template class AbstractMesh<1,2>;
00507 template class AbstractMesh<1,3>;
00508 template class AbstractMesh<2,2>;
00509 template class AbstractMesh<2,3>;
00510 template class AbstractMesh<3,3>;

Generated by  doxygen 1.6.2