Quetzal-CoaTL
The Coalescence Template Library
Loading...
Searching...
No Matches
FlowOnDiskImplementation.hpp
1// Copyright 2021 Arnaud Becheler <abechele@umich.edu>
2
3/*********************************************************************** * This program is free software; you can
4 *redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free
5 *Software Foundation; either version 2 of the License, or * (at your option) any later version. *
6 * *
7 ***************************************************************************/
8
9#ifndef __POPULATION_FLOW_ON_DISK_H_INCLUDED__
10#define __POPULATION_FLOW_ON_DISK_H_INCLUDED__
11
12#include <boost/serialization/serialization.hpp>
13#include <boost/serialization/unordered_map.hpp>
14#include <boost/serialization/utility.hpp>
15
16#include <boost/archive/binary_iarchive.hpp>
17#include <boost/archive/binary_oarchive.hpp>
18
19#include <algorithm>
20#include <cassert>
21#include <functional>
22#include <iostream> // output operator
23#include <unordered_map>
24
25namespace quetzal
26{
27namespace demography
28{
37template <typename Space, typename Time, typename Value> class FlowOnDiskImplementation
38{
39 public:
41 using time_type = Time;
43 using coord_type = Space;
45 using value_type = Value;
47 struct key_type
48 {
50 coord_type from;
52 coord_type to;
54 key_type() = default;
56 key_type(coord_type const &origin, coord_type const &destination) : from(origin), to(destination)
57 {
58 }
60 bool operator==(key_type const &other) const
61 {
62 return (other.from == this->from && other.to == this->to);
63 }
66 template <class Archive> void serialize(Archive &ar, const unsigned int version)
67 {
68 ar &from;
69 ar &to;
70 }
71 };
75 struct key_hash
76 {
77 std::size_t operator()(const key_type &k) const
78 {
79 size_t res = 17;
80 res = res * 31 + std::hash<coord_type>()(k.from);
81 res = res * 31 + std::hash<coord_type>()(k.to);
82 return res;
83 }
84 };
85
86 private:
87 mutable std::pair<Time, Time> m_RAM_window = {0, 1};
89 using forward_flow_type = std::unordered_map<time_type, std::unordered_map<key_type, value_type, key_hash>>;
91 using backward_flow_type =
92 std::unordered_map<time_type, std::unordered_map<coord_type, std::unordered_map<coord_type, value_type>>>;
94 mutable forward_flow_type m_forward_flow;
96 mutable backward_flow_type m_backward_flow;
97
98 public:
106 value_type flow_from_to(coord_type const &from, coord_type const &to, time_type t) const
107 {
108 slide_RAM_window_to(t);
109 assert(m_forward_flow.find(t) != m_forward_flow.end());
110 assert(m_forward_flow.at(t).find(key_type(from, to)) != m_forward_flow.at(t).end());
111 return m_forward_flow.at(t).at(key_type(from, to));
112 }
117 void set_flow_from_to(coord_type const &from, coord_type const &to, time_type t, value_type v)
118 {
119 slide_RAM_window_to(t);
120 m_forward_flow[t][key_type(from, to)] = v;
121 m_backward_flow[t][to][from] = v;
122 }
126 void add_to_flow_from_to(coord_type const &from, coord_type const &to, time_type t, value_type v)
127 {
128 slide_RAM_window_to(t);
129 m_forward_flow[t][key_type(from, to)] += v;
130 m_backward_flow[t][to][from] += v;
131 }
137 std::unordered_map<coord_type, value_type> const &flow_to(coord_type const &x, time_type t) const
138 {
139 slide_RAM_window_to(t);
140 assert(flow_to_is_defined(x, t));
141 return m_backward_flow.at(t).at(x);
142 }
147 bool flow_to_is_defined(coord_type const &to, time_type const &t) const
148 {
149 slide_RAM_window_to(t);
150 auto it1 = m_backward_flow.find(t);
151 if (it1 != m_backward_flow.end())
152 {
153 auto it2 = m_backward_flow.at(t).find(to);
154 return it2 != m_backward_flow.at(t).end();
155 }
156 else
157 {
158 return false;
159 }
160 }
161
162 private:
167 std::string get_forward_flow_archive_name(time_type t) const
168 {
169 const std::string prefix = "M-forward-";
170 const std::string extension = ".archive";
171 return prefix + std::to_string(t) + extension;
172 }
177 std::string get_backward_flow_archive_name(time_type t) const
178 {
179 const std::string prefix = "M-backward-";
180 const std::string extension = ".archive";
181 return prefix + std::to_string(t) + extension;
182 }
186 void serialize_layer(time_type t) const
187 {
188 const std::string forward_filename = get_forward_flow_archive_name(t);
189 const std::string backward_filename = get_backward_flow_archive_name(t);
190 // create and open a binary archive for output
191 std::ofstream forward_ofs(forward_filename, std::ios::binary);
192 std::ofstream backward_ofs(backward_filename, std::ios::binary);
193 // save data to archive
194 boost::archive::binary_oarchive forward_oa(forward_ofs);
195 boost::archive::binary_oarchive backward_oa(backward_ofs);
196 // write class instance to archive
197 forward_oa << m_forward_flow.at(t);
198 backward_oa << m_backward_flow.at(t);
199 // archive and stream closed when destructors are called, clear map
200 m_forward_flow.erase(t);
201 m_backward_flow.erase(t);
202 }
203
204 void deserialize_layer(time_type t) const
205 {
206 const std::string forward_filename = get_forward_flow_archive_name(t);
207 const std::string backward_filename = get_backward_flow_archive_name(t);
208 // create and open an archive for input
209 std::ifstream forward_ifs(forward_filename, std::ios::binary);
210 std::ifstream backward_ifs(backward_filename, std::ios::binary);
211 boost::archive::binary_iarchive forward_ia(forward_ifs);
212 boost::archive::binary_iarchive backward_ia(backward_ifs);
213 // read class state from archive
214 std::unordered_map<key_type, value_type, key_hash> forward_layer;
215 std::unordered_map<coord_type, std::unordered_map<coord_type, value_type>> backward_layer;
216 forward_ia >> forward_layer;
217 backward_ia >> backward_layer;
218 // archive and stream closed when destructors are called
219 m_forward_flow.emplace(t, forward_layer);
220 m_backward_flow.emplace(t, backward_layer);
221 }
222
223 void slide_RAM_window_to(time_type t) const
224 {
225 // window is well positioned
226 if (t == m_RAM_window.first || t == m_RAM_window.second)
227 {
228 // do nothing, just read the data
229 return;
230 }
231 // windows has to go forward
232 else if (t == m_RAM_window.second + 1)
233 {
234 // we know for sure we can serialize this
235 serialize_layer(m_RAM_window.first);
236 // slide the window
237 m_RAM_window.first += 1;
238 m_RAM_window.second += 1;
239 // we don't know if we are in forward history simulation or forward reading
240 try
241 {
242 deserialize_layer(m_RAM_window.second);
243 }
244 catch (const std::exception &e)
245 {
246 // std::cout << "layer did not exist on disk, I assume it's forward simulation time" << std::endl;
247 }
248 }
249 // windows has to go backward
250 else if (t == m_RAM_window.first - 1)
251 {
252 // we know for sure we can serialize this
253 serialize_layer(m_RAM_window.second);
254 // we know for sure we should be able to deserialize this
255 deserialize_layer(m_RAM_window.first - 1);
256 // slide back the window
257 m_RAM_window.first -= 1;
258 m_RAM_window.second -= 1;
259 }
260 // current windows is totally not aligned: assume it's (for now) only random reading access
261 else
262 {
263 // erase both layers from RAM
264 serialize_layer(m_RAM_window.first);
265 serialize_layer(m_RAM_window.second);
266 // slide the windows
267 if (t == 0)
268 {
269 m_RAM_window.first = 0;
270 m_RAM_window.second = 1;
271 }
272 else
273 {
274 m_RAM_window.first = t - 1;
275 m_RAM_window.second = t;
276 }
277
278 // read both layers from disk
279 deserialize_layer(m_RAM_window.first);
280 deserialize_layer(m_RAM_window.second);
281 }
282 }
283};
284} // namespace demography
285} // namespace quetzal
286#endif
Defines a template class to store the demographic flows number across a landscape along time.
Definition FlowOnDiskImplementation.hpp:38
std::unordered_map< coord_type, value_type > const & flow_to(coord_type const &x, time_type t) const
Retrieves the distribution of the value of the flow converging to deme x at time t.
Definition FlowOnDiskImplementation.hpp:137
bool flow_to_is_defined(coord_type const &to, time_type const &t) const
Check if the distribution of the value of the flow converging to deme x at time t is defined.
Definition FlowOnDiskImplementation.hpp:147
void set_flow_from_to(coord_type const &from, coord_type const &to, time_type t, value_type v)
Retrieves value of the flow from deme i to deme j at time t.
Definition FlowOnDiskImplementation.hpp:117
value_type flow_from_to(coord_type const &from, coord_type const &to, time_type t) const
Retrieves value of the flow from deme i to deme j at time t.
Definition FlowOnDiskImplementation.hpp:106
void add_to_flow_from_to(coord_type const &from, coord_type const &to, time_type t, value_type v)
Adds value v to the flow from deme i to deme j at time t.
Definition FlowOnDiskImplementation.hpp:126
FlowOnDiskImplementation()=default
Default constructor.
Simulation of coalescence-based models of molecular evolution.
Definition coalescence.hpp:21
Makes key_type hashable in unordered_map.
Definition FlowOnDiskImplementation.hpp:76
The type of key for nested map member.
Definition FlowOnDiskImplementation.hpp:48
key_type(coord_type const &origin, coord_type const &destination)
Constructor.
Definition FlowOnDiskImplementation.hpp:56
bool operator==(key_type const &other) const
EqualityComparable.
Definition FlowOnDiskImplementation.hpp:60
key_type()=default
Default constructor needed to default construct inner nested map.
friend class boost::serialization::access
Serializable by boost.
Definition FlowOnDiskImplementation.hpp:65
coord_type from
origin of the flow
Definition FlowOnDiskImplementation.hpp:50
coord_type to
destination of the flow
Definition FlowOnDiskImplementation.hpp:52