CYCLUS
Loading...
Searching...
No Matches
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
18namespace cyclus {
19namespace toolkit {
20
21typedef std::vector<Resource::Ptr> ResVec;
22typedef std::vector<Material::Ptr> MatVec;
23typedef 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.
61template <class T>
62class ResBuf {
63 public:
64 ResBuf(bool is_bulk=false, bool keep_pkg=false) : qty_(0), is_bulk_(is_bulk) {
67 }
68
69 virtual ~ResBuf() {}
70
71 /// Returns the maximum resource quantity this buffer can hold (units
72 /// based on constituent resource objects' units).
73 /// Never throws.
74 inline double capacity() const { return cap_; }
75
76 /// Sets the maximum quantity this buffer can hold (units based
77 /// on constituent resource objects' units).
78 ///
79 /// @throws ValueError the new capacity is lower (by eps_rsrc()) than the
80 /// quantity of resources that exist in the buffer.
81 void capacity(double cap) {
82 if (cap < 0) {
83 throw ValueError("capacity must not be negative");
84 }
85
86 if (quantity() - cap > eps_rsrc()) {
87 std::stringstream ss;
88 ss << std::setprecision(17) << "new capacity " << cap
89 << " lower than existing quantity " << quantity();
90 throw ValueError(ss.str());
91 }
92 cap_ = cap;
93 }
94
95 /// Sets whether the buffer should keep packaged resources
97 if (is_bulk_ && keep_packaging) {
98 throw ValueError("bulk storage resbufs cannot keep packaging. Only one of the two options can be true.");
99 }
100 keep_packaging_ = keep_packaging;
101 }
102
103 bool keep_packaging() const { return keep_packaging_; }
104
105 /// Returns the total number of constituent resource objects
106 /// in the buffer. Never throws.
107 inline int count() const { return rs_.size(); }
108
109 /// Returns the total resource quantity of constituent resource
110 /// objects in the buffer. Never throws.
111 inline double quantity() const { return qty_; }
112
113 /// Returns the quantity of space remaining in this buffer.
114 /// This is effectively the difference between the capacity and the quantity
115 /// and is never negative. Never throws.
116 inline double space() const { return std::max(0.0, cap_ - qty_); }
117
118 /// Returns true if there are no resources in the buffer.
119 inline bool empty() const { return rs_.empty(); }
120
121 /// Pops and returns the specified quantity from the buffer as a vector of
122 /// resources.
123 /// Resources are split if necessary in order to pop the exact quantity
124 /// requested (within eps_rsrc()). Resources are retrieved in the order they
125 /// were pushed (i.e. oldest first).
126 ///
127 /// @throws ValueError the specified pop quantity is larger than the
128 /// buffer's current inventory.
129 std::vector<typename T::Ptr> PopVector(double qty) {
130 if (qty > this->quantity()) {
131 std::stringstream ss;
132 ss << std::setprecision(17) << "removal quantity " << qty
133 << " larger than buff quantity " << this->quantity();
134 throw ValueError(ss.str());
135 }
136
137 std::vector<typename T::Ptr> rs;
138 typename T::Ptr r;
139 typename T::Ptr tmp;
140 double left = qty;
141 double quan;
142 while (left > 0 && count() > 0) {
143 r = rs_.front();
144 rs_.pop_front();
145 quan = r->quantity();
146 if (quan > left) {
147 // too big - split the res before popping
148 tmp = boost::dynamic_pointer_cast<T>(r->ExtractRes(left));
149 rs_.push_front(r);
150 r = tmp;
151 } else {
152 rs_present_.erase(r);
153 }
154
155 qty_ -= r->quantity();
156 rs.push_back(r);
157 left -= quan;
158 }
159
160 UpdateQty();
161
162 return rs;
163 }
164
165 /// Pops and returns the specified quantity from the buffer as a single
166 /// resource object.
167 /// Resources are split if necessary in order to pop the exact quantity
168 /// requested (within eps_rsrc()). Resources are retrieved in the order they
169 /// were pushed (i.e. oldest first) and are squashed into a single object
170 /// when returned.
171 typename T::Ptr Pop(double qty) {
172 return Squash(PopVector(qty));
173 }
174
175 /// Same behavior as Pop(double) except a non-zero eps may be specified. eps
176 /// is used only in cases where qty might be slightly larger than the
177 /// buffer's current inventory quantity.
178 typename T::Ptr Pop(double qty, double eps) {
179 if (qty > this->quantity() + eps) {
180 std::stringstream ss;
181 ss << std::setprecision(17) << "removal quantity " << qty
182 << " larger than buff quantity " << this->quantity();
183 throw ValueError(ss.str());
184 }
185
186 if (qty >= this->quantity()) {
187 return Squash(PopN(count()));
188 }
189 return Pop(qty);
190 }
191
192 /// Pops the specified number of resource objects from the buffer.
193 /// Resources are not split and are retrieved in the order they were
194 /// pushed (i.e. oldest first).
195 ///
196 /// @throws ValueError the specified n is larger than the
197 /// buffer's current resource count or the specified number is negative.
198 std::vector<typename T::Ptr> PopN(int n) {
199 if (count() < n || n < 0) {
200 std::stringstream ss;
201 ss << "remove count " << n << " larger than buff count " << count();
202 throw ValueError(ss.str());
203 }
204
205 std::vector<typename T::Ptr> rs;
206 for (int i = 0; i < n; i++) {
207 typename T::Ptr r = rs_.front();
208 qty_ -= r->quantity();
209 rs_.pop_front();
210 rs.push_back(r);
211 rs_present_.erase(r);
212 }
213
214 UpdateQty();
215 return rs;
216 }
217
218 /// Same as PopN except returns the Resource-typed objects.
219 ResVec PopNRes(int n) { return ResCast(PopN(n)); }
220
221 /// Returns the next resource in line to be popped from the buffer
222 /// without actually removing it from the buffer.
223 typename T::Ptr Peek() {
224 if (rs_.size() < 1) {
225 throw ValueError("cannot peek at resource from an empty buff");
226 }
227 return rs_.front();
228 }
229
230 /// Pops one resource object from the buffer.
231 /// Resources are not split and are retrieved in the order
232 /// they were pushed (i.e. oldest first).
233 ///
234 /// @throws ValueError the buffer is empty.
235 typename T::Ptr Pop() {
236 if (rs_.size() < 1) {
237 throw ValueError("cannot pop resource from an empty buff");
238 }
239
240 typename T::Ptr r = rs_.front();
241 rs_.pop_front();
242 rs_present_.erase(r);
243 qty_ -= r->quantity();
244 UpdateQty();
245 return r;
246 }
247
248 /// Same as Pop, except it returns the most recently added resource.
249 typename T::Ptr PopBack() {
250 if (rs_.size() < 1) {
251 throw ValueError("cannot pop resource from an empty buff");
252 }
253
254 typename T::Ptr r = rs_.back();
255 rs_.pop_back();
256 rs_present_.erase(r);
257 qty_ -= r->quantity();
258 UpdateQty();
259 return r;
260 }
261
262 /// Pushes a single resource object to the buffer. If not classified as a bulk
263 /// storage buffer, resource objects are not combined in the buffer; they
264 /// are stored as unique objects. The resource object is only pushed to the
265 /// buffer if it does not cause the buffer to exceed its capacity.
266 ///
267 /// @throws ValueError the pushing of the given resource object would cause
268 /// the buffer to exceed its capacity.
269 ///
270 /// @throws KeyError the resource object to be pushed is already present
271 /// in the buffer.
273 typename T::Ptr m = boost::dynamic_pointer_cast<T>(r);
274 if (m == NULL) {
275 throw CastError("pushing wrong type of resource onto ResBuf");
276 } else if (r->quantity() - space() > eps_rsrc()) {
277 std::stringstream ss;
278 ss << "resource pushing breaks capacity limit: space=" << space()
279 << ", rsrc->quantity()=" << r->quantity();
280 throw ValueError(ss.str());
281 } else if (rs_present_.count(m) == 1) {
282 throw KeyError("duplicate resource push attempted");
283 }
284
285 if (!is_bulk_ || rs_.size() == 0) {
286 // strip package id and set as default
287 if (!keep_packaging_) {
288 m->ChangePackage();
289 }
290 rs_.push_back(m);
291 rs_present_.insert(m);
292 } else {
293 rs_.front()->Absorb(m);
294 }
295 qty_ += r->quantity();
296 UpdateQty();
297 }
298
299 /// Pushes one or more resource objects (as a std::vector) to the buffer. If
300 /// not classified as a bulk storage buffer, resource objects are not
301 /// squashed in the buffer; they are stored as unique objects. The resource
302 /// objects are only pushed to the buffer if they do not cause the buffer to
303 /// exceed its capacity; otherwise none of the given resource objects are
304 /// added to the buffer.
305 ///
306 /// @throws ValueError adding the given resource objects would cause the
307 /// buffer to exceed its capacity.
308 ///
309 /// @throws KeyError one or more of the resource objects to be added are
310 /// already present in the buffer.
311 template <class B>
312 void Push(std::vector<B> rs) {
313 std::vector<typename T::Ptr> rss;
314 typename T::Ptr r;
315 for (int i = 0; i < rs.size(); i++) {
316 r = boost::dynamic_pointer_cast<T>(rs[i]);
317 if (r == NULL) {
318 throw CastError("pushing wrong type of resource onto ResBuf");
319 }
320 rss.push_back(r);
321 }
322
323 double tot_qty = 0;
324 for (int i = 0; i < rss.size(); i++) {
325 tot_qty += rss.at(i)->quantity();
326 }
327 if (tot_qty - space() > eps_rsrc()) {
328 throw ValueError("Resource pushing breaks capacity limit.");
329 }
330
331 for (int i = 0; i < rss.size(); i++) {
332 if (rs_present_.count(rss.at(i)) == 1) {
333 throw KeyError("Duplicate resource pushing attempted");
334 }
335 }
336
337 for (int i = 0; i < rss.size(); i++) {
338 if (!is_bulk_ || rs_.size() == 0) {
339 if (!keep_packaging_) {
340 rss[i]->ChangePackage();
341 }
342 rs_.push_back(rss[i]);
343 rs_present_.insert(rss[i]);
344 } else {
345 rs_.front()->Absorb(rss[i]);
346 }
347 }
348 qty_ += tot_qty;
349 }
350
351 /// Decays all the materials in a resource buffer
352 /// @param curr_time time to calculate decay inventory
353 /// (default: -1 uses the current time of the context)
354 void Decay(int curr_time = -1) {
355 for (int i = 0; i < rs_.size(); i++) {
356 rs_.at(i)->Decay(curr_time);
357 }
358 }
359
360 private:
361 void UpdateQty() {
362 int n = rs_.size();
363 if (n == 0) {
364 qty_ = 0;
365 } else if (n == 1) {
366 qty_ = rs_.front()->quantity();
367 }
368 }
369
370 double qty_;
371
372 /// Maximum quantity of resources this buffer can hold
373 double cap_;
374
375 /// Whether materials should be stored as a single squashed item or as individual resource objects
376 bool is_bulk_;
377 /// Whether materials should be stripped of their packaging before being
378 /// pushed onto the resbuf. If res_buf is bulk, this is assumed true.
379 bool keep_packaging_;
380
381 /// List of constituent resource objects forming the buffer's inventory
382 std::list<typename T::Ptr> rs_;
383 std::set<typename T::Ptr> rs_present_;
384};
385
386} // namespace toolkit
387} // namespace cyclus
388
389#endif // CYCLUS_SRC_TOOLKIT_RES_BUF_H_
For failed casts that shouldn't.
Definition error.h:65
For failed retrieval/insertion of key-based data into/from data structures.
Definition error.h:47
boost::shared_ptr< Resource > Ptr
Definition resource.h:27
For values that are too big, too small, etc.
Definition error.h:41
ResBuf is a helper class that provides semi-automated management of a collection of resources (e....
Definition res_buf.h:62
T::Ptr Pop(double qty)
Pops and returns the specified quantity from the buffer as a single resource object.
Definition res_buf.h:171
void Push(Resource::Ptr r)
Pushes a single resource object to the buffer.
Definition res_buf.h:272
double quantity() const
Returns the total resource quantity of constituent resource objects in the buffer.
Definition res_buf.h:111
T::Ptr PopBack()
Same as Pop, except it returns the most recently added resource.
Definition res_buf.h:249
double capacity() const
Returns the maximum resource quantity this buffer can hold (units based on constituent resource objec...
Definition res_buf.h:74
int count() const
Returns the total number of constituent resource objects in the buffer.
Definition res_buf.h:107
ResVec PopNRes(int n)
Same as PopN except returns the Resource-typed objects.
Definition res_buf.h:219
bool empty() const
Returns true if there are no resources in the buffer.
Definition res_buf.h:119
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:223
std::vector< typename T::Ptr > PopVector(double qty)
Pops and returns the specified quantity from the buffer as a vector of resources.
Definition res_buf.h:129
bool keep_packaging() const
Definition res_buf.h:103
T::Ptr Pop()
Pops one resource object from the buffer.
Definition res_buf.h:235
void keep_packaging(bool keep_packaging)
Sets whether the buffer should keep packaged resources.
Definition res_buf.h:96
T::Ptr Pop(double qty, double eps)
Same behavior as Pop(double) except a non-zero eps may be specified.
Definition res_buf.h:178
std::vector< typename T::Ptr > PopN(int n)
Pops the specified number of resource objects from the buffer.
Definition res_buf.h:198
double space() const
Returns the quantity of space remaining in this buffer.
Definition res_buf.h:116
void Push(std::vector< B > rs)
Pushes one or more resource objects (as a std::vector) to the buffer.
Definition res_buf.h:312
void Decay(int curr_time=-1)
Decays all the materials in a resource buffer.
Definition res_buf.h:354
ResBuf(bool is_bulk=false, bool keep_pkg=false)
Definition res_buf.h:64
void capacity(double cap)
Sets the maximum quantity this buffer can hold (units based on constituent resource objects' units).
Definition res_buf.h:81
Declares the CycArithmetic class, which holds arithmetic algorithms.
std::vector< Resource::Ptr > ResVec
Definition res_buf.h:21
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
std::vector< Product::Ptr > ProdVec
Definition res_buf.h:23
std::vector< Resource::Ptr > ResCast(std::vector< Material::Ptr > rs)
Casts a vector of Materials into a vector of Resources.
Definition res_manip.cc:51
std::vector< Material::Ptr > MatVec
Definition res_buf.h:22
taken directly from OsiSolverInterface.cpp on 2/17/14 from https://projects.coin-or....
Definition agent.cc:14
double eps_rsrc()
an epsilon value to be used by resources
Definition cyc_limits.h:19
double eps()
a generic epsilon value
Definition cyc_limits.h:12
T OptionalQuery(InfileTree *tree, std::string query, T default_val)
a query method for optional parameters