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