Chaste Release::3.1
SurfaceAreaConstraintPottsUpdateRule.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 "SurfaceAreaConstraintPottsUpdateRule.hpp"
00037 
00038 template<unsigned DIM>
00039 SurfaceAreaConstraintPottsUpdateRule<DIM>::SurfaceAreaConstraintPottsUpdateRule()
00040     : AbstractPottsUpdateRule<DIM>(),
00041       mDeformationEnergyParameter(0.5), // Educated guess
00042       mMatureCellTargetSurfaceArea(16.0) // Defaults to a 4*4 cell size
00043 {
00045 }
00046 
00047 template<unsigned DIM>
00048 SurfaceAreaConstraintPottsUpdateRule<DIM>::~SurfaceAreaConstraintPottsUpdateRule()
00049 {
00050 }
00051 
00052 template<unsigned DIM>
00053 double SurfaceAreaConstraintPottsUpdateRule<DIM>::EvaluateHamiltonianContribution(unsigned currentNodeIndex,
00054                                                                         unsigned targetNodeIndex,
00055                                                                         PottsBasedCellPopulation<DIM>& rCellPopulation)
00056 {
00057     double delta_H = 0.0;
00058 
00059     // This method only works in 2D and 3D at present
00060     assert(DIM == 2 || DIM == 3);
00061 
00062     std::set<unsigned> containing_elements = rCellPopulation.GetNode(currentNodeIndex)->rGetContainingElementIndices();
00063     std::set<unsigned> new_location_containing_elements = rCellPopulation.GetNode(targetNodeIndex)->rGetContainingElementIndices();
00064 
00065     bool current_node_contained = !containing_elements.empty();
00066     bool target_node_contained = !new_location_containing_elements.empty();
00067 
00068     // Every node must each be in at most one element
00069     assert(new_location_containing_elements.size() < 2);
00070 
00071     if (!current_node_contained && !target_node_contained)
00072     {
00073         EXCEPTION("At least one of the current node or target node must be in an element.");
00074     }
00075 
00076     if (current_node_contained && target_node_contained)
00077     {
00078         if (*(new_location_containing_elements.begin()) == *(containing_elements.begin()))
00079         {
00080             EXCEPTION("The current node and target node must not be in the same element.");
00081         }
00082     }
00083 
00084     // Iterate over nodes neighbouring the target node to work out the change in surface area
00085     unsigned neighbours_in_same_element_as_current_node = 0;
00086     unsigned neighbours_in_same_element_as_target_node = 0;
00087     std::set<unsigned> target_neighbouring_node_indices = rCellPopulation.rGetMesh().GetVonNeumannNeighbouringNodeIndices(targetNodeIndex);
00088     for (std::set<unsigned>::iterator iter = target_neighbouring_node_indices.begin();
00089          iter != target_neighbouring_node_indices.end();
00090          ++iter)
00091     {
00092         std::set<unsigned> neighbouring_node_containing_elements = rCellPopulation.rGetMesh().GetNode(*iter)->rGetContainingElementIndices();
00093 
00094         // Every node must each be in at most one element
00095         assert(neighbouring_node_containing_elements.size() < 2);
00096 
00097         bool neighbouring_node_contained = !neighbouring_node_containing_elements.empty();
00098 
00099         if (neighbouring_node_contained && target_node_contained)
00100         {
00101             unsigned neighbour_element = (*neighbouring_node_containing_elements.begin());
00102             unsigned target_element = (*new_location_containing_elements.begin());
00103             if (target_element == neighbour_element)
00104             {
00105                 neighbours_in_same_element_as_target_node++;
00106             }
00107         }
00108         if (neighbouring_node_contained && current_node_contained)
00109         {
00110             unsigned neighbour_element = (*neighbouring_node_containing_elements.begin());
00111             unsigned current_element = (*containing_elements.begin());
00112             if (current_element == neighbour_element)
00113             {
00114                 neighbours_in_same_element_as_current_node++;
00115             }
00116         }
00117     }
00118 
00119     if (DIM == 2)
00120     {
00121         assert(neighbours_in_same_element_as_current_node<5);
00122         assert(neighbours_in_same_element_as_target_node<5);
00123 
00124         double change_in_surface_area[5] = {4,2,0,-2,-4};
00125 
00126         if (current_node_contained) // current node is in an element
00127         {
00128             unsigned current_element = (*containing_elements.begin());
00129             double current_surface_area = rCellPopulation.rGetMesh().GetSurfaceAreaOfElement(current_element);
00130             double current_surface_area_difference = current_surface_area - mMatureCellTargetSurfaceArea;
00131             double current_surface_area_difference_after_switch = current_surface_area_difference + change_in_surface_area[neighbours_in_same_element_as_current_node];
00132 
00133             delta_H += mDeformationEnergyParameter*(current_surface_area_difference_after_switch*current_surface_area_difference_after_switch - current_surface_area_difference*current_surface_area_difference);
00134         }
00135         if (target_node_contained) // target node is in an element
00136         {
00137             unsigned target_element = (*new_location_containing_elements.begin());
00138             double target_surface_area = rCellPopulation.rGetMesh().GetSurfaceAreaOfElement(target_element);
00139             double target_surface_area_difference = target_surface_area - mMatureCellTargetSurfaceArea;
00140             double target_surface_area_difference_after_switch = target_surface_area_difference - change_in_surface_area[neighbours_in_same_element_as_target_node];
00141 
00142             delta_H += mDeformationEnergyParameter*(target_surface_area_difference_after_switch*target_surface_area_difference_after_switch - target_surface_area_difference*target_surface_area_difference);
00143         }
00144     }
00145     else if (DIM==3)
00146     {
00147         assert(neighbours_in_same_element_as_current_node < 7);
00148         assert(neighbours_in_same_element_as_target_node < 7);
00149 
00150         double change_in_surface_area[7] = {6,4,2,0,-2,-4,-6};
00151 
00152         if (current_node_contained) // current node is in an element
00153         {
00154             unsigned current_element = (*containing_elements.begin());
00155             double current_surface_area = rCellPopulation.rGetMesh().GetSurfaceAreaOfElement(current_element);
00156             double current_surface_area_difference = current_surface_area - mMatureCellTargetSurfaceArea;
00157             double current_surface_area_difference_after_switch = current_surface_area_difference + change_in_surface_area[neighbours_in_same_element_as_current_node];
00158 
00159             delta_H += mDeformationEnergyParameter*(current_surface_area_difference_after_switch*current_surface_area_difference_after_switch - current_surface_area_difference*current_surface_area_difference);
00160         }
00161         if (target_node_contained) // target node is in an element
00162         {
00163             unsigned target_element = (*new_location_containing_elements.begin());
00164             double target_surface_area = rCellPopulation.rGetMesh().GetSurfaceAreaOfElement(target_element);
00165             double target_surface_area_difference = target_surface_area - mMatureCellTargetSurfaceArea;
00166             double target_surface_area_difference_after_switch = target_surface_area_difference - change_in_surface_area[neighbours_in_same_element_as_target_node];
00167 
00168             delta_H += mDeformationEnergyParameter*(target_surface_area_difference_after_switch*target_surface_area_difference_after_switch - target_surface_area_difference*target_surface_area_difference);
00169         }
00170     }
00171 
00172     return delta_H;
00173 }
00174 
00175 template<unsigned DIM>
00176 double SurfaceAreaConstraintPottsUpdateRule<DIM>::GetDeformationEnergyParameter()
00177 {
00178     return mDeformationEnergyParameter;
00179 }
00180 
00181 template<unsigned DIM>
00182 void SurfaceAreaConstraintPottsUpdateRule<DIM>::SetDeformationEnergyParameter(double deformationEnergyParameter)
00183 {
00184     mDeformationEnergyParameter = deformationEnergyParameter;
00185 }
00186 
00187 template<unsigned DIM>
00188 double SurfaceAreaConstraintPottsUpdateRule<DIM>::GetMatureCellTargetSurfaceArea() const
00189 {
00190     return mMatureCellTargetSurfaceArea;
00191 }
00192 
00193 template<unsigned DIM>
00194 void SurfaceAreaConstraintPottsUpdateRule<DIM>::SetMatureCellTargetSurfaceArea(double matureCellTargetSurfaceArea)
00195 {
00196     assert(matureCellTargetSurfaceArea >= 0.0);
00197     mMatureCellTargetSurfaceArea = matureCellTargetSurfaceArea;
00198 }
00199 
00200 template<unsigned DIM>
00201 void SurfaceAreaConstraintPottsUpdateRule<DIM>::OutputUpdateRuleParameters(out_stream& rParamsFile)
00202 {
00203     *rParamsFile << "\t\t\t<DeformationEnergyParameter>" << mDeformationEnergyParameter << "</DeformationEnergyParameter>\n";
00204     *rParamsFile << "\t\t\t<MatureCellTargetSurfaceArea>" << mMatureCellTargetSurfaceArea << "</MatureCellTargetSurfaceArea>\n";
00205 
00206     // Call method on direct parent class
00207     AbstractPottsUpdateRule<DIM>::OutputUpdateRuleParameters(rParamsFile);
00208 }
00209 
00211 // Explicit instantiation
00213 
00214 template class SurfaceAreaConstraintPottsUpdateRule<1>;
00215 template class SurfaceAreaConstraintPottsUpdateRule<2>;
00216 template class SurfaceAreaConstraintPottsUpdateRule<3>;
00217 
00218 // Serialization for Boost >= 1.36
00219 #include "SerializationExportWrapperForCpp.hpp"
00220 EXPORT_TEMPLATE_CLASS_SAME_DIMS(SurfaceAreaConstraintPottsUpdateRule)