Stride Reference Manual  - generated for commit 9643b11
GeoGridJSONReader.cpp
Go to the documentation of this file.
1 /*
2  * This is free software: you can redistribute it and/or modify it
3  * under the terms of the GNU General Public License as published by
4  * the Free Software Foundation, either version 3 of the License, or
5  * any later version.
6  * The software is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  * You should have received a copy of the GNU General Public License
11  * along with the software. If not, see <http://www.gnu.org/licenses/>.
12  *
13  * Copyright 2018, 2019, Jan Broeckhove and Bistromatics group.
14  */
15 
16 #include "GeoGridJSONReader.h"
17 
18 #include "geopop/ContactCenter.h"
19 #include "geopop/GeoGrid.h"
20 #include "pop/Population.h"
21 #include "util/Exception.h"
22 
23 #include <boost/lexical_cast.hpp>
24 #include <boost/property_tree/json_parser.hpp>
25 #include <memory>
26 
27 namespace geopop {
28 
29 using namespace std;
30 using namespace stride;
31 using namespace stride::ContactType;
32 using namespace stride::util;
33 
34 GeoGridJSONReader::GeoGridJSONReader(unique_ptr<istream> inputStream, Population* pop)
35  : GeoGridReader(move(inputStream), pop)
36 {
37 }
38 
40 {
41  boost::property_tree::ptree root;
42  try {
43  boost::property_tree::read_json(*m_inputStream, root);
44  } catch (runtime_error&) {
45  throw Exception("Problem parsing JSON file, check whether empty or invalid JSON.");
46  }
47 
48  auto& geoGrid = m_population->RefGeoGrid();
49  auto people = root.get_child("persons");
50 
51  for (auto it = people.begin(); it != people.end(); it++) {
52  auto person = ParsePerson(it->second.get_child(""));
53  m_people[person->GetId()] = person;
54  }
55  auto locations = root.get_child("locations");
56 
57  for (auto it = locations.begin(); it != locations.end(); it++) {
58  shared_ptr<Location> loc;
59  loc = ParseLocation(it->second.get_child(""));
60  geoGrid.AddLocation(move(loc));
61  }
62 
63  AddCommutes(geoGrid);
64  m_commutes.clear();
65  m_people.clear();
66 }
67 
68 shared_ptr<Location> GeoGridJSONReader::ParseLocation(boost::property_tree::ptree& location)
69 {
70  const auto id = boost::lexical_cast<unsigned int>(location.get<string>("id"));
71  const auto name = location.get<string>("name");
72  const auto province = boost::lexical_cast<unsigned int>(location.get<string>("province"));
73  const auto population = boost::lexical_cast<unsigned int>(location.get<string>("population"));
74  const auto coordinate = ParseCoordinate(location.get_child("coordinate"));
75 
76  auto result = make_shared<Location>(id, province, coordinate, name, population);
77  auto contactCenters = location.get_child("contactCenters");
78 
79  for (auto it = contactCenters.begin(); it != contactCenters.end(); it++) {
80  const auto center = ParseContactCenter(it->second.get_child(""));
81  result->AddCenter(center);
82  }
83 
84  if (location.count("commutes")) {
85  boost::property_tree::ptree commutes = location.get_child("commutes");
86  for (auto it = commutes.begin(); it != commutes.end(); it++) {
87  const auto to = boost::lexical_cast<unsigned int>(it->first);
88  const auto amount = boost::lexical_cast<double>(it->second.data());
89  m_commutes.emplace_back(id, to, amount);
90  }
91  }
92 
93  return result;
94 }
95 
96 Coordinate GeoGridJSONReader::ParseCoordinate(boost::property_tree::ptree& coordinate)
97 {
98  const auto longitude = boost::lexical_cast<double>(coordinate.get<string>("longitude"));
99  const auto latitude = boost::lexical_cast<double>(coordinate.get<string>("latitude"));
100  return {longitude, latitude};
101 }
102 
103 shared_ptr<ContactCenter> GeoGridJSONReader::ParseContactCenter(boost::property_tree::ptree& contactCenter)
104 {
105  const auto type = contactCenter.get<string>("type");
106  const auto id = boost::lexical_cast<unsigned int>(contactCenter.get<string>("id"));
107 
108  ContactType::Id typeId;
109  if (type == ToString(Id::K12School)) {
110  typeId = Id::K12School;
111  } else if (type == ToString(Id::College)) {
112  typeId = Id::College;
113  } else if (type == ToString(Id::Household)) {
114  typeId = Id::Household;
115  } else if (type == ToString(Id::PrimaryCommunity)) {
116  typeId = Id::PrimaryCommunity;
117  } else if (type == ToString(Id::SecondaryCommunity)) {
118  typeId = Id::SecondaryCommunity;
119  } else if (type == ToString(Id::Workplace)) {
120  typeId = Id::Workplace;
121  } else {
122  throw Exception("No such ContactCenter type: " + type);
123  }
124  auto result = make_shared<ContactCenter>(id, typeId);
125  auto contactPools = contactCenter.get_child("pools");
126 
127  for (auto it = contactPools.begin(); it != contactPools.end(); it++) {
128  const auto pool = ParseContactPool(it->second.get_child(""), typeId);
129  result->RegisterPool(pool);
130  }
131 
132  return result;
133 }
134 
135 ContactPool* GeoGridJSONReader::ParseContactPool(boost::property_tree::ptree& contactPool, ContactType::Id typeId)
136 {
137  // Don't use the id of the ContactPool but the let the Population create an id.
138  auto result = m_population->RefPoolSys().CreateContactPool(typeId);
139  auto people = contactPool.get_child("people");
140 
141  for (auto it = people.begin(); it != people.end(); it++) {
142  auto person_id = boost::lexical_cast<unsigned int>(it->second.get<string>(""));
143  if (m_people.count(person_id) == 0) {
144  throw Exception("No such person: " + to_string(person_id));
145  }
146  result->AddMember(m_people[person_id]);
147  }
148 
149  return result;
150 }
151 
152 Person* GeoGridJSONReader::ParsePerson(boost::property_tree::ptree& person)
153 {
154  const auto id = boost::lexical_cast<unsigned int>(person.get<string>("id"));
155  const auto age = boost::lexical_cast<unsigned int>(person.get<string>("age"));
156  const auto hhId = boost::lexical_cast<unsigned int>(person.get<string>("Household"));
157  const auto ksId = boost::lexical_cast<unsigned int>(person.get<string>("K12School"));
158  const auto coId = boost::lexical_cast<unsigned int>(person.get<string>("College"));
159  const auto wpId = boost::lexical_cast<unsigned int>(person.get<string>("Workplace"));
160  const auto pcId = boost::lexical_cast<unsigned int>(person.get<string>("PrimaryCommunity"));
161  const auto scId = boost::lexical_cast<unsigned int>(person.get<string>("SecondaryCommunity"));
162 
163  return m_population->CreatePerson(id, age, hhId, ksId, coId, wpId, pcId, scId);
164 }
165 
166 } // namespace geopop
void Read() override
Actually perform the read and return the GeoGrid.
std::shared_ptr< ContactCenter > ParseContactCenter(boost::property_tree::ptree &contactCenter)
Create a ContactCenter based on the information stored in the provided boost property tree...
Id
Enumerates the ContactPool types.
Definition: ContactType.h:34
void AddCommutes(GeoGrid &geoGrid)
Add the commutes that were found to their respective Locations symmetrically.
A group of Persons that potentially have contacts with one another.
Definition: ContactPool.h:38
Utilities for the project.
string ToString(Id l)
Converts a LogMode value to corresponding name.
stride::Population * m_population
Population to use in the GeoGrid may be nullptr.
Definition: GeoGridReader.h:67
geopop::GeoGrid & RefGeoGrid()
Reference the GeoGrid associated with this population (may be a nullptr).
Definition: Population.h:83
STL namespace.
Basic exception class: needed to prevent clang-tidy warning "thrown exception type is not nothrow cop...
Definition: Exception.h:28
ContactPoolSys & RefPoolSys()
Reference the ContactPoolSys of the Population.
Definition: Population.h:80
Key Data structure: container for (a) all individuals in the population (b) the ContactPoolSys wchich...
Definition: Population.h:47
Coordinate ParseCoordinate(boost::property_tree::ptree &coordinate)
Create a Coordinate based on the information stored in the provided boost property tree...
Namespace for the geographic and demograhic classes.
Definition: Coordinate.h:21
std::vector< std::tuple< unsigned int, unsigned int, double > > m_commutes
Definition: GeoGridReader.h:64
Person * CreatePerson(unsigned int id, double age, unsigned int householdId, unsigned int k12SchoolId, unsigned int collegeId, unsigned int workId, unsigned int primaryCommunityId, unsigned int secondaryCommunityId)
Create Person in the population.
Definition: Population.cpp:108
std::unique_ptr< std::istream > m_inputStream
File to read.
Definition: GeoGridReader.h:66
An abstract base class for creating a GeoGrid that was read from a file, can be implemented using mul...
Definition: GeoGridReader.h:37
boost::geometry::model::point< double, 2, boost::geometry::cs::geographic< boost::geometry::degree >> Coordinate
Definition: Coordinate.h:23
Header file for the core Population class.
GeoGridJSONReader(std::unique_ptr< std::istream > inputStream, stride::Population *pop)
Construct the GeoGridJSONReader with the istream which contains the JSON.
std::map< unsigned int, stride::Person * > m_people
< Store the persons (id->person) that were found while loping over the ContactPools.
Definition: GeoGridReader.h:61
ContactPool * CreateContactPool(ContactType::Id typeId)
Create a new contact pool of a given type.
std::shared_ptr< Location > ParseLocation(boost::property_tree::ptree &location)
Create a Location based on the information stored in the provided boost property tree.
Store and handle person data.
Definition: Person.h:34
Namespace for the simulator and related classes.
Definition: Calendar.cpp:28
stride::Person * ParsePerson(boost::property_tree::ptree &person)
Create a Person based on the information stored in the provided boost property tree.
stride::ContactPool * ParseContactPool(boost::property_tree::ptree &contactPool, stride::ContactType::Id typeId)
Create a ContactCenter based on the information stored in the provided boost property tree...
Namespace to manage types of ContactPool.
Definition: ContactType.cpp:28