Chaste Release::3.1
|
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 "DiscreteSystemForceCalculator.hpp" 00037 00038 DiscreteSystemForceCalculator::DiscreteSystemForceCalculator(MeshBasedCellPopulation<2>& rCellPopulation, 00039 std::vector<boost::shared_ptr<AbstractTwoBodyInteractionForce<2> > > forceCollection) 00040 : mrCellPopulation(rCellPopulation), 00041 mForceCollection(forceCollection), 00042 mEpsilon(0.01) 00043 { 00044 } 00045 00046 std::vector< std::vector<double> > DiscreteSystemForceCalculator::CalculateExtremalNormalForces() 00047 { 00048 unsigned num_nodes = mrCellPopulation.GetNumNodes(); 00049 00050 std::vector< std::vector<double> > extremal_normal_forces; 00051 std::vector<double> minimum_normal_forces(num_nodes); 00052 std::vector<double> maximum_normal_forces(num_nodes); 00053 00054 for (unsigned i=0; i<num_nodes; i++) 00055 { 00056 std::vector<double> sampling_angles = GetSamplingAngles(i); 00057 std::vector<double> extremal_angles = GetExtremalAngles(i, sampling_angles); 00058 00059 double minimum_normal_force_for_node_i = DBL_MAX; 00060 double maximum_normal_force_for_node_i = -DBL_MAX; 00061 00062 for (unsigned j=0; j<extremal_angles.size(); j++) 00063 { 00064 double current_normal_force = CalculateFtAndFn(i, extremal_angles[j])[1]; 00065 00066 if (current_normal_force > maximum_normal_force_for_node_i) 00067 { 00068 maximum_normal_force_for_node_i = current_normal_force; 00069 } 00070 if (current_normal_force < minimum_normal_force_for_node_i) 00071 { 00072 minimum_normal_force_for_node_i = current_normal_force; 00073 } 00074 } 00075 00076 assert( minimum_normal_force_for_node_i <= maximum_normal_force_for_node_i); 00077 00078 minimum_normal_forces[i] = minimum_normal_force_for_node_i; 00079 maximum_normal_forces[i] = maximum_normal_force_for_node_i; 00080 } 00081 00082 extremal_normal_forces.push_back(minimum_normal_forces); 00083 extremal_normal_forces.push_back(maximum_normal_forces); 00084 00085 return extremal_normal_forces; 00086 } 00087 00088 void DiscreteSystemForceCalculator::WriteResultsToFile(std::string simulationOutputDirectory) 00089 { 00090 double time = SimulationTime::Instance()->GetTime(); 00091 std::ostringstream time_string; 00092 time_string << time; 00093 std::string results_directory = simulationOutputDirectory + "/results_from_time_" + time_string.str(); 00094 00095 OutputFileHandler output_file_handler2(results_directory+"/", false); 00096 mpVizStressResultsFile = output_file_handler2.OpenOutputFile("results.vizstress"); 00097 00098 (*mpVizStressResultsFile) << time << "\t"; 00099 00100 double global_index; 00101 double x; 00102 double y; 00103 double minimum; 00104 double maximum; 00105 00106 TetrahedralMesh<2,2>& r_mesh = mrCellPopulation.rGetMesh(); 00107 00108 std::vector< std::vector<double> > extremal_normal_forces = CalculateExtremalNormalForces(); 00109 00110 for (unsigned i=0; i<r_mesh.GetNumNodes(); i++) 00111 { 00112 global_index = (double) i; 00113 00114 x = r_mesh.GetNode(i)->rGetLocation()[0]; 00115 y = r_mesh.GetNode(i)->rGetLocation()[1]; 00116 00117 minimum = extremal_normal_forces[0][i]; 00118 maximum = extremal_normal_forces[1][i]; 00119 00120 (*mpVizStressResultsFile) << global_index << " " << x << " " << y << " " << minimum << " " << maximum << " "; 00121 } 00122 00123 (*mpVizStressResultsFile) << "\n"; 00124 mpVizStressResultsFile->close(); 00125 } 00126 00127 std::vector<double> DiscreteSystemForceCalculator::CalculateFtAndFn(unsigned index, double theta) 00128 { 00129 TetrahedralMesh<2,2>& r_mesh = mrCellPopulation.rGetMesh(); 00130 00131 std::set<unsigned> neighbouring_node_indices = mrCellPopulation.GetNeighbouringNodeIndices(index); 00132 00133 double tangential_force = 0.0; 00134 double normal_force = 0.0; 00135 double alpha; 00136 00137 c_vector<double,2> unit_vec_between_nodes(2); 00138 00139 for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin(); 00140 iter != neighbouring_node_indices.end(); 00141 ++iter) 00142 { 00143 // The method GetAngleBetweenNodes() returns an angle in the range (-pi,pi] 00144 alpha = r_mesh.GetAngleBetweenNodes(index, *iter); 00145 00146 assert(alpha <= M_PI); 00147 assert(alpha > -M_PI); 00148 00149 if (sin(alpha-theta) > DBL_EPSILON) 00150 { 00151 // Initialise a zero force vector between neighbouring nodes 00152 c_vector<double,2> force_between_nodes = zero_vector<double>(2); 00153 00154 // Iterate over vector of forces present and add up forces between nodes 00155 for (std::vector<boost::shared_ptr<AbstractTwoBodyInteractionForce<2> > >::iterator force_iter = mForceCollection.begin(); 00156 force_iter != mForceCollection.end(); 00157 ++force_iter) 00158 { 00159 force_between_nodes += (*force_iter)->CalculateForceBetweenNodes(index, *iter, mrCellPopulation); 00160 } 00161 00162 unit_vec_between_nodes[0] = cos(alpha); 00163 unit_vec_between_nodes[1] = sin(alpha); 00164 00165 double plusminus_norm_force = inner_prod(force_between_nodes,unit_vec_between_nodes); 00166 tangential_force += plusminus_norm_force * cos(alpha-theta); 00167 normal_force += plusminus_norm_force * sin(alpha-theta); 00168 } 00169 } 00170 00171 std::vector<double> ret(2); 00172 ret[0] = tangential_force; 00173 ret[1] = normal_force; 00174 00175 return ret; 00176 } 00177 00178 std::vector<double> DiscreteSystemForceCalculator::GetSamplingAngles(unsigned index) 00179 { 00180 TetrahedralMesh<2,2>& r_mesh = mrCellPopulation.rGetMesh(); 00181 00182 std::set<unsigned> neighbouring_node_indices = mrCellPopulation.GetNeighbouringNodeIndices(index); 00183 00184 std::vector<double> sampling_angles(4*neighbouring_node_indices.size()); 00185 00186 unsigned i=0; 00187 00188 for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin(); 00189 iter != neighbouring_node_indices.end(); 00190 ++iter) 00191 { 00192 // The method GetAngleBetweenNodes() returns an angle in the range (-pi,pi] 00193 double alpha = r_mesh.GetAngleBetweenNodes(index, *iter); 00194 00195 double alpha_minus_epsilon = alpha - mEpsilon; 00196 double alpha_plus_epsilon = alpha + mEpsilon; 00197 double alpha_plus_pi_minus_epsilon = alpha + M_PI - mEpsilon; 00198 double alpha_plus_pi_plus_epsilon = alpha + M_PI + mEpsilon; 00199 00200 // Calculate sampling angles in the range (-pi,pi] 00201 00202 #define COVERAGE_IGNORE 00203 if (alpha_minus_epsilon <= -M_PI) 00204 { 00205 alpha_minus_epsilon += 2*M_PI; 00206 } 00207 #undef COVERAGE_IGNORE 00208 sampling_angles[i] = alpha_minus_epsilon; 00209 00210 assert(sampling_angles[i] <= M_PI); 00211 assert(sampling_angles[i] > -M_PI); 00212 i++; 00213 00214 if (alpha_plus_epsilon > M_PI) 00215 { 00216 alpha_plus_epsilon -= 2*M_PI; 00217 } 00218 sampling_angles[i] = alpha_plus_epsilon; 00219 00220 assert(sampling_angles[i] <= M_PI); 00221 assert(sampling_angles[i] > -M_PI); 00222 i++; 00223 00224 if (alpha_plus_pi_minus_epsilon > M_PI) 00225 { 00226 alpha_plus_pi_minus_epsilon -= 2*M_PI; 00227 } 00228 sampling_angles[i] = alpha_plus_pi_minus_epsilon; 00229 00230 assert(sampling_angles[i] <= M_PI); 00231 assert(sampling_angles[i] > -M_PI); 00232 i++; 00233 00234 if (alpha_plus_pi_plus_epsilon > M_PI) 00235 { 00236 alpha_plus_pi_plus_epsilon -= 2*M_PI; 00237 } 00238 sampling_angles[i] = alpha_plus_pi_plus_epsilon; 00239 00240 assert(sampling_angles[i] <= M_PI); 00241 assert(sampling_angles[i] > -M_PI); 00242 i++; 00243 } 00244 00245 sort(sampling_angles.begin(), sampling_angles.end()); 00246 return sampling_angles; 00247 } 00248 00249 double DiscreteSystemForceCalculator::GetLocalExtremum(unsigned index, double angle1, double angle2) 00250 { 00251 // We always pass in angle1 and angle2 such that angle1<angle2, 00252 // but note that angle1 may be <M_PI 00253 assert(angle1 < angle2); 00254 00255 double tolerance = 1e-5; 00256 unsigned counter = 0; 00257 00258 double previous_angle; 00259 double current_error; 00260 double current_angle = angle1; 00261 00262 current_error = angle2 - angle1; 00263 std::vector<double> current_ft_and_fn(2); 00264 00265 while (current_error > tolerance) 00266 { 00267 previous_angle = current_angle; 00268 current_ft_and_fn = CalculateFtAndFn(index, current_angle); 00269 current_angle -= current_ft_and_fn[0]/current_ft_and_fn[1]; 00270 current_error = fabs(current_angle - previous_angle); 00271 counter++; 00272 } 00273 00274 assert(current_angle>angle1 && current_angle<angle2); 00275 assert(current_error < tolerance); 00276 00277 return current_angle; 00278 } 00279 00280 std::vector<double> DiscreteSystemForceCalculator::GetExtremalAngles(unsigned index, std::vector<double> samplingAngles) 00281 { 00282 std::vector<double> extremal_angles; 00283 std::vector<double> ft_and_fn(2); 00284 std::vector<double> tangential_force(samplingAngles.size()); 00285 00286 for (unsigned i=0; i<samplingAngles.size(); i++) 00287 { 00288 ft_and_fn = CalculateFtAndFn(index, samplingAngles[i]); 00289 tangential_force[i] = ft_and_fn[0]; 00290 } 00291 00292 unsigned n = samplingAngles.size()-1; 00293 00294 for (unsigned i=0; i<n; i++) 00295 { 00296 if ( ( tangential_force[i%n]>0 && tangential_force[(i+1)%n]<0 ) || 00297 ( tangential_force[i%n]<0 && tangential_force[(i+1)%n]>0 ) ) 00298 { 00299 double next_extremal_angle; 00300 00301 // If we are in the interval that crosses the branch line at pi, 00302 // then subtract 2*pi from the positive angle 00303 if (i==n-1) 00304 { 00305 samplingAngles[i%n] -= 2*M_PI; 00306 } 00307 00308 if (samplingAngles[(i+1)%n] - samplingAngles[i%n] < 2*mEpsilon + 1e-6 ) 00309 { 00310 // If we find a jump through zero, then the local extremum is 00311 // simply at the mid-point of the interval 00312 next_extremal_angle = 0.5*(samplingAngles[(i+1)%n] + samplingAngles[i%n]); 00313 } 00314 else 00315 { 00316 // Otherwise we need to find it using Newton's method 00317 next_extremal_angle = GetLocalExtremum(index, samplingAngles[i%n], samplingAngles[(i+1)%n]); 00318 } 00319 00320 if (next_extremal_angle <= -M_PI) 00321 { 00322 next_extremal_angle += 2*M_PI; 00323 } 00324 assert(next_extremal_angle>-M_PI && next_extremal_angle<=M_PI); 00325 extremal_angles.push_back(next_extremal_angle); 00326 } 00327 } 00328 00329 return extremal_angles; 00330 }