DiscreteSystemForceCalculator.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include "DiscreteSystemForceCalculator.hpp"
00030 
00031 DiscreteSystemForceCalculator::DiscreteSystemForceCalculator(MeshBasedCellPopulation<2>& rCellPopulation,
00032                                                              std::vector<boost::shared_ptr<AbstractTwoBodyInteractionForce<2> > > forceCollection)
00033     : mrCellPopulation(rCellPopulation),
00034       mForceCollection(forceCollection),
00035       mEpsilon(0.01)
00036 {
00037 }
00038 
00039 std::vector< std::vector<double> > DiscreteSystemForceCalculator::CalculateExtremalNormalForces()
00040 {
00041     unsigned num_nodes = mrCellPopulation.GetNumNodes();
00042 
00043     std::vector< std::vector<double> > extremal_normal_forces;
00044     std::vector<double> minimum_normal_forces(num_nodes);
00045     std::vector<double> maximum_normal_forces(num_nodes);
00046 
00047     for (unsigned i=0; i<num_nodes; i++)
00048     {
00049         std::vector<double> sampling_angles = GetSamplingAngles(i);
00050         std::vector<double> extremal_angles = GetExtremalAngles(i, sampling_angles);
00051 
00052         double minimum_normal_force_for_node_i = DBL_MAX;
00053         double maximum_normal_force_for_node_i = -DBL_MAX;
00054 
00055         for (unsigned j=0; j<extremal_angles.size(); j++)
00056         {
00057             double current_normal_force = CalculateFtAndFn(i, extremal_angles[j])[1];
00058 
00059             if (current_normal_force > maximum_normal_force_for_node_i)
00060             {
00061                 maximum_normal_force_for_node_i = current_normal_force;
00062             }
00063             if (current_normal_force < minimum_normal_force_for_node_i)
00064             {
00065                 minimum_normal_force_for_node_i = current_normal_force;
00066             }
00067         }
00068 
00069         assert( minimum_normal_force_for_node_i <= maximum_normal_force_for_node_i);
00070 
00071         minimum_normal_forces[i] = minimum_normal_force_for_node_i;
00072         maximum_normal_forces[i] = maximum_normal_force_for_node_i;
00073     }
00074 
00075     extremal_normal_forces.push_back(minimum_normal_forces);
00076     extremal_normal_forces.push_back(maximum_normal_forces);
00077 
00078     return extremal_normal_forces;
00079 }
00080 
00081 void DiscreteSystemForceCalculator::WriteResultsToFile(std::string simulationOutputDirectory)
00082 {
00083     double time = SimulationTime::Instance()->GetTime();
00084     std::ostringstream time_string;
00085     time_string << time;
00086     std::string results_directory = simulationOutputDirectory + "/results_from_time_" + time_string.str();
00087 
00088     OutputFileHandler output_file_handler2(results_directory+"/", false);
00089     mpVizStressResultsFile = output_file_handler2.OpenOutputFile("results.vizstress");
00090 
00091     (*mpVizStressResultsFile) <<  time << "\t";
00092 
00093     double global_index;
00094     double x;
00095     double y;
00096     double minimum;
00097     double maximum;
00098 
00099     TetrahedralMesh<2,2>& r_mesh = mrCellPopulation.rGetMesh();
00100 
00101     std::vector< std::vector<double> > extremal_normal_forces = CalculateExtremalNormalForces();
00102 
00103     for (unsigned i=0; i<r_mesh.GetNumNodes(); i++)
00104     {
00105         global_index = (double) i;
00106 
00107         x = r_mesh.GetNode(i)->rGetLocation()[0];
00108         y = r_mesh.GetNode(i)->rGetLocation()[1];
00109 
00110         minimum = extremal_normal_forces[0][i];
00111         maximum = extremal_normal_forces[1][i];
00112 
00113         (*mpVizStressResultsFile) << global_index << " " << x << " " << y << " " << minimum << " " << maximum << " ";
00114     }
00115 
00116     (*mpVizStressResultsFile) << "\n";
00117     mpVizStressResultsFile->close();
00118 }
00119 
00120 std::vector<double> DiscreteSystemForceCalculator::CalculateFtAndFn(unsigned index, double theta)
00121 {
00122     TetrahedralMesh<2,2>& r_mesh = mrCellPopulation.rGetMesh();
00123 
00124     std::set<unsigned> neighbouring_node_indices = mrCellPopulation.GetNeighbouringNodeIndices(index);
00125 
00126     double tangential_force = 0.0;
00127     double normal_force = 0.0;
00128     double alpha;
00129 
00130     c_vector<double,2> unit_vec_between_nodes(2);
00131 
00132     for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
00133          iter != neighbouring_node_indices.end();
00134          ++iter)
00135     {
00136         // The method GetAngleBetweenNodes() returns an angle in the range (-pi,pi]
00137         alpha = r_mesh.GetAngleBetweenNodes(index, *iter);
00138 
00139         assert(alpha <= M_PI);
00140         assert(alpha > -M_PI);
00141 
00142         if (sin(alpha-theta) > DBL_EPSILON)
00143         {
00144             // Initialise a zero force vector between neighbouring nodes
00145             c_vector<double,2> force_between_nodes = zero_vector<double>(2);
00146 
00147             // Iterate over vector of forces present and add up forces between nodes
00148             for (std::vector<boost::shared_ptr<AbstractTwoBodyInteractionForce<2> > >::iterator force_iter = mForceCollection.begin();
00149                  force_iter != mForceCollection.end();
00150                  ++force_iter)
00151             {
00152                force_between_nodes += (*force_iter)->CalculateForceBetweenNodes(index, *iter, mrCellPopulation);
00153             }
00154 
00155             unit_vec_between_nodes[0] = cos(alpha);
00156             unit_vec_between_nodes[1] = sin(alpha);
00157 
00158             double plusminus_norm_force = inner_prod(force_between_nodes,unit_vec_between_nodes);
00159             tangential_force += plusminus_norm_force * cos(alpha-theta);
00160             normal_force += plusminus_norm_force * sin(alpha-theta);
00161         }
00162     }
00163 
00164     std::vector<double> ret(2);
00165     ret[0] = tangential_force;
00166     ret[1] = normal_force;
00167 
00168     return ret;
00169 }
00170 
00171 std::vector<double> DiscreteSystemForceCalculator::GetSamplingAngles(unsigned index)
00172 {
00173     TetrahedralMesh<2,2>& r_mesh = mrCellPopulation.rGetMesh();
00174 
00175     std::set<unsigned> neighbouring_node_indices = mrCellPopulation.GetNeighbouringNodeIndices(index);
00176 
00177     std::vector<double> sampling_angles(4*neighbouring_node_indices.size());
00178 
00179     unsigned i=0;
00180 
00181     for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
00182          iter != neighbouring_node_indices.end();
00183          ++iter)
00184     {
00185         // The method GetAngleBetweenNodes() returns an angle in the range (-pi,pi]
00186         double alpha = r_mesh.GetAngleBetweenNodes(index, *iter);
00187 
00188         double alpha_minus_epsilon = alpha - mEpsilon;
00189         double alpha_plus_epsilon = alpha + mEpsilon;
00190         double alpha_plus_pi_minus_epsilon = alpha + M_PI - mEpsilon;
00191         double alpha_plus_pi_plus_epsilon = alpha + M_PI + mEpsilon;
00192 
00193         // Calculate sampling angles in the range (-pi,pi]
00194 
00195         #define COVERAGE_IGNORE
00196         if (alpha_minus_epsilon <= -M_PI)
00197         {
00198             alpha_minus_epsilon += 2*M_PI;
00199         }
00200         #undef COVERAGE_IGNORE
00201         sampling_angles[i] = alpha_minus_epsilon;
00202 
00203         assert(sampling_angles[i] <= M_PI);
00204         assert(sampling_angles[i] > -M_PI);
00205         i++;
00206 
00207         if (alpha_plus_epsilon > M_PI)
00208         {
00209             alpha_plus_epsilon -= 2*M_PI;
00210         }
00211         sampling_angles[i] = alpha_plus_epsilon;
00212 
00213         assert(sampling_angles[i] <= M_PI);
00214         assert(sampling_angles[i] > -M_PI);
00215         i++;
00216 
00217         if (alpha_plus_pi_minus_epsilon > M_PI)
00218         {
00219             alpha_plus_pi_minus_epsilon -= 2*M_PI;
00220         }
00221         sampling_angles[i] = alpha_plus_pi_minus_epsilon;
00222 
00223         assert(sampling_angles[i] <= M_PI);
00224         assert(sampling_angles[i] > -M_PI);
00225         i++;
00226 
00227         if (alpha_plus_pi_plus_epsilon > M_PI)
00228         {
00229             alpha_plus_pi_plus_epsilon -= 2*M_PI;
00230         }
00231         sampling_angles[i] = alpha_plus_pi_plus_epsilon;
00232 
00233         assert(sampling_angles[i] <= M_PI);
00234         assert(sampling_angles[i] > -M_PI);
00235         i++;
00236     }
00237 
00238     sort(sampling_angles.begin(), sampling_angles.end());
00239     return sampling_angles;
00240 }
00241 
00242 double DiscreteSystemForceCalculator::GetLocalExtremum(unsigned index, double angle1, double angle2)
00243 {
00244     // We always pass in angle1 and angle2 such that angle1<angle2,
00245     // but note that angle1 may be <M_PI
00246     assert(angle1 < angle2);
00247 
00248     double tolerance = 1e-5;
00249     unsigned counter = 0;
00250 
00251     double previous_angle;
00252     double current_error;
00253     double current_angle = angle1;
00254 
00255     current_error = angle2 - angle1;
00256     std::vector<double> current_ft_and_fn(2);
00257 
00258     while (current_error > tolerance)
00259     {
00260         previous_angle = current_angle;
00261         current_ft_and_fn = CalculateFtAndFn(index, current_angle);
00262         current_angle -= current_ft_and_fn[0]/current_ft_and_fn[1];
00263         current_error = fabs(current_angle - previous_angle);
00264         counter++;
00265     }
00266 
00267     assert(current_angle>angle1 && current_angle<angle2);
00268     assert(current_error < tolerance);
00269 
00270     return current_angle;
00271 }
00272 
00273 std::vector<double> DiscreteSystemForceCalculator::GetExtremalAngles(unsigned index, std::vector<double> samplingAngles)
00274 {
00275     std::vector<double> extremal_angles;
00276     std::vector<double> ft_and_fn(2);
00277     std::vector<double> tangential_force(samplingAngles.size());
00278 
00279     for (unsigned i=0; i<samplingAngles.size(); i++)
00280     {
00281         ft_and_fn = CalculateFtAndFn(index, samplingAngles[i]);
00282         tangential_force[i] = ft_and_fn[0];
00283     }
00284 
00285     unsigned n = samplingAngles.size()-1;
00286 
00287     for (unsigned i=0; i<n; i++)
00288     {
00289         if ( ( tangential_force[i%n]>0 && tangential_force[(i+1)%n]<0 ) ||
00290              ( tangential_force[i%n]<0 && tangential_force[(i+1)%n]>0 ) )
00291         {
00292             double next_extremal_angle;
00293 
00294             // If we are in the interval that crosses the branch line at pi,
00295             // then subtract 2*pi from the positive angle
00296             if (i==n-1)
00297             {
00298                 samplingAngles[i%n] -= 2*M_PI;
00299             }
00300 
00301             if (samplingAngles[(i+1)%n] - samplingAngles[i%n] < 2*mEpsilon + 1e-6 )
00302             {
00303                 // If we find a jump through zero, then the local extremum is
00304                 // simply at the mid-point of the interval
00305                 next_extremal_angle = 0.5*(samplingAngles[(i+1)%n] + samplingAngles[i%n]);
00306             }
00307             else
00308             {
00309                 // Otherwise we need to find it using Newton's method
00310                 next_extremal_angle = GetLocalExtremum(index, samplingAngles[i%n], samplingAngles[(i+1)%n]);
00311             }
00312 
00313             if (next_extremal_angle <= -M_PI)
00314             {
00315                 next_extremal_angle += 2*M_PI;
00316             }
00317             assert(next_extremal_angle>-M_PI && next_extremal_angle<=M_PI);
00318             extremal_angles.push_back(next_extremal_angle);
00319         }
00320     }
00321 
00322     return extremal_angles;
00323 }
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3