7 #include <boost/property_tree/xml_parser.hpp> 12 using namespace popgen;
21 throw runtime_error(
string(__func__) +
"> Data directory not present! Aborting.");
26 }
catch (exception& e) {
31 long int tot = m_props.get <
long 32 int > (
"population.<xmlattr>.total");
35 throw invalid_argument(
"Invalid attribute population::total");
39 }
catch (invalid_argument& e) {
41 }
catch (exception& e) {
42 throw invalid_argument(
"Missing/invalid attribute population::total");
55 if (m_output) cerr <<
"Generating " << m_total <<
" people...\n";
66 assignToUniversities();
69 double start_radius = m_props.get<
double>(
"population.commutingdata.<xmlattr>.start_radius");
70 double factor = m_props.get<
double>(
"population.commutingdata.<xmlattr>.factor");
72 vector<pair<GeoCoordinate, map<double, vector<uint>>>> distance_map = makeDistanceMap(start_radius, factor,
73 m_primary_communities);
77 distance_map = makeDistanceMap(start_radius, factor, m_secondary_communities);
79 "secondary communities");
81 if (m_output) cerr <<
"Generated " << m_people.size() <<
" people\n";
83 string target_cities = prefix +
"_districts.csv";
84 string target_pop = prefix +
"_people.csv";
85 string target_households = prefix +
"_households.csv";
86 string target_clusters = prefix +
"_clusters.csv";
87 string target_summary = prefix +
".xml";
89 writeCities(target_cities);
91 writeHouseholds(target_households);
92 writeClusters(target_clusters);
96 config.put(
"population.people", target_pop);
97 config.put(
"population.districts", target_cities);
98 config.put(
"population.clusters", target_clusters);
99 config.put(
"population.households", target_households);
100 config.add_child(
"population.cities", m_props.get_child(
"population.cities"));
102 if (m_output) cout <<
"Written summary " << target_summary << endl;
108 double total_pop = 0.0;
111 total_pop += city.m_current_size;
115 total_pop += village.m_current_size;
118 if (my_file.is_open()) {
120 <<
"\"city_id\",\"city_name\",\"province\",\"population\",\"x_coord\",\"y_coord\",\"latitude\",\"longitude\"\n";
122 uint provinces = m_props.get<
uint>(
"population.<xmlattr>.provinces");
125 auto printCityData = [&](
const SimpleCity& to_print) {
126 my_file << to_print.m_current_size / total_pop
128 << to_print.m_coord.m_latitude
130 << to_print.m_coord.m_longitude
141 my_file.precision(std::numeric_limits<double>::max_digits10);
145 <<
"\"," << dist(m_rng) + 1 <<
",";
149 uint village_counter = 1;
151 my_file.precision(std::numeric_limits<double>::max_digits10);
152 my_file << village.m_id
155 <<
"\"," << dist(m_rng) + 1 <<
",";
157 printVillageData(village);
162 if (m_output) cout <<
"Written " << target_cities << endl;
164 throw invalid_argument(
"In PopulationGenerator: Invalid file.");
172 if (my_file.is_open()) {
173 my_file <<
"\"age\",\"household_id\",\"school_id\",\"work_id\",\"primary_community\",\"secondary_community\"\n";
176 my_file << person.m_age <<
"," 177 << person.m_household_id <<
"," 178 << person.m_school_id <<
"," 179 << person.m_work_id <<
"," 180 << person.m_primary_community <<
"," 181 << person.m_secondary_community
186 if (m_output) cout <<
"Written " << target_pop << endl;
188 throw invalid_argument(
"In PopulationGenerator: Invalid file.");
195 if (my_file.is_open()) {
196 my_file <<
"\"hh_id\",\"latitude\",\"longitude\",\"size\"\n";
199 my_file << household.m_id <<
"," 200 << m_people.at(household.m_indices.at(0)).m_coord.m_latitude <<
"," 201 << m_people.at(household.m_indices.at(0)).m_coord.m_longitude <<
"," 202 << household.m_indices.size()
207 if (m_output) cout <<
"Written " << target_households << endl;
209 throw invalid_argument(
"In PopulationGenerator: Invalid file.");
216 if (my_file.is_open()) {
217 my_file <<
"\"cluster_id\",\"cluster_type\",\"latitude\",\"longitude\"\n";
226 for (
auto& cluster_type: types) {
228 while (m_locations.find(make_pair(cluster_type, current_id)) != m_locations.end()) {
229 my_file.precision(std::numeric_limits<double>::max_digits10);
230 my_file << current_id <<
"," 232 << m_locations.at(make_pair(cluster_type, current_id)).m_latitude <<
"," 233 << m_locations.at(make_pair(cluster_type, current_id)).m_longitude
241 if (m_output) cout <<
"Written " << target_clusters << endl;
243 throw invalid_argument(
"In PopulationGenerator: Invalid file.");
249 ptree pop_config = m_props.get_child(
"population");
255 int provinces = pop_config.get<
int>(
"<xmlattr>.provinces");
257 if (provinces <= 0) {
258 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
262 double radius = pop_config.get<
double>(
"commutingdata.<xmlattr>.start_radius");
263 double factor = pop_config.get<
double>(
"commutingdata.<xmlattr>.factor");
265 if (radius <= 0 || factor <= 1.0) {
266 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
270 if (m_output) cerr <<
"\rChecking for valid XML [0%]";
272 bool has_no_cities =
true;
273 auto cities_config = pop_config.get_child(
"cities");
274 vector<GeoCoordinate> current_locations;
275 for (
auto it = cities_config.begin(); it != cities_config.end(); it++) {
276 if (it->first ==
"city") {
277 has_no_cities =
false;
278 it->second.get<
string>(
"<xmlattr>.name");
279 total_size += it->second.get<
int>(
"<xmlattr>.pop");
280 double latitude = it->second.get<
double>(
"<xmlattr>.lat");
281 double longitude = it->second.get<
double>(
"<xmlattr>.lon");
283 if (abs(latitude) > 90 || abs(longitude) > 180) {
284 throw invalid_argument(
"In PopulationGenerator: Invalid geo-coordinate in XML.");
287 if (it->second.get<
int>(
"<xmlattr>.pop") <= 0) {
288 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
291 auto it2 = find(current_locations.begin(), current_locations.end(),
GeoCoordinate(latitude, longitude));
292 if (it2 != current_locations.end())
293 throw invalid_argument(
"In PopulationGenerator: Duplicate coordinates given in XML.");
295 current_locations.push_back(
GeoCoordinate(latitude, longitude));
297 throw invalid_argument(
"In PopulationGenerator: Missing/incorrect tags/attributes in XML.");
302 throw invalid_argument(
"In PopulationGenerator: No cities found.");
306 if (m_output) cerr <<
"\rChecking for valid XML [18%]";
307 auto village_config = pop_config.get_child(
"villages");
308 double village_radius_factor = village_config.get<
double>(
"<xmlattr>.radius");
310 bool has_no_villages =
true;
312 double fraction = 0.0;
313 for (
auto it = village_config.begin(); it != village_config.end(); it++) {
314 if (it->first ==
"village") {
315 has_no_villages =
false;
316 int minimum = it->second.get<
int>(
"<xmlattr>.min");
317 int max = it->second.get<
int>(
"<xmlattr>.max");
318 fraction += it->second.get<
double>(
"<xmlattr>.fraction") / 100.0;
321 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
324 if (minimum > max || minimum <= 0 || max < 0) {
325 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
327 }
else if (it->first ==
"<xmlattr>") {
329 throw invalid_argument(
"In PopulationGenerator: Missing/incorrect tags/attributes in XML.");
333 if (fraction != 1.0 || village_radius_factor <= 0.0) {
334 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
337 if (has_no_villages) {
338 throw invalid_argument(
"In PopulationGenerator: No villages found.");
344 if (m_output) cerr <<
"\rChecking for valid XML [36%]";
345 auto education_config = pop_config.get_child(
"education");
346 auto school_work_config = pop_config.get_child(
"school_work_profile");
347 total_size = education_config.get<
int>(
"mandatory.<xmlattr>.total_size");
348 int cluster_size = education_config.get<
int>(
"mandatory.<xmlattr>.cluster_size");
349 int mandatory_min = school_work_config.get<
int>(
"mandatory.<xmlattr>.min");
350 int mandatory_max = school_work_config.get<
int>(
"mandatory.<xmlattr>.max");
352 if (mandatory_min > mandatory_max || mandatory_min < 0 || mandatory_max < 0) {
353 throw invalid_argument(
"In PopulationGenerator: Numerical error in min/max pair.");
356 if (total_size <= 0 || cluster_size <= 0) {
357 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
361 if (m_output) cerr <<
"\rChecking for valid XML [42%]";
362 school_work_config = pop_config.get_child(
"school_work_profile.employable.young_employee");
363 int minimum = school_work_config.get<
int>(
"<xmlattr>.min");
364 int max = school_work_config.get<
int>(
"<xmlattr>.max");
365 cluster_size = education_config.get<
int>(
"optional.<xmlattr>.cluster_size");
366 fraction = 1.0 - school_work_config.get<
double>(
"<xmlattr>.fraction") / 100.0;
367 total_size = education_config.get<
uint>(
"optional.<xmlattr>.total_size");
369 if (minimum > max || minimum < 0 || max < 0) {
370 throw invalid_argument(
"In PopulationGenerator: Numerical error in min/max pair.");
373 if (total_size <= 0 || cluster_size <= 0 || fraction < 0.0 || fraction > 1.0) {
374 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
377 if (minimum <= mandatory_max) {
378 throw invalid_argument(
"In PopulationGenerator: Overlapping min/max pairs.");
381 fraction = education_config.get<
double>(
"optional.far.<xmlattr>.fraction") / 100.0;
383 if (fraction < 0.0 || fraction > 1.0) {
384 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
390 if (m_output) cerr <<
"\rChecking for valid XML [68%]";
391 school_work_config = pop_config.get_child(
"school_work_profile.employable");
392 auto work_config = pop_config.get_child(
"work");
394 total_size = work_config.get<
int>(
"<xmlattr>.size");
395 minimum = school_work_config.get<
int>(
"employee.<xmlattr>.min");
396 max = school_work_config.get<
int>(
"employee.<xmlattr>.max");
397 fraction = school_work_config.get<
double>(
"<xmlattr>.fraction") / 100.0;
399 if (minimum > max || minimum < 0 || max < 0) {
400 throw invalid_argument(
"In PopulationGenerator: Numerical error in min/max pair.");
403 if (total_size <= 0 || cluster_size <= 0 || fraction < 0.0 || fraction > 1.0) {
404 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
407 int min2 = school_work_config.get<
int>(
"young_employee.<xmlattr>.min");
408 int max2 = school_work_config.get<
int>(
"young_employee.<xmlattr>.max");
409 fraction = work_config.get<
double>(
"far.<xmlattr>.fraction") / 100.0;
411 if (min2 > max2 || min2 < 0 || max2 < 0) {
412 throw invalid_argument(
"In PopulationGenerator: Numerical error in min/max pair.");
415 if (max2 >= minimum) {
416 throw invalid_argument(
"In PopulationGenerator: Overlapping min/max pairs.");
419 if (fraction < 0.0 || fraction > 1.0) {
420 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
426 if (m_output) cerr <<
"\rChecking for valid XML [84%]";
427 total_size = pop_config.get<
int>(
"community.<xmlattr>.size");
429 if (total_size <= 0) {
430 throw invalid_argument(
"In PopulationGenerator: Numerical error.");
432 if (m_output) cerr <<
"\rChecking for valid XML [100%]\n";
438 string file_name = m_props.get<
string>(
"population.family.<xmlattr>.file");
442 vector<FamilyConfig> family_config {parser.
parseFamilies(file_name)};
444 uint current_generated = 0;
447 AliasDistribution dist {vector<double>(family_config.size(), 1.0 / family_config.size())};
448 while (current_generated < m_total) {
450 cerr <<
"\rGenerating households [" << min(
uint(
double(current_generated) / m_total * 100), 100U) <<
"%]";
453 uint family_index = dist(m_rng);
454 FamilyConfig& new_config = family_config.at(family_index);
458 new_household.
m_id = m_next_id;
459 for (
uint& age: new_config) {
462 m_people.push_back(new_person);
463 new_household.
m_indices.push_back(m_people.size() - 1);
466 m_age_distribution[age] = m_age_distribution[age] + 1;
470 m_household_size[new_config.size()] = m_household_size[new_config.size()] + 1;
472 m_households.push_back(new_household);
474 current_generated += new_config.size();
476 if (m_output) cerr <<
"\rGenerating households [100%]...\n";
481 ptree cities_config = m_props.get_child(
"population.cities");
486 uint to_generate = distance(cities_config.begin(), cities_config.end());
487 for (
auto it = cities_config.begin(); it != cities_config.end(); it++) {
488 if (m_output) cerr <<
"\rGenerating cities [" << min(
uint(
double(generated) / to_generate * 100), 100U) <<
"%]";
489 if (it->first ==
"city") {
490 string name = it->second.get<
string>(
"<xmlattr>.name");
491 int size = it->second.get<
int>(
"<xmlattr>.pop");
492 double latitude = it->second.get<
double>(
"<xmlattr>.lat");
493 double longitude = it->second.get<
double>(
"<xmlattr>.lon");
499 m_cities.push_back(new_city);
503 if (m_output) cerr <<
"\rGenerating cities [100%]...\n";
507 sort(m_cities.begin(), m_cities.end(), compare_city_size);
512 double latitude_middle = 0.0;
513 double longitude_middle = 0.0;
515 latitude_middle += city.m_coord.m_latitude;
516 longitude_middle += city.m_coord.m_longitude;
518 latitude_middle /= m_cities.size();
519 longitude_middle /= m_cities.size();
529 double current_maximum = -1.0;
533 double distance = calc.
getDistance(coord, city.m_coord);
534 if (distance > current_maximum) {
535 current_maximum = distance;
539 return current_maximum;
547 result += city.m_max_size;
558 result += village.m_max_size;
567 ptree village_config = m_props.get_child(
"population.villages");
568 double village_radius_factor = village_config.get<
double>(
"<xmlattr>.radius");
570 double radius = getCityRadius(middle);
571 uint city_population = getCityPopulation();
572 int unassigned_population = m_people.size() - city_population;
573 int unassigned_population_progress = unassigned_population;
576 vector<double> fractions;
577 vector<MinMax> boundaries;
578 for (
auto it = village_config.begin(); it != village_config.end(); it++) {
579 if (it->first ==
"village") {
580 uint min = it->second.get<
uint>(
"<xmlattr>.min");
581 uint max = it->second.get<
uint>(
"<xmlattr>.max");
582 double fraction = it->second.get<
double>(
"<xmlattr>.fraction") / 100.0;
583 MinMax min_max {min, max};
585 fractions.push_back(fraction);
586 boundaries.push_back(min_max);
593 while (unassigned_population > 0) {
595 cerr <<
"\rGenerating villages [" << min(
uint(
596 double(unassigned_population_progress - unassigned_population) / unassigned_population_progress *
598 uint village_type_index = village_type_dist(m_rng);
599 MinMax village_pop = boundaries.at(village_type_index);
600 uint range_interval_size = village_pop.
max - village_pop.
min + 1;
602 AliasDistribution village_size_dist {vector<double>(range_interval_size, 1.0 / range_interval_size)};
603 uint village_size = village_size_dist(m_rng) + village_pop.
min;
607 new_village.
m_id = m_next_id;
612 auto same_coordinate_village = [&](
const SimpleCluster& cl) {
return cl.m_coord == new_village.
m_coord; };
613 auto same_coordinate_city = [&](
const SimpleCity& cl) {
return cl.m_coord == new_village.
m_coord; };
615 auto it_villages = find_if(m_villages.begin(), m_villages.end(), same_coordinate_village);
616 auto it_cities = find_if(m_cities.begin(), m_cities.end(), same_coordinate_city);
618 if (it_villages == m_villages.end() && it_cities == m_cities.end()) {
619 m_villages.push_back(new_village);
620 unassigned_population -= new_village.
m_max_size;
623 if (m_output) cerr <<
"\rGenerating villages [100%]...\n";
628 uint city_pop = getCityPopulation();
629 uint village_pop = getVillagePopulation();
631 village_pop + city_pop;
635 vector<double> fractions;
637 fractions.push_back(
double(city.m_max_size) /
double(total_pop));
641 fractions.push_back(
double(village.m_max_size) /
double(total_pop));
648 cerr <<
"\rPlacing households [" << min(
uint(
double(i) / m_households.size() * 100), 100U) <<
"%]";
649 uint index = village_city_dist(m_rng);
650 if (index < m_cities.size()) {
654 for (
uint& person_index: household.m_indices) {
655 m_people.at(person_index).m_coord = city.
m_coord;
661 SimpleCluster& village = m_villages.at(index - m_cities.size());
663 for (
uint& person_index: household.m_indices) {
664 m_people.at(person_index).m_coord = village.
m_coord;
670 if (m_output) cerr <<
"\rPlacing households [100%]...\n";
677 ptree education_config = m_props.get_child(
"population.education");
678 ptree school_work_config = m_props.get_child(
"population.school_work_profile.mandatory");
679 uint school_size = education_config.get<
uint>(
"mandatory.<xmlattr>.total_size");
680 uint min_age = school_work_config.get<
uint>(
"<xmlattr>.min");
681 uint max_age = school_work_config.get<
uint>(
"<xmlattr>.max");
682 uint cluster_size = education_config.get<
uint>(
"mandatory.<xmlattr>.cluster_size");
684 placeClusters(school_size, min_age, max_age, 1.0, m_mandatory_schools,
"schools",
ClusterType::School,
false);
689 uint current_size = 0;
691 m_mandatory_schools_clusters.push_back(vector<SimpleCluster>());
692 while (current_size < cluster.m_max_size) {
693 current_size += cluster_size;
696 new_cluster.
m_id = m_next_id;
698 new_cluster.
m_coord = cluster.m_coord;
699 m_mandatory_schools_clusters.back().push_back(new_cluster);
708 ptree school_work_config = m_props.get_child(
"population.school_work_profile.employable.young_employee");
709 ptree university_config = m_props.get_child(
"population.education.optional");
710 uint min_age = school_work_config.get<
uint>(
"<xmlattr>.min");
711 uint max_age = school_work_config.get<
uint>(
"<xmlattr>.max");
712 double fraction = 1.0 - school_work_config.get<
double>(
"<xmlattr>.fraction") / 100.0;
713 uint size = university_config.get<
uint>(
"<xmlattr>.total_size");
714 uint cluster_size = university_config.get<
uint>(
"<xmlattr>.cluster_size");
716 uint intellectual_pop = 0;
717 for (
uint i = min_age; i <= max_age; i++) {
718 intellectual_pop += m_age_distribution[i];
721 intellectual_pop = ceil(intellectual_pop * fraction);
723 uint needed_universities = ceil(
double(intellectual_pop) / size);
724 uint placed_universities = 0;
725 uint clusters_per_univ = size / cluster_size;
726 uint left_over_cluster_size = size % cluster_size;
728 m_optional_schools.clear();
730 while (needed_universities > placed_universities) {
732 cerr <<
"\rPlacing Universities [" 733 << min(
uint(
double(needed_universities) / placed_universities * 100), 100U) <<
"%]";
737 vector<SimpleCluster> univ;
738 for (
uint i = 0; i < clusters_per_univ; i++) {
740 univ_cluster.
m_id = m_next_id;
742 univ_cluster.
m_coord = m_cities.at(placed_universities % m_cities.size()).m_coord;
744 univ.push_back(univ_cluster);
749 if (left_over_cluster_size > 0) {
752 univ_cluster.
m_id = m_next_id;
753 univ_cluster.
m_max_size = left_over_cluster_size;
754 univ_cluster.
m_coord = m_cities.at(placed_universities % m_cities.size()).m_coord;
756 univ.push_back(univ_cluster);
761 m_optional_schools.push_back(univ);
762 placed_universities++;
769 vector<SimpleCluster> result;
773 if (city.m_coord == workplace.m_coord) {
774 result.push_back(workplace);
781 if (village.m_coord == workplace.m_coord) {
782 result.push_back(workplace);
787 m_workplaces = result;
793 ptree school_work_config = m_props.get_child(
"population.school_work_profile.employable");
794 ptree work_config = m_props.get_child(
"population.work");
796 uint size = work_config.get<
uint>(
"<xmlattr>.size");
797 uint min_age = school_work_config.get<
uint>(
"employee.<xmlattr>.min");
798 uint max_age = school_work_config.get<
uint>(
"employee.<xmlattr>.max");
799 uint young_min_age = school_work_config.get<
uint>(
"young_employee.<xmlattr>.min");
800 uint young_max_age = school_work_config.get<
uint>(
"young_employee.<xmlattr>.max");
801 double young_fraction = school_work_config.get<
double>(
"young_employee.<xmlattr>.fraction") / 100.0;
802 double fraction = school_work_config.get<
double>(
"<xmlattr>.fraction") / 100.0;
804 uint possible_students = 0;
807 if (person.m_age >= young_min_age && person.m_age <= young_max_age) {
811 if (person.m_age >= std::max(min_age, young_max_age + 1) && person.m_age <= max_age) {
816 uint total_of_age = possible_students + total_old;
818 uint total_working = total_of_age - ceil(possible_students * (1.0 - young_fraction));
819 total_working = ceil(total_working * fraction);
822 double actual_fraction =
double(total_working) / total_of_age;
824 placeClusters(size, young_min_age, max_age, actual_fraction, m_workplaces,
"workplaces",
ClusterType::Work);
834 ptree community_config = m_props.get_child(
"population.community");
835 uint size = community_config.get<
uint>(
"<xmlattr>.size");
845 ptree education_config = m_props.get_child(
"population.education.mandatory");
846 ptree school_work_config = m_props.get_child(
"population.school_work_profile.mandatory");
847 uint min_age = school_work_config.get<
uint>(
"<xmlattr>.min");
848 uint max_age = school_work_config.get<
uint>(
"<xmlattr>.max");
849 double start_radius = m_props.get<
double>(
"population.commutingdata.<xmlattr>.start_radius");
851 double factor = m_props.get<
double>(
"population.commutingdata.<xmlattr>.factor");
853 double current_radius = start_radius;
856 uint total_placed = 0;
858 for (
uint i = min_age; i <= max_age; i++) {
859 total += m_age_distribution[i];
862 auto distance_map = makeDistanceMap(start_radius, factor, m_mandatory_schools);
865 current_radius = start_radius;
866 if (person.m_age >= min_age && person.m_age <= max_age) {
868 cerr <<
"\rAssigning children to schools [" << min(
uint(
double(total_placed) / total * 100), 100U)
872 vector<uint> closest_clusters_indices;
874 while (closest_clusters_indices.size() == 0 && m_mandatory_schools.size() != 0) {
875 closest_clusters_indices = getClustersWithinRange(current_radius, distance_map, person.m_coord);
876 current_radius *= factor;
880 vector<double>(closest_clusters_indices.size(), 1.0 /
double(closest_clusters_indices.size()))};
881 uint index = closest_clusters_indices.at(cluster_dist(m_rng));
883 AliasDistribution inner_cluster_dist {vector<double>(m_mandatory_schools_clusters.at(index).size(),
884 1.0 / m_mandatory_schools_clusters.at(index).size())};
885 uint index2 = inner_cluster_dist(m_rng);
887 m_mandatory_schools_clusters.at(index).at(index2).m_current_size++;
888 person.m_school_id = m_mandatory_schools_clusters.at(index).at(index2).m_id;
891 if (m_output) cerr <<
"\rAssigning children to schools [100%]...\n";
896 ptree school_work_config = m_props.get_child(
"population.school_work_profile.employable.young_employee");
897 ptree university_config = m_props.get_child(
"population.education.optional");
898 uint min_age = school_work_config.get<
uint>(
"<xmlattr>.min");
899 uint max_age = school_work_config.get<
uint>(
"<xmlattr>.max");
900 double student_fraction = 1.0 - school_work_config.get<
double>(
"<xmlattr>.fraction") / 100.0;
901 double commute_fraction = university_config.get<
double>(
"far.<xmlattr>.fraction") / 100.0;
902 double radius = m_props.get<
double>(
"population.commutingdata.<xmlattr>.start_radius");
908 uint total_placed = 0;
910 for (
uint i = min_age; i <= max_age; i++) {
911 total += m_age_distribution[i];
914 auto distance_map = makeDistanceMap(radius, 2.0, m_optional_schools);
917 if (person.m_age >= min_age && person.m_age <= max_age && student_dist(m_rng) == 0) {
919 cerr <<
"\rAssigning students to universities [" << min(
uint(
double(total_placed) / total * 100), 100U)
923 if (commute_dist(m_rng) == 0) {
925 assignCommutingStudent(person, distance_map);
928 assignCloseStudent(person, radius, distance_map);
932 if (m_output) cerr <<
"\rAssigning students to universities [100%]...\n";
938 bool full_capacity =
true;
940 for (
uint curr_univ = index; curr_univ < m_optional_schools.size(); ++curr_univ) {
941 for (
const SimpleCluster& uni: m_optional_schools.at(curr_univ)) {
942 if (uni.m_current_size < uni.m_max_size) {
943 full_capacity =
false;
950 for (
auto& coord_map_pair: distance_map) {
951 for (
auto it = coord_map_pair.second.begin(); it != coord_map_pair.second.end(); ++it) {
952 auto& index_vector = it->second;
954 auto cluster_iterator = std::find(index_vector.begin(), index_vector.end(), index);
956 if (cluster_iterator != index_vector.end()) {
957 index_vector.erase(cluster_iterator, cluster_iterator + 1);
959 removeFromUniMap(distance_map, index);
974 for (
auto& coord_map_pair: distance_map) {
975 for (
auto it = coord_map_pair.second.begin(); it != coord_map_pair.second.end(); ++it) {
976 auto& index_vector = it->second;
978 auto cluster_iterator = std::find(index_vector.begin(), index_vector.end(), index);
980 if (cluster_iterator != index_vector.end()) {
981 index_vector.erase(cluster_iterator, cluster_iterator + 1);
983 removeFromMap(distance_map, index);
994 vector<pair<
GeoCoordinate, map<
double, vector<uint>>>>& distance_map) {
995 uint current_city = 0;
998 while (current_city < m_cities.size() && !added) {
999 uint current_univ = current_city;
1000 while (current_univ < m_optional_schools.size() && !added) {
1001 for (
uint i = 0; i < m_optional_schools.at(current_univ).size(); ++i) {
1002 SimpleCluster& univ_cluster = m_optional_schools.at(current_univ).at(i);
1008 removeFromUniMap(distance_map, current_city);
1012 current_univ += m_cities.size();
1020 vector<pair<
GeoCoordinate, map<
double, vector<uint>>>>& distance_map) {
1021 double factor = m_props.get<
double>(
"population.commutingdata.<xmlattr>.factor");
1022 double current_radius = start_radius;
1024 vector<uint> closest_clusters_indices;
1031 closest_clusters_indices = getClustersWithinRange(current_radius, distance_map, person.
m_coord);
1033 if (closest_clusters_indices.size() != 0) {
1035 vector<double>(closest_clusters_indices.size(), 1.0 / closest_clusters_indices.size())};
1037 uint index = dist(m_rng);
1038 while (index < m_optional_schools.size() && !added) {
1040 for (
uint i = 0; i < m_optional_schools.at(index).size(); i++) {
1041 SimpleCluster& univ_cluster = m_optional_schools.at(index).at(i);
1047 removeFromUniMap(distance_map, index);
1051 index += m_cities.size();
1059 current_radius *= factor;
1065 ptree school_work_config = m_props.get_child(
"population.school_work_profile.employable");
1066 ptree work_config = m_props.get_child(
"population.work");
1067 uint min_age = school_work_config.get<
uint>(
"young_employee.<xmlattr>.min");
1068 uint max_age = school_work_config.get<
uint>(
"employee.<xmlattr>.max");
1069 double unemployment_rate = 1.0 - school_work_config.get<
double>(
"<xmlattr>.fraction") / 100.0;
1070 double commute_fraction = work_config.get<
double>(
"far.<xmlattr>.fraction") / 100.0;
1071 double radius = m_props.get<
double>(
"population.commutingdata.<xmlattr>.start_radius");
1073 AliasDistribution unemployment_dist {{unemployment_rate, 1.0 - unemployment_rate}};
1077 uint total_placed = 0;
1078 uint amount_full = 0;
1080 for (
uint i = min_age; i <= max_age; i++) {
1081 total += m_age_distribution[i];
1084 auto distance_map = makeDistanceMap(radius, 2.0, m_workplaces);
1087 if (amount_full == m_workplaces.size()) {
1092 if (person.m_age >= min_age && person.m_age <= max_age) {
1094 cerr <<
"\rAssigning people to workplaces [" << min(
uint(
double(total_placed) / total * 100), 100U)
1097 if (unemployment_dist(m_rng) == 1 && person.m_school_id == 0) {
1098 bool filled_cluster =
true;
1099 if (commute_dist(m_rng) == 0) {
1101 filled_cluster = assignCommutingEmployee(person, distance_map);
1104 filled_cluster = assignCloseEmployee(person, radius, distance_map);
1107 if (filled_cluster) {
1113 if (m_output) cerr <<
"\rAssigning people to workplaces [100%]...\n";
1118 vector<pair<
GeoCoordinate, map<
double, vector<uint>>>>& distance_map) {
1122 for (
uint i = 0; i < m_workplaces.size(); ++i) {
1130 return removeFromMap(distance_map, i);
1142 vector<pair<
GeoCoordinate, map<
double, vector<uint>>>>& distance_map) {
1143 double factor = m_props.get<
double>(
"population.commutingdata.<xmlattr>.factor");
1144 double current_radius = start_radius;
1146 vector<uint> closest_clusters_indices;
1148 while (closest_clusters_indices.size() == 0) {
1149 closest_clusters_indices = getClustersWithinRange(current_radius, distance_map, person.
m_coord);
1150 current_radius *= factor;
1154 vector<double>(closest_clusters_indices.size(), 1.0 /
double(closest_clusters_indices.size()))};
1155 uint rnd = dist(m_rng);
1156 auto index = closest_clusters_indices.at(rnd);
1164 return removeFromMap(distance_map, index);
1173 vector<SimpleCluster>& clusters,
1175 const string& name) {
1177 double start_radius = m_props.get<
double>(
"population.commutingdata.<xmlattr>.start_radius");
1178 double factor = m_props.get<
double>(
"population.commutingdata.<xmlattr>.factor");
1180 uint total = m_households.size();
1181 uint total_placed = 0;
1185 cerr <<
"\rAssigning people to " << name <<
" [" << min(
uint(
double(total_placed) / total * 100), 100U)
1189 double current_radius = start_radius;
1190 vector<uint> closest_clusters_indices;
1193 while (closest_clusters_indices.size() == 0) {
1194 closest_clusters_indices = getClustersWithinRange(current_radius, distance_map,
1195 m_people.at(household.m_indices.back()).m_coord);
1196 current_radius *= factor;
1200 vector<double>(closest_clusters_indices.size(), 1.0 /
double(closest_clusters_indices.size()))};
1201 uint index = closest_clusters_indices.at(dist(m_rng));
1203 for (
uint& person_index: household.m_indices) {
1205 person.*member = community.
m_id;
1211 removeFromMap(distance_map, index);
1215 if (m_output) cerr <<
"\rAssigning people to " << name <<
" [100%]...\n";
void writeClusters(const string &target_clusters) const
Writes the clusters to the file (type, ID and coordinates), see PopulationGenerator::generate.
void assignCommutingStudent(SimplePerson &person, vector< pair< GeoCoordinate, map< double, vector< uint >>>> &distance_map)
Put one student in a university according to the rules of commuting students.
Interface for install directory queries.
string toString(ClusterType c)
Converts a ClusterType value to corresponding name.
bool removeFromMap(vector< pair< GeoCoordinate, map< double, vector< uint >>>> &distance_map, uint index) const
Remove an element from the map (of regular clusters, not like universities, because they represent a ...
bool assignCloseEmployee(SimplePerson &person, double start_radius, vector< pair< GeoCoordinate, map< double, vector< uint >>>> &distance_map)
Assign one person to a workplace according to the rule of workers that work close to their home...
Usage is very simple, construct with a vector of probabilities, then use as a distribution from the s...
void assignToUniversities()
Put students in universities.
void writePop(const string &target_pop) const
Writes the population to the file, see PopulationGenerator::generate.
double getVillagePopulation() const
Get the population of all the villages combined (if they were on full capacity)
Time Dependent Person DataType.
GeoCoordinate generateRandomCoord(const GeoCoordinate &coord, double radius, T rng) const
Result is in kilometers Uses the haversine formula See: http://www.movable-type.co.uk/scripts/latlong.html.
static boost::filesystem::path getDataDir()
Utility method: get path to the directory for data files.
vector< FamilyConfig > parseFamilies(string filename) const
void assignToWork()
Assign people to a workplace.
void removeFromUniMap(vector< pair< GeoCoordinate, map< double, vector< uint >>>> &distance_map, uint index) const
Remove an element from the university map (the university map is special compared to other cluster ma...
double getCityRadius(const GeoCoordinate &coord) const
Returns the distance between the given coordinate and the furthest city (in km)
util::GeoCoordinate m_coord
void generate(const string &prefix)
Generates a population, writes the result to the files found in the data directory Output files are r...
void writeCities(const string &target_cities)
Writes the cities to the file, see PopulationGenerator::generate, recently, the villages have been ad...
void makeWork()
Make workplaces Note: due to the fact that the cluster size of workplaces must be respected...
util::GeoCoordinate m_coord
void makeUniversities()
Make the universities, place them in a city.
void checkForValidXML() const
Checks the xml on correctness, this includes only semantic errors, no syntax errors.
std::vector< uint > m_indices
bool assignCommutingEmployee(SimplePerson &person, vector< pair< GeoCoordinate, map< double, vector< uint >>>> &distance_map)
Assign one person to a workplace according to the rule of commuting workers.
void writeHouseholds(const string &target_households) const
Writes the households to the file, see PopulationGenerator::generate.
void assignToCommunities(vector< pair< GeoCoordinate, map< double, vector< uint >>>> &distance_map, vector< SimpleCluster > &clusters, uint SimplePerson::*member, const string &name="")
Assign entire households.
uint m_secondary_community
void makeSchools()
Make the schools, place them in a village/city.
void makeHouseholds()
Generates all households (not yet their positions)
void makeCommunities()
Make the communities.
PopulationGenerator(const string &filename, const int &seed, bool output=true)
Constructor: Check if the xml is valid and set up the basic things like a random generator.
vector< uint > FamilyConfig
void assignCloseStudent(SimplePerson &person, double start_radius, vector< pair< GeoCoordinate, map< double, vector< uint >>>> &distance_map)
Put one student in a university according to the rules of students that study close to their home...
void sortWorkplaces()
Make sure workplaces are sorted: workplaces in bigger cities are in front of workplaces in smaller ci...
util::GeoCoordinate m_coord
void makeVillages()
Generate all villages (without inhabitants)
void makeCities()
Generate all cities (without inhabitants)
double getDistance(const GeoCoordinate &coord1, const GeoCoordinate &coord2) const
static const GeoCoordCalculator & getInstance()
Singleton pattern.
void assignToSchools()
Put children in mandatory schools.
GeoCoordinate getCityMiddle() const
Gets the middle of all cities.
double getCityPopulation() const
Get the population of all the cities combined (if they were on full capacity)
void placeHouseholds()
Assign the households to a city/village.