CryptProjectionForce.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 "CryptProjectionForce.hpp"
00037 #include "MeshBasedCellPopulation.hpp"
00038 #include "WntConcentration.hpp"
00039 #include "IsNan.hpp"
00040 
00041 CryptProjectionForce::CryptProjectionForce()
00042     : GeneralisedLinearSpringForce<2>(),
00043       mIncludeWntChemotaxis(false),
00044       mWntChemotaxisStrength(100.0)
00045 {
00046     mA = WntConcentration<2>::Instance()->GetCryptProjectionParameterA();
00047     mB = WntConcentration<2>::Instance()->GetCryptProjectionParameterB();
00048 }
00049 
00050 CryptProjectionForce::~CryptProjectionForce()
00051 {
00052 }
00053 
00054 void CryptProjectionForce::UpdateNode3dLocationMap(AbstractCellPopulation<2>& rCellPopulation)
00055 {
00056     mNode3dLocationMap.clear();
00057 
00058     c_vector<double, 2> node_location_2d;
00059     c_vector<double, 3> node_location_3d;
00060 
00061     // Only consider nodes corresponding to real cells
00062     for (AbstractCellPopulation<2>::Iterator cell_iter = rCellPopulation.Begin();
00063          cell_iter != rCellPopulation.End();
00064          ++cell_iter)
00065     {
00066         // Get node index
00067         unsigned node_index = rCellPopulation.GetLocationIndexUsingCell(*cell_iter);
00068 
00069         // Get 3D location
00070         node_location_2d = rCellPopulation.GetLocationOfCellCentre(*cell_iter);
00071 
00072         node_location_3d[0] = node_location_2d[0];
00073         node_location_3d[1] = node_location_2d[1];
00074         node_location_3d[2] = CalculateCryptSurfaceHeightAtPoint(node_location_2d);
00075 
00076         // Add to map
00077         mNode3dLocationMap[node_index] = node_location_3d;
00078     }
00079 }
00080 
00081 double CryptProjectionForce::GetA() const
00082 {
00083     return mA;
00084 }
00085 
00086 double CryptProjectionForce::GetB() const
00087 {
00088     return mB;
00089 }
00090 
00091 void CryptProjectionForce::SetWntChemotaxisStrength(double wntChemotaxisStrength)
00092 {
00093     assert(wntChemotaxisStrength >= 0.0);
00094     mWntChemotaxisStrength = wntChemotaxisStrength;
00095 }
00096 double CryptProjectionForce::GetWntChemotaxisStrength()
00097 {
00098     return mWntChemotaxisStrength;
00099 }
00100 
00101 void CryptProjectionForce::SetWntChemotaxis(bool includeWntChemotaxis)
00102 {
00103     mIncludeWntChemotaxis = includeWntChemotaxis;
00104 }
00105 
00106 double CryptProjectionForce::CalculateCryptSurfaceHeightAtPoint(const c_vector<double,2>& rNodeLocation)
00107 {
00108     return mA*pow(norm_2(rNodeLocation), mB); // =z_coord;
00109 }
00110 
00111 double CryptProjectionForce::CalculateCryptSurfaceDerivativeAtPoint(const c_vector<double,2>& rNodeLocation)
00112 {
00113     return mA*mB*pow(norm_2(rNodeLocation), (mB - 1.0));
00114 }
00115 
00116 c_vector<double,2> CryptProjectionForce::CalculateForceBetweenNodes(unsigned nodeAGlobalIndex, unsigned nodeBGlobalIndex, AbstractCellPopulation<2>& rCellPopulation)
00117 {
00118     MeshBasedCellPopulation<2>* p_static_cast_cell_population = static_cast<MeshBasedCellPopulation<2>*>(&rCellPopulation);
00119 
00120     // We should only ever calculate the force between two distinct nodes
00121     assert(nodeAGlobalIndex != nodeBGlobalIndex);
00122 
00123     // Get the node locations in 2D
00124     c_vector<double,2> node_a_location_2d = rCellPopulation.GetNode(nodeAGlobalIndex)->rGetLocation();
00125     c_vector<double,2> node_b_location_2d = rCellPopulation.GetNode(nodeBGlobalIndex)->rGetLocation();
00126 
00127     // "Get the unit vector parallel to the line joining the two nodes" [GeneralisedLinearSpringForce]
00128 
00129     // Create a unit vector in the direction of the 3D spring
00130     c_vector<double,3> unit_difference = mNode3dLocationMap[nodeBGlobalIndex] - mNode3dLocationMap[nodeAGlobalIndex];
00131 
00132     // Calculate the distance between the two nodes
00133     double distance_between_nodes = norm_2(unit_difference);
00134     assert(distance_between_nodes > 0);
00135     assert(!std::isnan(distance_between_nodes));
00136 
00137     unit_difference /= distance_between_nodes;
00138 
00139     // If mUseCutOffLength has been set, then there is zero force between
00140     // two nodes located a distance apart greater than mUseCutOffLength
00141     if (this->mUseCutOffLength)
00142     {
00143         if (distance_between_nodes >= mMechanicsCutOffLength)
00144         {
00145             // Return zero (2D projected) force
00146             return zero_vector<double>(2);
00147         }
00148     }
00149 
00150     // Calculate the rest length of the spring connecting the two nodes
00151 
00152     double rest_length = 1.0;
00153 
00154     CellPtr p_cell_A = rCellPopulation.GetCellUsingLocationIndex(nodeAGlobalIndex);
00155     CellPtr p_cell_B = rCellPopulation.GetCellUsingLocationIndex(nodeBGlobalIndex);
00156 
00157     double ageA = p_cell_A->GetAge();
00158     double ageB = p_cell_B->GetAge();
00159 
00160     assert(!std::isnan(ageA));
00161     assert(!std::isnan(ageB));
00162 
00163     /*
00164      * If the cells are both newly divided, then the rest length of the spring
00165      * connecting them grows linearly with time, until mMeinekeSpringGrowthDuration hour after division.
00166      */
00167     if (ageA < mMeinekeSpringGrowthDuration && ageB < mMeinekeSpringGrowthDuration)
00168     {
00169         /*
00170          * The spring rest length increases from a predefined small parameter
00171          * to a normal rest length of 1.0, over a period of one hour.
00172          */
00173         std::pair<CellPtr,CellPtr> cell_pair = p_static_cast_cell_population->CreateCellPair(p_cell_A, p_cell_B);
00174         if (p_static_cast_cell_population->IsMarkedSpring(cell_pair))
00175         {
00176             double lambda = mMeinekeDivisionRestingSpringLength;
00177             rest_length = lambda + (1.0 - lambda) * ageA/mMeinekeSpringGrowthDuration;
00178         }
00179         if (ageA+SimulationTime::Instance()->GetTimeStep() >= mMeinekeSpringGrowthDuration)
00180         {
00181             // This spring is about to go out of scope
00182             p_static_cast_cell_population->UnmarkSpring(cell_pair);
00183         }
00184     }
00185 
00186     double a_rest_length = rest_length*0.5;
00187     double b_rest_length = a_rest_length;
00188 
00189     /*
00190      * If either of the cells has begun apoptosis, then the length of the spring
00191      * connecting them decreases linearly with time.
00192      */
00193     if (p_cell_A->HasApoptosisBegun())
00194     {
00195         double time_until_death_a = p_cell_A->GetTimeUntilDeath();
00196         a_rest_length = a_rest_length * time_until_death_a / p_cell_A->GetApoptosisTime();
00197     }
00198     if (p_cell_B->HasApoptosisBegun())
00199     {
00200         double time_until_death_b = p_cell_B->GetTimeUntilDeath();
00201         b_rest_length = b_rest_length * time_until_death_b / p_cell_B->GetApoptosisTime();
00202     }
00203 
00204     rest_length = a_rest_length + b_rest_length;
00205 
00206     // Assert that the rest length does not exceed 1
00207     assert(rest_length <= 1.0+1e-12);
00208 
00209     bool is_closer_than_rest_length = true;
00210 
00211     if (distance_between_nodes - rest_length > 0)
00212     {
00213         is_closer_than_rest_length = false;
00214     }
00215 
00216     /*
00217      * Although in this class the 'spring constant' is a constant parameter, in
00218      * subclasses it can depend on properties of each of the cells.
00219      */
00220     double multiplication_factor = 1.0;
00221     multiplication_factor *= VariableSpringConstantMultiplicationFactor(nodeAGlobalIndex, nodeBGlobalIndex, rCellPopulation, is_closer_than_rest_length);
00222 
00223     // Calculate the 3D force between the two points
00224     c_vector<double,3> force_between_nodes = multiplication_factor * this->GetMeinekeSpringStiffness() * unit_difference * (distance_between_nodes - rest_length);
00225 
00226     // Calculate an outward normal unit vector to the tangent plane of the crypt surface at the 3D point corresponding to node B
00227     c_vector<double,3> outward_normal_unit_vector;
00228 
00229     double dfdr = CalculateCryptSurfaceDerivativeAtPoint(node_b_location_2d);
00230     double theta_B = atan2(node_b_location_2d[1], node_b_location_2d[0]); // use atan2 to determine the quadrant
00231     double normalization_factor = sqrt(1 + dfdr*dfdr);
00232 
00233     outward_normal_unit_vector[0] = dfdr*cos(theta_B)/normalization_factor;
00234     outward_normal_unit_vector[1] = dfdr*sin(theta_B)/normalization_factor;
00235     outward_normal_unit_vector[2] = -1.0/normalization_factor;
00236 
00237     // Calculate the projection of the force onto the plane z=0
00238     c_vector<double,2> projected_force_between_nodes_2d;
00239     double force_dot_normal = inner_prod(force_between_nodes, outward_normal_unit_vector);
00240 
00241     for (unsigned i=0; i<2; i++)
00242     {
00243         projected_force_between_nodes_2d[i] = force_between_nodes[i]
00244                                               - force_dot_normal*outward_normal_unit_vector[i]
00245                                               + force_dot_normal*outward_normal_unit_vector[2];
00246     }
00247 
00248     return projected_force_between_nodes_2d;
00249 }
00250 
00251 void CryptProjectionForce::AddForceContribution(AbstractCellPopulation<2>& rCellPopulation)
00252 {
00253     // First work out the 3D location of each cell
00254     UpdateNode3dLocationMap(rCellPopulation);
00255 
00256     // Throw an exception message if not using a MeshBasedCellPopulation
00257     if (dynamic_cast<MeshBasedCellPopulation<2>*>(&rCellPopulation) == NULL)
00258     {
00259         EXCEPTION("CryptProjectionForce is to be used with a subclass of MeshBasedCellPopulation only");
00260     }
00261 
00262     MeshBasedCellPopulation<2>* p_static_cast_cell_population = static_cast<MeshBasedCellPopulation<2>*>(&rCellPopulation);
00263 
00264     for (MeshBasedCellPopulation<2>::SpringIterator spring_iterator = p_static_cast_cell_population->SpringsBegin();
00265          spring_iterator != p_static_cast_cell_population->SpringsEnd();
00266          ++spring_iterator)
00267     {
00268         unsigned nodeA_global_index = spring_iterator.GetNodeA()->GetIndex();
00269         unsigned nodeB_global_index = spring_iterator.GetNodeB()->GetIndex();
00270 
00271         c_vector<double, 2> force = CalculateForceBetweenNodes(nodeA_global_index, nodeB_global_index, rCellPopulation);
00272         c_vector<double, 2> negative_force = -1.0 * force;
00273         spring_iterator.GetNodeB()->AddAppliedForceContribution(negative_force);
00274         spring_iterator.GetNodeA()->AddAppliedForceContribution(force);
00275     }
00276 
00277     if (mIncludeWntChemotaxis)
00278     {
00279         assert(WntConcentration<2>::Instance()->IsWntSetUp());
00280 
00281         for (AbstractCellPopulation<2>::Iterator cell_iter = rCellPopulation.Begin();
00282              cell_iter != rCellPopulation.End();
00283              ++cell_iter)
00284         {
00285             if (cell_iter->GetCellProliferativeType()->IsType<StemCellProliferativeType>())
00286             {
00287                 c_vector<double, 2> wnt_chemotactic_force = mWntChemotaxisStrength*WntConcentration<2>::Instance()->GetWntGradient(*cell_iter);
00288                 unsigned index = rCellPopulation.GetLocationIndexUsingCell(*cell_iter);
00289 
00290                 rCellPopulation.GetNode(index)->AddAppliedForceContribution(wnt_chemotactic_force);
00291             }
00292         }
00293     }
00294 }
00295 
00296 void CryptProjectionForce::OutputForceParameters(out_stream& rParamsFile)
00297 {
00298     *rParamsFile << "\t\t\t<A>" << mA << "</A>\n";
00299     *rParamsFile << "\t\t\t<B>" << mB << "</B>\n";
00300     *rParamsFile << "\t\t\t<IncludeWntChemotaxis>" << mIncludeWntChemotaxis << "</IncludeWntChemotaxis>\n";
00301     *rParamsFile << "\t\t\t<WntChemotaxisStrength>" << mWntChemotaxisStrength << "</WntChemotaxisStrength>\n";
00302 
00303     // Call method on direct parent class
00304     GeneralisedLinearSpringForce<2>::OutputForceParameters(rParamsFile);
00305 }
00306 
00307 // Serialization for Boost >= 1.36
00308 #include "SerializationExportWrapperForCpp.hpp"
00309 CHASTE_CLASS_EXPORT(CryptProjectionForce)

Generated by  doxygen 1.6.2