Chaste  Build::
AngiogenesisSolver.cpp
1 /*
2 
3  Copyright (c) 2005-2015, University of Oxford.
4  All rights reserved.
5 
6  University of Oxford means the Chancellor, Masters and Scholars of the
7  University of Oxford, having an administrative office at Wellington
8  Square, Oxford OX1 2JD, UK.
9 
10  This file is part of Chaste.
11 
12  Redistribution and use in source and binary forms, with or without
13  modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34  */
35 
36 #include <boost/lexical_cast.hpp>
37 #include "UblasIncludes.hpp"
38 #include "RandomNumberGenerator.hpp"
39 #include "VesselNode.hpp"
40 #include "VesselSegment.hpp"
41 #include "VesselNode.hpp"
42 #include "AngiogenesisSolver.hpp"
43 #include "StalkCellMutationState.hpp"
44 #include "TipCellMutationState.hpp"
45 #include "VesselNetworkWriter.hpp"
46 
47 template<unsigned DIM>
49  mpNetwork(),
50  mNodeAnastamosisRadius(5.0 * unit::microns),
51  mpMigrationRule(),
52  mpSproutingRule(),
53  mpBoundingDomain(),
54  mpFileHandler(),
55  mpVesselGrid(),
56  mpCellPopulation(),
57  mCellPopulationReferenceLength(5.0 * unit::microns),
58  mTipCells(),
59  mCellNodeMap()
60 {
61 
62 }
63 
64 template<unsigned DIM>
66 {
67 
68 }
69 
70 template<unsigned DIM>
71 boost::shared_ptr<AngiogenesisSolver<DIM> > AngiogenesisSolver<DIM>::Create()
72 {
73  MAKE_PTR(AngiogenesisSolver<DIM>, pSelf);
74  return pSelf;
75 }
76 
77 template<unsigned DIM>
79 {
80  return bool(mpSproutingRule);
81 }
82 
83 template<unsigned DIM>
84 void AngiogenesisSolver<DIM>::SetAnastamosisRadius(units::quantity<unit::length> radius)
85 {
86  mNodeAnastamosisRadius = radius;
87 }
88 
89 template<unsigned DIM>
90 void AngiogenesisSolver<DIM>::SetBoundingDomain(boost::shared_ptr<Part<DIM> > pDomain)
91 {
92  mpBoundingDomain = pDomain;
93 }
94 
95 template<unsigned DIM>
96 void AngiogenesisSolver<DIM>::SetCellPopulation(boost::shared_ptr<AbstractCellPopulation<DIM> > cell_population, units::quantity<unit::length> cellPopulationReferenceLength)
97 {
98  mpCellPopulation = cell_population;
99  mCellPopulationReferenceLength = cellPopulationReferenceLength;
100 }
101 
102 template<unsigned DIM>
104 {
105  mpMigrationRule = pMigrationRule;
106 }
107 
108 template<unsigned DIM>
109 void AngiogenesisSolver<DIM>::SetOutputFileHandler(boost::shared_ptr<OutputFileHandler> pHandler)
110 {
111  mpFileHandler = pHandler;
112 }
113 
114 template<unsigned DIM>
116 {
117  mpSproutingRule = pSproutingRule;
118 }
119 
120 template<unsigned DIM>
121 void AngiogenesisSolver<DIM>::SetVesselGrid(boost::shared_ptr<RegularGrid<DIM> > pVesselGrid)
122 {
123  mpVesselGrid = pVesselGrid;
124 }
125 
126 template<unsigned DIM>
128 {
129  mpNetwork = pNetwork;
130 }
131 
132 template<unsigned DIM>
134 {
135  // Get the candidate sprouts and set them as migrating
136  std::vector<boost::shared_ptr<VesselNode<DIM> > > candidate_sprouts = mpSproutingRule->GetSprouts(mpNetwork->GetNodes());
137  for (unsigned idx = 0; idx < candidate_sprouts.size(); idx++)
138  {
139  candidate_sprouts[idx]->SetIsMigrating(true);
140  }
141 
142  UpdateNodalPositions(true);
143 }
144 
145 template<unsigned DIM>
147 {
148  // Move any nodes marked as migrating, either new sprouts or tips
149  std::vector<boost::shared_ptr<VesselNode<DIM> > > nodes = mpNetwork->GetNodes();
150  std::vector<boost::shared_ptr<VesselNode<DIM> > > tips;
151  for (unsigned idx = 0; idx < nodes.size(); idx++)
152  {
153  if (sprouting)
154  {
155  if (nodes[idx]->IsMigrating() && nodes[idx]->GetNumberOfSegments() == 2)
156  {
157  tips.push_back(nodes[idx]);
158  }
159  }
160  else
161  {
162  if (nodes[idx]->IsMigrating() && nodes[idx]->GetNumberOfSegments() == 1)
163  {
164  tips.push_back(nodes[idx]);
165  }
166  }
167  }
168 
169  // Do lattice or off lattice movement
170  if (mpVesselGrid)
171  {
172  // If we have a cell population update the cell-point map
173  std::vector<int> indices = mpMigrationRule->GetIndices(tips);
174 
175  for (unsigned idx = 0; idx < tips.size(); idx++)
176  {
177  if(tips[idx]->GetFlowProperties()->IsInputNode() or tips[idx]->GetFlowProperties()->IsOutputNode())
178  {
179  tips[idx]->SetIsMigrating(false);
180  continue;
181  }
182 
183  if (indices[idx] >= 0 )
184  {
185  if (sprouting)
186  {
187  mpNetwork->FormSprout(tips[idx]->rGetLocation(), mpVesselGrid->GetLocationOf1dIndex(indices[idx]));
188  tips[idx]->SetIsMigrating(false);
189  mpNetwork->UpdateAll();
190  }
191  else
192  {
193  boost::shared_ptr<VesselNode<DIM> > p_new_node = VesselNode<DIM>::Create(tips[idx]);
194  p_new_node->SetLocation(mpVesselGrid->GetLocationOf1dIndex(indices[idx]));
195  mpNetwork->ExtendVessel(tips[idx]->GetSegment(0)->GetVessel(), tips[idx], p_new_node);
196  tips[idx]->SetIsMigrating(false);
197  p_new_node->SetIsMigrating(true);
198  mpNetwork->UpdateAll();
199  }
200  }
201  else
202  {
203  if (sprouting && tips[idx]->GetNumberOfSegments() == 2)
204  {
205  tips[idx]->SetIsMigrating(false);
206  }
207  }
208  }
209  }
210  else
211  {
212  if (mpBoundingDomain)
213  {
214  mpMigrationRule->SetBoundingDomain(mpBoundingDomain);
215  }
216 
217  mpMigrationRule->SetIsSprouting(sprouting);
218  std::vector<DimensionalChastePoint<DIM> > movement_vectors = mpMigrationRule->GetDirections(tips);
219  std::vector<DimensionalChastePoint<DIM> > candidate_tip_locations;
220  std::vector<bool> candidate_tips_inside_domain(tips.size(), true);
221  for (unsigned idx = 0; idx < tips.size(); idx++)
222  {
223  candidate_tip_locations.push_back(tips[idx]->rGetLocation() + movement_vectors[idx]);
224  }
225 
226  if (mpBoundingDomain)
227  {
228  candidate_tips_inside_domain = mpBoundingDomain->IsPointInPart(candidate_tip_locations);
229  }
230 
231  for (unsigned idx = 0; idx < tips.size(); idx++)
232  {
233  if(tips[idx]->GetFlowProperties()->IsInputNode() or tips[idx]->GetFlowProperties()->IsOutputNode())
234  {
235  tips[idx]->SetIsMigrating(false);
236  continue;
237  }
238 
239  if (movement_vectors[idx].GetNorm2() > 0.0*unit::metres)
240  {
241  if (candidate_tips_inside_domain[idx])
242  {
243  if (sprouting)
244  {
245  mpNetwork->FormSprout(tips[idx]->rGetLocation(), candidate_tip_locations[idx]);
246  mpNetwork->UpdateAll();
247  tips[idx]->SetIsMigrating(false);
248  }
249  else
250  {
251  boost::shared_ptr<VesselNode<DIM> > p_new_node = VesselNode<DIM>::Create(tips[idx]);
252  p_new_node->SetLocation(candidate_tip_locations[idx]);
253  mpNetwork->ExtendVessel(tips[idx]->GetSegment(0)->GetVessel(), tips[idx], p_new_node);
254  tips[idx]->SetIsMigrating(false);
255  p_new_node->SetIsMigrating(true);
256  }
257  }
258  }
259  else
260  {
261  if (sprouting && tips[idx]->GetNumberOfSegments() == 2)
262  {
263  tips[idx]->SetIsMigrating(false);
264  }
265  }
266  }
267  }
268  mpNetwork->UpdateAll();
269 }
270 
271 template<unsigned DIM>
273 {
274  mpNetwork->UpdateAll();
275  std::vector<boost::shared_ptr<VesselNode<DIM> > > nodes = mpNetwork->GetNodes();
276 
277  for (unsigned idx = 0; idx < nodes.size(); idx++)
278  {
279  // If this is currently a tip
280  if (nodes[idx]->IsMigrating() && nodes[idx]->GetNumberOfSegments() == 1)
281  {
282  if (mpVesselGrid)
283  {
284  std::vector<std::vector<boost::shared_ptr<VesselNode<DIM> > > > point_node_map = mpVesselGrid->GetPointNodeMap();
285  unsigned grid_index = mpVesselGrid->GetNearestGridIndex(nodes[idx]->rGetLocation());
286  if (point_node_map[grid_index].size() >= 2)
287  {
288  boost::shared_ptr<VesselNode<DIM> > p_merge_node = VesselNode<DIM>::Create(nodes[idx]);
289  if (point_node_map[grid_index][0] == nodes[idx])
290  {
291  p_merge_node = mpNetwork->DivideVessel(
292  point_node_map[grid_index][1]->GetSegment(0)->GetVessel(), nodes[idx]->rGetLocation());
293  }
294  else
295  {
296  p_merge_node = mpNetwork->DivideVessel(
297  point_node_map[grid_index][0]->GetSegment(0)->GetVessel(), nodes[idx]->rGetLocation());
298  }
299 
300  // Replace the tip node with the merge node
301  p_merge_node->SetIsMigrating(false);
302  if (nodes[idx]->GetSegment(0)->GetNode(0) == nodes[idx])
303  {
304  nodes[idx]->GetSegment(0)->ReplaceNode(0, p_merge_node);
305  }
306  else
307  {
308  nodes[idx]->GetSegment(0)->ReplaceNode(1, p_merge_node);
309  }
310  mpNetwork->UpdateAll();
311  }
312  }
313  else
314  {
315  // Get the nearest segment and check if it is close enough to the node for a merge
316  std::pair<boost::shared_ptr<VesselSegment<DIM> >, units::quantity<unit::length> > segment_pair =
317  mpNetwork->GetNearestSegment(nodes[idx], false);
318 
319  if (segment_pair.second <= mNodeAnastamosisRadius
320  && nodes[idx]->GetSegment(0)->GetLength() > segment_pair.second)
321  {
322  // If there is a non-zero anastamosis radius move the tip onto the segment
323  DimensionalChastePoint<DIM> original_location = nodes[idx]->rGetLocation();
324  if (mNodeAnastamosisRadius > 0.0 * unit::metres)
325  {
326  DimensionalChastePoint<DIM> divide_location = segment_pair.first->GetPointProjection(
327  original_location, true);
328  nodes[idx]->SetLocation(divide_location);
329  }
330  boost::shared_ptr<VesselNode<DIM> > p_merge_node = mpNetwork->DivideVessel(
331  segment_pair.first->GetVessel(), nodes[idx]->rGetLocation());
332 
333  // Replace the node at the end of the migrating tip with the merge node
334  if ((nodes[idx]->GetSegment(0)->GetNode(0) == p_merge_node)
335  || (nodes[idx]->GetSegment(0)->GetNode(1) == p_merge_node))
336  {
337  nodes[idx]->SetLocation(original_location);
338  }
339  else
340  {
341  p_merge_node->SetIsMigrating(false);
342  if (nodes[idx]->GetSegment(0)->GetNode(0) == nodes[idx])
343  {
344  nodes[idx]->GetSegment(0)->ReplaceNode(0, p_merge_node);
345  }
346  else
347  {
348  nodes[idx]->GetSegment(0)->ReplaceNode(1, p_merge_node);
349  }
350  }
351  mpNetwork->UpdateAll();
352  }
353  }
354  }
355  }
356 }
357 
358 template<unsigned DIM>
360 {
361  if (!mpNetwork)
362  {
363  EXCEPTION("The angiogenesis solver needs an initial vessel network");
364  }
365 
366  if (mpVesselGrid)
367  {
368  mpVesselGrid->SetVesselNetwork(mpNetwork);
369  if (mpCellPopulation)
370  {
372  }
373  }
374 
375  if (mpMigrationRule)
376  {
377  mpMigrationRule->SetNetwork(mpNetwork);
378  if (mpVesselGrid)
379  {
380  mpMigrationRule->SetGrid(mpVesselGrid);
381  }
382  if (mpCellPopulation)
383  {
384  mpMigrationRule->SetCellPopulation(mpCellPopulation);
385  }
386  }
387 
388  if (mpSproutingRule)
389  {
390  mpSproutingRule->SetVesselNetwork(mpNetwork);
391  if (mpVesselGrid)
392  {
393  mpSproutingRule->SetGrid(mpVesselGrid);
394  }
395  }
396 
397  // Move any migrating nodes
399 
400  // Check for anastamosis
401  DoAnastamosis();
402 
403  // Do sprouting
404  if (mpSproutingRule)
405  {
406  DoSprouting();
407  DoAnastamosis();
408  }
409 
410  // If there is a cell population, update it.
411  if (mpCellPopulation)
412  {
413  // First label all existing Tip ECs as sprouts
414  MAKE_PTR(StalkCellMutationState, p_EC_state);
415  MAKE_PTR(TipCellMutationState, p_EC_Tip_state);
416  CellPtr p_reference_cell;
417  for (typename AbstractCellPopulation<DIM, DIM>::Iterator cell_iter = mpCellPopulation->Begin();
418  cell_iter != mpCellPopulation->End(); ++cell_iter)
419  {
420  p_reference_cell = (*cell_iter);
421  if ((*cell_iter)->GetMutationState()->IsSame(p_EC_Tip_state))
422  {
423  (*cell_iter)->SetMutationState(p_EC_state);
424  }
425  }
426 
427  // Then create new tip cells corresponding to vessel tips
428  std::vector<boost::shared_ptr<VesselNode<DIM> > > nodes = mpNetwork->GetNodes();
429  for (unsigned idx = 0; idx < nodes.size(); idx++)
430  {
431  if (nodes[idx]->IsMigrating())
432  {
433  unsigned location_index = mpVesselGrid->GetNearestGridIndex(nodes[idx]->rGetLocation());
434 
435  // If there is already a stalk cell here it means a vessel tip has stayed in the same location, set it to tip type
436  if(mpCellPopulation->IsCellAttachedToLocationIndex(location_index))
437  {
438  if (mpCellPopulation->GetCellUsingLocationIndex(location_index)->GetMutationState()->IsSame(p_EC_state))
439  {
440  mpCellPopulation->GetCellUsingLocationIndex(location_index)->SetMutationState(p_EC_Tip_state);
441  }
442  }
443  else
444  {
445  // Make a new cell here
446  CellPtr p_new_cell(new Cell(p_EC_Tip_state, p_reference_cell->GetCellCycleModel()->CreateCellCycleModel()));
447  p_new_cell->GetCellCycleModel()->InitialiseDaughterCell();
448  p_new_cell->SetApoptosisTime(p_reference_cell->GetApoptosisTime());
449 
450  // Place them in the population
451  mpCellPopulation->AddCellUsingLocationIndex(location_index, p_new_cell); // this doesn't actually add a cell!
452  mpCellPopulation->rGetCells().push_back(p_new_cell); // do it manually here...
453  }
454  }
455  }
456  }
457 }
458 
459 template<unsigned DIM>
460 void AngiogenesisSolver<DIM>::Run(bool writeOutput)
461 {
462  // Set up a vessel network writer
463  boost::shared_ptr<VesselNetworkWriter<DIM> > p_network_writer = VesselNetworkWriter<DIM>::Create();
464 
465  // Loop for the duration of the simulation time
466  while (!SimulationTime::Instance()->IsFinished())
467  {
468  // Write the vessel network if appropriate
469  if (writeOutput && mpFileHandler && mpNetwork)
470  {
471  p_network_writer->SetFileName(
472  mpFileHandler->GetOutputDirectoryFullPath() + "/vessel_network_"
473  + boost::lexical_cast<std::string>(SimulationTime::Instance()->GetTimeStepsElapsed())
474  + ".vtp");
475  p_network_writer->SetVesselNetwork(mpNetwork);
476  p_network_writer->Write();
477  if (mpCellPopulation)
478  {
479  mpCellPopulation->OpenWritersFiles(*mpFileHandler);
480  mpCellPopulation->WriteResultsToFiles(mpFileHandler->GetRelativePath());
481  mpCellPopulation->CloseWritersFiles();
482  }
483  }
484 
485  // Increment the solver and simulation time
486  Increment();
487  SimulationTime::Instance()->IncrementTimeOneStep();
488  }
489 }
490 
491 // Explicit instantiation
492 template class AngiogenesisSolver<2> ;
493 template class AngiogenesisSolver<3> ;
void SetMigrationRule(boost::shared_ptr< AbstractMigrationRule< DIM > > pMigrationRule)
void SetAnastamosisRadius(units::quantity< unit::length > radius)
void SetVesselGrid(boost::shared_ptr< RegularGrid< DIM > >pVesselGrid)
static boost::shared_ptr< VesselNode< DIM > > Create(double v1=0.0, double v2=0.0, double v3=0.0)
Definition: VesselNode.cpp:100
static boost::shared_ptr< VesselNetworkWriter< DIM > > Create()
void SetCellPopulation(boost::shared_ptr< AbstractCellPopulation< DIM > > pCellPopulation, units::quantity< unit::length > cellPopulationReferenceLength)
void SetSproutingRule(boost::shared_ptr< AbstractSproutingRule< DIM > > pSproutingRule)
boost::shared_ptr< AbstractMigrationRule< DIM > > mpMigrationRule
virtual void DoAnastamosis()
virtual void UpdateNodalPositions(bool sprouting=false)
virtual void DoSprouting()
void SetOutputFileHandler(boost::shared_ptr< OutputFileHandler > pHandler)
units::quantity< unit::length > mCellPopulationReferenceLength
boost::shared_ptr< OutputFileHandler > mpFileHandler
units::quantity< unit::length > mNodeAnastamosisRadius
static boost::shared_ptr< AngiogenesisSolver< DIM > > Create()
boost::shared_ptr< AbstractCellPopulation< DIM > > mpCellPopulation
boost::shared_ptr< Part< DIM > > mpBoundingDomain
void SetVesselNetwork(boost::shared_ptr< VesselNetwork< DIM > > pNetwork)
boost::shared_ptr< VesselNetwork< DIM > > mpNetwork
void Run(bool writeOutput=false)
boost::shared_ptr< RegularGrid< DIM > > mpVesselGrid
void SetBoundingDomain(boost::shared_ptr< Part< DIM > > pDomain)
boost::shared_ptr< AbstractSproutingRule< DIM > > mpSproutingRule
Definition: Part.hpp:60