CYCLUS
res_buf.h
Go to the documentation of this file.
1 #ifndef CYCLUS_SRC_TOOLKIT_RES_BUF_H_
2 #define CYCLUS_SRC_TOOLKIT_RES_BUF_H_
3 
4 #include <iomanip>
5 #include <limits>
6 #include <list>
7 #include <set>
8 #include <vector>
9 
10 #include "cyc_arithmetic.h"
11 #include "cyc_limits.h"
12 #include "error.h"
13 #include "product.h"
14 #include "material.h"
15 #include "resource.h"
16 #include "res_manip.h"
17 
18 namespace cyclus {
19 namespace toolkit {
20 
21 typedef std::vector<Resource::Ptr> ResVec;
22 typedef std::vector<Material::Ptr> MatVec;
23 typedef std::vector<Product::Ptr> ProdVec;
24 
25 /// ResBuf is a helper class that provides semi-automated management of
26 /// a collection of resources (e.g. agent stocks and inventories).
27 /// Constructed buffers have infinite capacity unless explicitly changed.
28 /// Resource popping occurs in the order the resources were pushed (i.e. oldest
29 /// resources are popped first), unless explicitly specified otherwise.
30 ///
31 /// Typically, a ResBuf will be a member variable on an agent/archetype class.
32 /// Resources can be added and retrieved from it as needed, and the buffer can
33 /// be queried in various ways as done in the example below:
34 ///
35 /// @code
36 /// class MyAgent : public cyclus::Facility {
37 /// public:
38 /// Tick() {
39 /// double batch_size = 2703;
40 /// if (outventory_.space() < batch_size) {
41 /// return;
42 /// } else if (inventory_.quantity() < batch_size) {
43 /// return;
44 /// }
45 ///
46 /// outventory_.Push(inventory_.Pop(batch_size));
47 /// }
48 ///
49 /// ... // resource exchange to fill up inventory_ buffer
50 ///
51 /// private:
52 /// ...
53 /// cyclus::toolkit::ResBuf<cyclus::Material> inventory_;
54 /// cyclus::toolkit::ResBuf<cyclus::Material> outventory_;
55 /// };
56 /// @endcode
57 ///
58 /// In this example, if there is sufficient material in inventory_, 2703 kg is
59 /// removed as a single object that is then placed in another buffer
60 /// (outventory_) each time step.
61 template <class T>
62 class ResBuf {
63  public:
64  ResBuf() : cap_(INFINITY), qty_(0) { }
65 
66  virtual ~ResBuf() {}
67 
68  /// Returns the maximum resource quantity this buffer can hold (units
69  /// based on constituent resource objects' units).
70  /// Never throws.
71  inline double capacity() const { return cap_; }
72 
73  /// Sets the maximum quantity this buffer can hold (units based
74  /// on constituent resource objects' units).
75  ///
76  /// @throws ValueError the new capacity is lower (by eps_rsrc()) than the
77  /// quantity of resources that exist in the buffer.
78  void capacity(double cap) {
79  if (quantity() - cap > eps_rsrc()) {
80  std::stringstream ss;
81  ss << std::setprecision(17) << "new capacity " << cap
82  << " lower than existing quantity " << quantity();
83  throw ValueError(ss.str());
84  }
85  cap_ = cap;
86  }
87 
88  /// Returns the total number of constituent resource objects
89  /// in the buffer. Never throws.
90  inline int count() const { return rs_.size(); }
91 
92  /// Returns the total resource quantity of constituent resource
93  /// objects in the buffer. Never throws.
94  inline double quantity() const { return qty_; }
95 
96  /// Returns the quantity of space remaining in this buffer.
97  /// This is effectively the difference between the capacity and the quantity
98  /// and is never negative. Never throws.
99  inline double space() const { return std::max(0.0, cap_ - qty_); }
100 
101  /// Returns true if there are no resources in the buffer.
102  inline bool empty() const { return rs_.empty(); }
103 
104  /// Pops and returns the specified quantity from the buffer as a single
105  /// resource object.
106  /// Resources are split if necessary in order to pop the exact quantity
107  /// requested (within eps_rsrc()). Resources are retrieved in the order they
108  /// were pushed (i.e. oldest first) and are squashed into a single object
109  /// when returned.
110  ///
111  /// @throws ValueError the specified pop quantity is larger than the
112  /// buffer's current inventory.
113  typename T::Ptr Pop(double qty) {
114  if (qty > this->quantity()) {
115  std::stringstream ss;
116  ss << std::setprecision(17) << "removal quantity " << qty
117  << " larger than buff quantity " << this->quantity();
118  throw ValueError(ss.str());
119  }
120 
121  std::vector<typename T::Ptr> rs;
122  typename T::Ptr r;
123  typename T::Ptr tmp;
124  double left = qty;
125  double quan;
126  while (left > 0 && count() > 0) {
127  r = rs_.front();
128  rs_.pop_front();
129  quan = r->quantity();
130  if (quan > left) {
131  // too big - split the res before popping
132  tmp = boost::dynamic_pointer_cast<T>(r->ExtractRes(left));
133  rs_.push_front(r);
134  r = tmp;
135  } else {
136  rs_present_.erase(r);
137  }
138 
139  qty_ -= r->quantity();
140  rs.push_back(r);
141  left -= quan;
142  }
143 
144  UpdateQty();
145 
146  return Squash(rs);
147  }
148 
149  /// Same behavior as Pop(double) except a non-zero eps may be specified. eps
150  /// is used only in cases where qty might be slightly larger than the
151  /// buffer's current inventory quantity.
152  typename T::Ptr Pop(double qty, double eps) {
153  if (qty > this->quantity() + eps) {
154  std::stringstream ss;
155  ss << std::setprecision(17) << "removal quantity " << qty
156  << " larger than buff quantity " << this->quantity();
157  throw ValueError(ss.str());
158  }
159 
160  if (qty >= this->quantity()) {
161  return Squash(PopN(count()));
162  }
163  return Pop(qty);
164  }
165 
166  /// Pops the specified number of resource objects from the buffer.
167  /// Resources are not split and are retrieved in the order they were
168  /// pushed (i.e. oldest first).
169  ///
170  /// @throws ValueError the specified n is larger than the
171  /// buffer's current resource count or the specified number is negative.
172  std::vector<typename T::Ptr> PopN(int n) {
173  if (count() < n || n < 0) {
174  std::stringstream ss;
175  ss << "remove count " << n << " larger than buff count " << count();
176  throw ValueError(ss.str());
177  }
178 
179  std::vector<typename T::Ptr> rs;
180  for (int i = 0; i < n; i++) {
181  typename T::Ptr r = rs_.front();
182  qty_ -= r->quantity();
183  rs_.pop_front();
184  rs.push_back(r);
185  rs_present_.erase(r);
186  }
187 
188  UpdateQty();
189  return rs;
190  }
191 
192  /// Same as PopN except returns the Resource-typed objects.
193  ResVec PopNRes(int n) { return ResCast(PopN(n)); }
194 
195  /// Returns the next resource in line to be popped from the buffer
196  /// without actually removing it from the buffer.
197  typename T::Ptr Peek() {
198  if (rs_.size() < 1) {
199  throw ValueError("cannot peek at resource from an empty buff");
200  }
201  return rs_.front();
202  }
203 
204  /// Pops one resource object from the buffer.
205  /// Resources are not split and are retrieved in the order
206  /// they were pushed (i.e. oldest first).
207  ///
208  /// @throws ValueError the buffer is empty.
209  typename T::Ptr Pop() {
210  if (rs_.size() < 1) {
211  throw ValueError("cannot pop resource from an empty buff");
212  }
213 
214  typename T::Ptr r = rs_.front();
215  rs_.pop_front();
216  rs_present_.erase(r);
217  qty_ -= r->quantity();
218  UpdateQty();
219  return r;
220  }
221 
222  /// Same as Pop, except it returns the most recently added resource.
223  typename T::Ptr PopBack() {
224  if (rs_.size() < 1) {
225  throw ValueError("cannot pop resource from an empty buff");
226  }
227 
228  typename T::Ptr r = rs_.back();
229  rs_.pop_back();
230  rs_present_.erase(r);
231  qty_ -= r->quantity();
232  UpdateQty();
233  return r;
234  }
235 
236  /// Pushes a single resource object to the buffer.
237  /// Resource objects are never combined in the buffer; they are stored as
238  /// unique objects. The resource object is only pushed to the buffer if it
239  /// does not cause the buffer to exceed its capacity.
240  ///
241  /// @throws ValueError the pushing of the given resource object would
242  /// cause the buffer to exceed its capacity.
243  ///
244  /// @throws KeyError the resource object to be pushed is already present
245  /// in the buffer.
246  void Push(Resource::Ptr r) {
247  typename T::Ptr m = boost::dynamic_pointer_cast<T>(r);
248  if (m == NULL) {
249  throw CastError("pushing wrong type of resource onto ResBuf");
250  } else if (r->quantity() - space() > eps_rsrc()) {
251  std::stringstream ss;
252  ss << "resource pushing breaks capacity limit: space=" << space()
253  << ", rsrc->quantity()=" << r->quantity();
254  throw ValueError(ss.str());
255  } else if (rs_present_.count(m) == 1) {
256  throw KeyError("duplicate resource push attempted");
257  }
258 
259  rs_.push_back(m);
260  rs_present_.insert(m);
261  qty_ += r->quantity();
262  UpdateQty();
263  }
264 
265  /// Pushes one or more resource objects (as a std::vector) to the buffer.
266  /// Resource objects are never squashed in the buffer; they are stored as
267  /// unique objects. The resource objects are only pushed to the buffer if
268  /// they do not cause the buffer to exceed its capacity; otherwise none of the
269  /// given resource objects are added to the buffer.
270  ///
271  /// @throws ValueError adding the given resource objects would
272  /// cause the buffer to exceed its capacity.
273  ///
274  /// @throws KeyError one or more of the resource objects to be added
275  /// are already present in the buffer.
276  template <class B>
277  void Push(std::vector<B> rs) {
278  std::vector<typename T::Ptr> rss;
279  typename T::Ptr r;
280  for (int i = 0; i < rs.size(); i++) {
281  r = boost::dynamic_pointer_cast<T>(rs[i]);
282  if (r == NULL) {
283  throw CastError("pushing wrong type of resource onto ResBuf");
284  }
285  rss.push_back(r);
286  }
287 
288  double tot_qty = 0;
289  for (int i = 0; i < rss.size(); i++) {
290  tot_qty += rss.at(i)->quantity();
291  }
292  if (tot_qty - space() > eps_rsrc()) {
293  throw ValueError("Resource pushing breaks capacity limit.");
294  }
295 
296  for (int i = 0; i < rss.size(); i++) {
297  if (rs_present_.count(rss.at(i)) == 1) {
298  throw KeyError("Duplicate resource pushing attempted");
299  }
300  }
301 
302  for (int i = 0; i < rss.size(); i++) {
303  rs_.push_back(rss[i]);
304  rs_present_.insert(rss[i]);
305  }
306  qty_ += tot_qty;
307  }
308 
309  private:
310  void UpdateQty() {
311  int n = rs_.size();
312  if (n == 0) {
313  qty_ = 0;
314  } else if (n == 1) {
315  qty_ = rs_.front()->quantity();
316  }
317  }
318 
319  double qty_;
320 
321  /// Maximum quantity of resources this buffer can hold
322  double cap_;
323 
324  /// List of constituent resource objects forming the buffer's inventory
325  std::list<typename T::Ptr> rs_;
326  std::set<typename T::Ptr> rs_present_;
327 };
328 
329 } // namespace toolkit
330 } // namespace cyclus
331 
332 #endif // CYCLUS_SRC_TOOLKIT_RES_BUF_H_
void capacity(double cap)
Sets the maximum quantity this buffer can hold (units based on constituent resource objects&#39; units)...
Definition: res_buf.h:78
std::vector< Product::Ptr > ProdVec
Definition: res_buf.h:23
bool empty() const
Returns true if there are no resources in the buffer.
Definition: res_buf.h:102
For values that are too big, too small, etc.
Definition: error.h:41
Product::Ptr Squash(std::vector< Product::Ptr > ps)
Squash combines all products in ps and returns the resulting single product.
Definition: res_manip.cc:7
T::Ptr Pop(double qty)
Pops and returns the specified quantity from the buffer as a single resource object.
Definition: res_buf.h:113
double quantity() const
Returns the total resource quantity of constituent resource objects in the buffer.
Definition: res_buf.h:94
double capacity() const
Returns the maximum resource quantity this buffer can hold (units based on constituent resource objec...
Definition: res_buf.h:71
T::Ptr PopBack()
Same as Pop, except it returns the most recently added resource.
Definition: res_buf.h:223
For failed casts that shouldn&#39;t.
Definition: error.h:65
ResVec PopNRes(int n)
Same as PopN except returns the Resource-typed objects.
Definition: res_buf.h:193
double space() const
Returns the quantity of space remaining in this buffer.
Definition: res_buf.h:99
double eps_rsrc()
an epsilon value to be used by resources
Definition: cyc_limits.h:19
std::vector< typename T::Ptr > PopN(int n)
Pops the specified number of resource objects from the buffer.
Definition: res_buf.h:172
T::Ptr Peek()
Returns the next resource in line to be popped from the buffer without actually removing it from the ...
Definition: res_buf.h:197
void Push(std::vector< B > rs)
Pushes one or more resource objects (as a std::vector) to the buffer.
Definition: res_buf.h:277
boost::shared_ptr< Resource > Ptr
Definition: resource.h:24
taken directly from OsiSolverInterface.cpp on 2/17/14 from https://projects.coin-or.org/Osi/browser/trunk.
Definition: agent.cc:14
T::Ptr Pop(double qty, double eps)
Same behavior as Pop(double) except a non-zero eps may be specified.
Definition: res_buf.h:152
Declares the CycArithmetic class, which holds arithmetic algorithms.
void Push(Resource::Ptr r)
Pushes a single resource object to the buffer.
Definition: res_buf.h:246
std::vector< Resource::Ptr > ResVec
Definition: res_buf.h:21
ResBuf is a helper class that provides semi-automated management of a collection of resources (e...
Definition: res_buf.h:62
std::vector< Resource::Ptr > ResCast(std::vector< Material::Ptr > rs)
Casts a vector of Materials into a vector of Resources.
Definition: res_manip.cc:48
int count() const
Returns the total number of constituent resource objects in the buffer.
Definition: res_buf.h:90
std::vector< Material::Ptr > MatVec
Definition: res_buf.h:22
For failed retrieval/insertion of key-based data into/from data structures.
Definition: error.h:47
T::Ptr Pop()
Pops one resource object from the buffer.
Definition: res_buf.h:209
double eps()
a generic epsilon value
Definition: cyc_limits.h:12