37 #include <boost/lexical_cast.hpp> 38 #include "RandomNumberGenerator.hpp" 39 #include "SmartPointers.hpp" 40 #include "VoronoiGenerator.hpp" 41 #include "Polygon.hpp" 42 #include "Exception.hpp" 43 #include "VesselNetworkGenerator.hpp" 45 template<
unsigned DIM>
47 mReferenceLength(1.e-6 *
unit::metres)
51 template<
unsigned DIM>
56 template <
unsigned DIM>
62 template<
unsigned DIM>
64 unsigned num_increments,
69 double increment_size = (2.0 * M_PI) /
double(num_increments);
71 std::vector<boost::shared_ptr<VesselNode<DIM> > > v1_nodes;
77 double x_offset = increment_size + std::sqrt(b_param*b_param + a_param*a_param);
78 c_vector<double, 2*DIM> bounds = zero_vector<double>(2*DIM);
83 std::vector<boost::shared_ptr<VesselNode<DIM> > > v2_nodes;
85 for(
unsigned idx=0; idx<= num_increments/2; idx++)
87 double t = double(idx) * increment_size;
88 double c_value = a_param*a_param*std::cos(2.0 * t) +
89 std::sqrt(pow(b_param,4) - a_param*a_param*pow(std::sin(2.0 * t),2));
90 double x = std::cos(t) * std::sqrt(c_value) + x_offset;
91 double y = std::sin(t) * std::sqrt(c_value);
99 std::vector<boost::shared_ptr<VesselNode<DIM> > > v3_nodes;
100 for(
unsigned idx=num_increments/2; idx<= num_increments; idx++)
102 double t = double(idx) * increment_size;
103 double c_value = a_param*a_param*std::cos(2.0 * t) +
104 std::sqrt(pow(b_param,4) - a_param*a_param*pow(std::sin(2.0 * t),2));
105 double x = std::cos(t) * std::sqrt(c_value) + x_offset;
106 double y = std::sin(t) * std::sqrt(c_value);
117 p_vessel_2->SetId(2);
118 p_vessel_3->SetId(3);
120 std::vector<boost::shared_ptr<VesselNode<DIM> > > v4_nodes;
123 bounds[1] = (std::sqrt(a_param*a_param + b_param*b_param) + increment_size + x_offset) * scale_factor/
mReferenceLength;
128 p_vessel_4->SetId(4);
130 p_network->AddVessel(p_vessel_1);
131 p_network->AddVessel(p_vessel_2);
132 p_network->AddVessel(p_vessel_3);
133 p_network->AddVessel(p_vessel_4);
134 p_network->MergeCoincidentNodes(1.e-6);
136 p_network->SetSegmentProperties(p_vessel_1->GetSegments()[0]);
137 p_vessel_1->GetStartNode()->GetFlowProperties()->SetIsInputNode(
true);
138 p_vessel_4->GetEndNode()->GetFlowProperties()->SetIsOutputNode(
true);
142 template<
unsigned DIM>
144 units::quantity<unit::per_area> targetDensity,
146 units::quantity<unit::length> exclusionDistance,
151 std::vector<units::quantity<unit::length> > bbox = domain->GetBoundingBox();
152 units::quantity<unit::length> delta_x = bbox[1] - bbox[0];
153 units::quantity<unit::length> delta_y = bbox[3] - bbox[2];
154 units::quantity<unit::length> delta_z = 0.0*unit::metres;
157 delta_z = bbox[5] - bbox[4];
159 if(delta_x == 0.0*unit::metres || delta_y == 0.0*unit::metres)
161 EXCEPTION(
"The domain must be at least two-dimensional.");
164 unsigned num_x = unsigned(units::sqrt(targetDensity) * delta_x);
165 unsigned num_y = unsigned(units::sqrt(targetDensity) * delta_y);
166 if(num_x == 0 || num_y == 0)
168 EXCEPTION(
"The domain is not large enough to contain any vessels at the requested density.");
170 units::quantity<unit::length> spacing_x = delta_x / double(num_x);
171 units::quantity<unit::length> spacing_y = delta_y / double(num_y);
174 std::vector<boost::shared_ptr<VesselNode<DIM> > > start_nodes;
175 std::vector<boost::shared_ptr<VesselNode<DIM> > > end_nodes;
176 if(distributionType == VesselDistribution::REGULAR)
178 for(
unsigned idx=0; idx<num_y; idx++)
180 for(
unsigned jdx=0; jdx<num_x; jdx++)
182 units::quantity<unit::length> location_x = bbox[0] + spacing_x / 2.0 + double(jdx) * spacing_x;
183 units::quantity<unit::length> location_y = bbox[2] + spacing_y / 2.0 + double(idx) * spacing_y;
197 else if(distributionType == VesselDistribution::UNIFORM)
199 unsigned attempts = 0;
200 for(
unsigned idx=0; idx<1.e9; idx++)
203 units::quantity<unit::length> location_x = bbox[0] + RandomNumberGenerator::Instance()->ranf() * delta_x;
204 units::quantity<unit::length> location_y = bbox[2] + RandomNumberGenerator::Instance()->ranf() * delta_y;
207 bool free_space =
true;
208 bool outside_x = location_x - bbox[0] < exclusionDistance || bbox[1] - location_x < exclusionDistance;
209 bool outside_y = location_y - bbox[2] < exclusionDistance || bbox[3] - location_y < exclusionDistance;
211 if(outside_x || outside_y)
218 for(
unsigned kdx=0; kdx<start_nodes.size();kdx++)
245 if(start_nodes.size() == num_x * num_y)
251 EXCEPTION(
"Too many attempts to locate a vessel");
255 else if(distributionType == VesselDistribution::TWO_LAYER)
257 unsigned attempts = 0;
260 unsigned num_kernels = 8;
261 std::vector<std::vector<units::quantity<unit::length> > > kernel_locations;
262 for(
unsigned kdx=0; kdx<num_kernels; kdx++)
264 std::vector<units::quantity<unit::length> > location;
265 location.push_back(bbox[0] + RandomNumberGenerator::Instance()->ranf() * delta_x);
266 location.push_back(bbox[2] + RandomNumberGenerator::Instance()->ranf() * delta_y);
267 kernel_locations.push_back(location);
271 for(
unsigned jdx=0;jdx<1.e9;jdx++)
273 units::quantity<unit::length> deviation = 100.0* 1.e-6*unit::metres;
276 unsigned kernel_index = RandomNumberGenerator::Instance()->randMod(num_kernels);
277 location_x += kernel_locations[kernel_index][0];
278 location_y += kernel_locations[kernel_index][1];
281 bool free_space =
true;
282 bool outside_x = location_x - bbox[0] < exclusionDistance || bbox[1] - location_x < exclusionDistance;
283 bool outside_y = location_y - bbox[2] < exclusionDistance || bbox[3] - location_y < exclusionDistance;
285 if(outside_x || outside_y)
292 for(
unsigned kdx=0; kdx<start_nodes.size();kdx++)
319 if(start_nodes.size() == num_x * num_y)
325 EXCEPTION(
"Too many attempts to locate a vessel");
331 std::vector<boost::shared_ptr<Vessel<DIM> > > vessels;
332 for(
unsigned idx=0; idx<start_nodes.size(); idx++)
339 p_network->AddVessels(vessels);
344 template<
unsigned DIM>
346 std::vector<units::quantity<unit::per_area> > targetDensity,
348 units::quantity<unit::length> exclusionDistance,
354 EXCEPTION(
"This generator works in 3-d only.");
357 if(targetDensity.size()!=3)
359 EXCEPTION(
"Target densities must be supplied for each x, y, z dimension.");
366 std::vector<units::quantity<unit::length> > bbox = domain->GetBoundingBox();
367 units::quantity<unit::length> delta_x = bbox[1] - bbox[0];
368 units::quantity<unit::length> delta_y = bbox[3] - bbox[2];
369 units::quantity<unit::length> delta_z = bbox[5] - bbox[4];
371 unsigned num_x = unsigned(units::sqrt(targetDensity[0]) * delta_x);
372 unsigned num_y = unsigned(units::sqrt(targetDensity[1]) * delta_y);
373 unsigned num_z = unsigned(units::sqrt(targetDensity[2]) * delta_z);
374 if(num_x == 0 || num_y == 0 || num_z == 0)
376 EXCEPTION(
"The domain is not large enough to contain any vessels at the requested density.");
378 units::quantity<unit::length> spacing_x = delta_x / double(num_x);
379 units::quantity<unit::length> spacing_y = delta_y / double(num_y);
380 units::quantity<unit::length> spacing_z = delta_z / double(num_z);
383 std::vector<boost::shared_ptr<VesselNode<DIM> > > nodes;
384 if(distributionType == VesselDistribution::REGULAR)
386 for(
unsigned kdx=0; kdx<num_z+2; kdx++)
388 for(
unsigned idx=0; idx<num_y+2; idx++)
390 for(
unsigned jdx=0; jdx<num_x+2; jdx++)
393 units::quantity<unit::length> location_x = bbox[0] + spacing_x / 2.0 + double(jdx) * spacing_x -spacing_x;
394 if(jdx==0 || jdx == num_x+1)
396 location_x -= spacing_x / 2.0;
400 location_x += spacing_x;
403 units::quantity<unit::length> location_y = bbox[2] + spacing_y / 2.0 + double(idx) * spacing_y - spacing_y;
404 if(idx==0 || idx == num_y+1)
406 location_y -= spacing_y / 2.0;
410 location_y += spacing_y;
413 units::quantity<unit::length> location_z = bbox[4] + spacing_z / 2.0 + double(kdx) * spacing_z - spacing_z;
414 if(kdx==0 || kdx == num_z+1)
416 location_z -= spacing_z / 2.0;
420 location_z += spacing_z;
433 std::vector<boost::shared_ptr<Vessel<DIM> > > vessels;
434 for(
unsigned kdx=1; kdx<num_z-1; kdx++)
436 for(
unsigned jdx=1; jdx<num_y-1; jdx++)
438 for(
unsigned idx=1; idx<num_x-1; idx++)
440 unsigned index = idx + num_x*jdx + num_y*num_x*kdx;
441 unsigned index_left = (idx-1) + num_x*jdx + num_y*num_x*kdx;
442 unsigned index_below = idx + num_x*(jdx-1) + num_y*num_x*kdx;
443 unsigned index_front = idx + num_x*(jdx) + num_y*num_x*(kdx-1);
449 unsigned index_right = (idx+1) + num_x*jdx + num_y*num_x*kdx;
454 unsigned index_up = idx + num_x*(jdx+1) + num_y*num_x*kdx;
459 unsigned index_back = idx + num_x*jdx + num_y*num_x*(kdx+1);
465 p_network->AddVessels(vessels);
468 else if(distributionType == VesselDistribution::UNIFORM)
470 std::vector<boost::shared_ptr<DimensionalChastePoint<DIM> > > seeds;
471 unsigned attempts = 0;
472 for(
unsigned idx=0; idx<1.e9; idx++)
475 units::quantity<unit::length> location_x = bbox[0] + RandomNumberGenerator::Instance()->ranf() * delta_x;
476 units::quantity<unit::length> location_y = bbox[2] + RandomNumberGenerator::Instance()->ranf() * delta_y;
477 units::quantity<unit::length> location_z = bbox[4] + RandomNumberGenerator::Instance()->ranf() * delta_z;
480 bool free_space =
true;
481 bool outside_x = location_x - bbox[0] < exclusionDistance || bbox[1] - location_x < exclusionDistance;
482 bool outside_y = location_y - bbox[2] < exclusionDistance || bbox[3] - location_y < exclusionDistance;
483 bool outside_z = location_z - bbox[4] < exclusionDistance || bbox[5] - location_z < exclusionDistance;
485 if(outside_x || outside_y || outside_z)
492 for(
unsigned kdx=0; kdx<seeds.size();kdx++)
511 if(seeds.size() == num_x * num_y * num_z)
517 EXCEPTION(
"Too many attempts to locate a vessel");
523 boost::shared_ptr<Part<DIM> > p_tesselation = generator.
Generate(domain, seeds, num_x * num_y * num_z);
524 p_network = GenerateFromPart(p_tesselation);
526 else if(distributionType == VesselDistribution::TWO_LAYER)
528 std::vector<boost::shared_ptr<DimensionalChastePoint<DIM> > > seeds;
529 unsigned attempts = 0;
532 unsigned num_kernels = 8;
533 std::vector<std::vector<units::quantity<unit::length> > > kernel_locations;
534 for(
unsigned kdx=0; kdx<num_kernels; kdx++)
536 std::vector<units::quantity<unit::length> > location;
537 location.push_back(bbox[0] + RandomNumberGenerator::Instance()->ranf() * delta_x);
538 location.push_back(bbox[2] + RandomNumberGenerator::Instance()->ranf() * delta_y);
539 location.push_back(bbox[3] + RandomNumberGenerator::Instance()->ranf() * delta_z);
540 kernel_locations.push_back(location);
544 for(
unsigned jdx=0;jdx<1.e9;jdx++)
546 units::quantity<unit::length> deviation = 100.0 * 1.e-6 * unit::metres;
550 unsigned kernel_index = RandomNumberGenerator::Instance()->randMod(num_kernels);
551 location_x += kernel_locations[kernel_index][0];
552 location_y += kernel_locations[kernel_index][1];
553 location_z += kernel_locations[kernel_index][2];
556 bool free_space =
true;
557 bool outside_x = location_x - bbox[0] < exclusionDistance || bbox[1] - location_x < exclusionDistance;
558 bool outside_y = location_y - bbox[2] < exclusionDistance || bbox[3] - location_y < exclusionDistance;
559 bool outside_z = location_z - bbox[4] < exclusionDistance || bbox[5] - location_z < exclusionDistance;
561 if(outside_x || outside_y || outside_z)
568 for(
unsigned kdx=0; kdx<seeds.size();kdx++)
587 if(seeds.size() == num_x * num_y * num_z)
593 EXCEPTION(
"Too many attempts to locate a vessel");
599 boost::shared_ptr<Part<DIM> > p_tesselation = generator.
Generate(domain, seeds, num_x * num_y * num_z);
600 p_network = GenerateFromPart(p_tesselation);
605 template<
unsigned DIM>
607 std::vector<unsigned> numberOfUnits)
616 if(numberOfUnits.size() >= 1)
618 num_x = numberOfUnits[0];
619 if(numberOfUnits.size() >= 2)
621 num_y = numberOfUnits[1];
622 if(numberOfUnits.size() >= 3 && DIM ==3)
624 num_z = numberOfUnits[2];
630 std::vector<boost::shared_ptr<Vessel<DIM> > > original_vessels = input_unit->GetVessels();
631 for(
unsigned idx =0; idx < num_x; idx++)
634 std::vector<boost::shared_ptr<Vessel<DIM> > > copied_vessels = input_unit->CopyVessels(original_vessels);
635 input_unit->Translate(translation_vector, copied_vessels);
637 input_unit->MergeCoincidentNodes();
639 std::vector<boost::shared_ptr<Vessel<DIM> > > x_transform_vessels = input_unit->GetVessels();
640 for(
unsigned idx =0; idx < num_y; idx++)
643 std::vector<boost::shared_ptr<Vessel<DIM> > > copied_vessels = input_unit->CopyVessels(x_transform_vessels);
644 input_unit->Translate(translation_vector, copied_vessels);
646 input_unit->MergeCoincidentNodes();
647 std::vector<boost::shared_ptr<Vessel<DIM> > > y_transform_vessels = input_unit->GetVessels();
649 for(
unsigned idx =0; idx < num_z; idx++)
652 std::vector<boost::shared_ptr<Vessel<DIM> > > copied_vessels = input_unit->CopyVessels(y_transform_vessels);
653 input_unit->Translate(translation_vector, copied_vessels);
655 input_unit->MergeCoincidentNodes();
658 template<
unsigned DIM>
663 std::vector<boost::shared_ptr<VesselNode<DIM> > > nodes;
680 std::vector<boost::shared_ptr<Vessel<DIM> > > vessels;
698 pNetwork->AddVessels(vessels);
703 template<
unsigned DIM>
709 std::vector<boost::shared_ptr<VesselNode<DIM> > > nodes;
718 std::vector<boost::shared_ptr<Vessel<DIM> > > vessels;
728 p_network->AddVessels(vessels);
729 p_network->Translate(startPosition);
733 template<
unsigned DIM>
736 unsigned divisions,
unsigned axis)
739 std::vector<boost::shared_ptr<VesselNode<DIM> > > nodes;
741 double interval = dimensionless_vessel_length/double(divisions + 1);
743 for(
unsigned idx=0;idx<divisions+1;idx++)
775 std::vector<boost::shared_ptr<Vessel<DIM> > > vessels;
780 p_network->AddVessels(vessels);
784 template<
unsigned DIM>
790 std::vector<boost::shared_ptr<Polygon<DIM> > > polygons = part->GetPolygons();
791 std::vector<boost::shared_ptr<Vessel<DIM> > > vessels;
792 for (
unsigned idx = 0; idx < polygons.size(); idx++)
794 std::vector<boost::shared_ptr<VesselSegment<DIM> > > segments;
795 std::vector<boost::shared_ptr<DimensionalChastePoint<DIM> > > vertices = polygons[idx]->GetVertices();
796 for (
unsigned jdx = 1; jdx < vertices.size(); jdx++)
802 p_network->AddVessels(vessels);
803 p_network->MergeCoincidentNodes();
807 template<
unsigned DIM>
809 units::quantity<unit::length> cubeY,
810 units::quantity<unit::length> cubeZ,
813 if(cubeZ == 0.0 * unit::metres || DIM==2)
815 EXCEPTION(
"This generator only works in 3D");
822 boost::shared_ptr<VesselNetwork<DIM> > p_network = GenerateFromPart(p_tesselation);
826 template<
unsigned DIM>
828 units::quantity<unit::length> radius, units::quantity<unit::length> thickess,
829 double azimuthExtent,
double polarExtent)
832 std::vector<boost::shared_ptr<VesselNode<DIM> > > nodes = pInputUnit->GetNodes();
833 for(
unsigned idx =0; idx<nodes.size(); idx++)
836 c_vector<double, DIM> offset = (extents.second - extents.first).GetLocation(
mReferenceLength);
838 double x_frac = node_loc[0] / offset[0];
839 double azimuth_angle = x_frac * azimuthExtent;
841 double y_frac = (node_loc[1] + 3.0) / offset[1];
842 double polar_angle = y_frac * polarExtent;
847 double z_frac = node_loc[2] / offset[2];
851 dimless_radius * std::cos(polar_angle),
852 dimless_radius * std::sin(azimuth_angle) * std::sin(polar_angle),
854 nodes[idx]->SetLocation(new_position);
858 template<
unsigned DIM>
860 units::quantity<unit::length> height,
861 units::quantity<unit::length> vessel_length)
869 double unit_height = 2.0 * grid_length;
870 double unit_width = 4.0 * grid_length;
873 unsigned units_in_x_direction = floor((width/
mReferenceLength)/ unit_width);
874 unsigned units_in_y_direction = floor((height/
mReferenceLength) / unit_height);
877 if (units_in_x_direction < 1)
879 units_in_x_direction = 1;
882 if (units_in_y_direction < 1)
884 units_in_x_direction = 1;
889 for(
unsigned jdx = 0; jdx<units_in_y_direction; jdx++)
891 for(
unsigned idx=0; idx<units_in_x_direction; idx++)
926 for(
unsigned idx=0; idx<units_in_x_direction; idx++)
935 pVesselNetwork->MergeCoincidentNodes();
936 return pVesselNetwork;
~VesselNetworkGenerator()
boost::shared_ptr< Part< DIM > > Generate(boost::shared_ptr< Part< DIM > > pPart, std::vector< boost::shared_ptr< DimensionalChastePoint< DIM > > > seeds=std::vector< boost::shared_ptr< DimensionalChastePoint< DIM > > >(), unsigned numSeeds=100)
static boost::shared_ptr< VesselNetwork< DIM > > Create()
void SetReferenceLengthScale(units::quantity< unit::length > rReferenceLength)
static boost::shared_ptr< Vessel< DIM > > Create(boost::shared_ptr< VesselSegment< DIM > > pSegment)
c_vector< double, DIM > GetLocation(units::quantity< unit::length > scale)
static boost::shared_ptr< Part< DIM > > Create()
units::quantity< unit::length > mReferenceLength