CYCAMORE
src/separations.cc
Go to the documentation of this file.
1 #include "separations.h"
2 
3 using cyclus::Material;
4 using cyclus::Composition;
5 using cyclus::toolkit::ResBuf;
6 using cyclus::toolkit::MatVec;
7 using cyclus::KeyError;
8 using cyclus::ValueError;
9 using cyclus::Request;
10 using cyclus::CompMap;
11 
12 namespace cycamore {
13 
14 Separations::Separations(cyclus::Context* ctx)
15  : cyclus::Facility(ctx),
16  latitude(0.0),
17  longitude(0.0),
19 
20 cyclus::Inventories Separations::SnapshotInv() {
21  cyclus::Inventories invs;
22 
23  // these inventory names are intentionally convoluted so as to not clash
24  // with the user-specified stream commods that are used as the separations
25  // streams inventory names.
26  invs["leftover-inv-name"] = leftover.PopNRes(leftover.count());
27  leftover.Push(invs["leftover-inv-name"]);
28  invs["feed-inv-name"] = feed.PopNRes(feed.count());
29  feed.Push(invs["feed-inv-name"]);
30 
31  std::map<std::string, ResBuf<Material> >::iterator it;
32  for (it = streambufs.begin(); it != streambufs.end(); ++it) {
33  invs[it->first] = it->second.PopNRes(it->second.count());
34  it->second.Push(invs[it->first]);
35  }
36 
37  return invs;
38 }
39 
40 void Separations::InitInv(cyclus::Inventories& inv) {
41  leftover.Push(inv["leftover-inv-name"]);
42  feed.Push(inv["feed-inv-name"]);
43 
44  cyclus::Inventories::iterator it;
45  for (it = inv.begin(); it != inv.end(); ++it) {
46  streambufs[it->first].Push(it->second);
47  }
48 }
49 
50 typedef std::pair<double, std::map<int, double> > Stream;
51 typedef std::map<std::string, Stream> StreamSet;
52 
54  cyclus::Facility::EnterNotify();
55  std::map<int, double> efficiency_;
56 
57  StreamSet::iterator it;
58  std::map<int, double>::iterator it2;
59 
60  for (it = streams_.begin(); it != streams_.end(); ++it) {
61  std::string name = it->first;
62  Stream stream = it->second;
63  double cap = stream.first;
64  if (cap >= 0) {
65  streambufs[name].capacity(cap);
66  }
67 
68  for (it2 = stream.second.begin(); it2 != stream.second.end(); it2++) {
69  efficiency_[it2->first] += it2->second;
70  }
72  }
73 
74  std::vector<int> eff_pb_;
75  for (it2 = efficiency_.begin(); it2 != efficiency_.end(); it2++) {
76  if (it2->second > 1) {
77  eff_pb_.push_back(it2->first);
78  }
79  }
80 
81  if (eff_pb_.size() > 0) {
82  std::stringstream ss;
83  ss << "In " << prototype() << ", ";
84  ss << "the following nuclide(s) have a cumulative separation efficiency "
85  "greater than 1:";
86  for (int i = 0; i < eff_pb_.size(); i++) {
87  ss << "\n " << eff_pb_[i];
88  if (i < eff_pb_.size() - 1) {
89  ss << ",";
90  } else {
91  ss << ".";
92  }
93  }
94 
95  throw cyclus::ValueError(ss.str());
96  }
97 
98  if (feed_commod_prefs.size() == 0) {
99  for (int i = 0; i < feed_commods.size(); i++) {
100  feed_commod_prefs.push_back(cyclus::kDefaultPref);
101  }
102  }
103 }
104 
105 void Separations::Tick() {
106  using cyclus::toolkit::RecordTimeSeries;
107  if (feed.count() == 0) {
108  return;
109  }
110  double pop_qty = std::min(throughput, feed.quantity());
111  Material::Ptr mat = feed.Pop(pop_qty, cyclus::eps_rsrc());
112  double orig_qty = mat->quantity();
113 
114  StreamSet::iterator it;
115  double maxfrac = 1;
116  std::map<std::string, Material::Ptr> stagedsep;
117  Record("Separating", orig_qty, "feed");
118  for (it = streams_.begin(); it != streams_.end(); ++it) {
119  Stream info = it->second;
120  std::string name = it->first;
121  stagedsep[name] = SepMaterial(info.second, mat);
122  double frac = streambufs[name].space() / stagedsep[name]->quantity();
123  if (frac < maxfrac) {
124  maxfrac = frac;
125  }
126  }
127 
128  std::map<std::string, Material::Ptr>::iterator itf;
129  for (itf = stagedsep.begin(); itf != stagedsep.end(); ++itf) {
130  std::string name = itf->first;
131  Material::Ptr m = itf->second;
132  if (m->quantity() > 0) {
133  double qty = m->quantity();
134  if (m->quantity() > mat->quantity()) {
135  qty = mat->quantity();
136  }
137  streambufs[name].Push(
138  mat->ExtractComp(qty * maxfrac, m->comp()));
139  Record("Separated", qty * maxfrac, name);
140  }
141  cyclus::toolkit::RecordTimeSeries<double>("supply"+name, this,
142  streambufs[name].quantity());
143  }
144 
145  if (maxfrac == 1) {
146  if (mat->quantity() > 0) {
147  // unspecified separations fractions go to leftovers
148  leftover.Push(mat);
149  }
150  } else { // maxfrac is < 1
151  // push back any leftover feed due to separated stream inv size constraints
152 
153  feed.Push(mat->ExtractQty((1 - maxfrac) * orig_qty));
154  if (mat->quantity() > 0) {
155  // unspecified separations fractions go to leftovers
156  leftover.Push(mat);
157  }
158  }
159  cyclus::toolkit::RecordTimeSeries<double>("supply"+leftover_commod, this,
160  leftover.quantity());
161 
162 }
163 
164 // Note that this returns an untracked material that should just be used for
165 // its composition and qty - not in any real inventories, etc.
166 Material::Ptr SepMaterial(std::map<int, double> effs, Material::Ptr mat) {
167  CompMap cm = mat->comp()->mass();
168  cyclus::compmath::Normalize(&cm, mat->quantity());
169  double tot_qty = 0;
170  CompMap sepcomp;
171 
172  CompMap::iterator it;
173  for (it = cm.begin(); it != cm.end(); ++it) {
174  int nuc = it->first;
175  int elem = (nuc / 10000000) * 10000000;
176  double eff = 0;
177  if (effs.count(nuc) > 0) {
178  eff = effs[nuc];
179  } else if (effs.count(elem) > 0) {
180  eff = effs[elem];
181  } else {
182  continue;
183  }
184 
185  double qty = it->second;
186  double sepqty = qty * eff;
187  sepcomp[nuc] = sepqty;
188  tot_qty += sepqty;
189  }
190 
191  Composition::Ptr c = Composition::CreateFromMass(sepcomp);
192  return Material::CreateUntracked(tot_qty, c);
193 };
194 
195 std::set<cyclus::RequestPortfolio<Material>::Ptr>
197  using cyclus::RequestPortfolio;
198  using cyclus::toolkit::RecordTimeSeries;
199  std::set<RequestPortfolio<Material>::Ptr> ports;
200 
201  int t = context()->time();
202  int t_exit = exit_time();
203 
204  // record demand of highest-preferred commodity
205  std::vector<double>::iterator result;
206  result = std::max_element(feed_commod_prefs.begin(), feed_commod_prefs.end());
207  int maxindx = std::distance(feed_commod_prefs.begin(), result);
208  cyclus::toolkit::RecordTimeSeries<double>("demand"+feed_commods[maxindx],
209  this, feed.space());
210  if (t_exit >= 0 && (feed.quantity() >= (t_exit - t) * throughput)) {
211  return ports; // already have enough feed for remainder of life
212  } else if (feed.space() < cyclus::eps_rsrc()) {
213  return ports;
214  }
215 
216  bool exclusive = false;
217  RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
218 
219  Material::Ptr m = cyclus::NewBlankMaterial(feed.space());
220  if (!feed_recipe.empty()) {
221  Composition::Ptr c = context()->GetRecipe(feed_recipe);
222  m = Material::CreateUntracked(feed.space(), c);
223  }
224 
225  std::vector<cyclus::Request<Material>*> reqs;
226  for (int i = 0; i < feed_commods.size(); i++) {
227  std::string commod = feed_commods[i];
228  double pref = feed_commod_prefs[i];
229  reqs.push_back(port->AddRequest(m, this, commod, pref, exclusive));
230  }
231  port->AddMutualReqs(reqs);
232  ports.insert(port);
233 
234  return ports;
235 }
236 
238  const std::vector<cyclus::Trade<Material> >& trades,
239  std::vector<std::pair<cyclus::Trade<Material>, Material::Ptr> >&
240  responses) {
241  using cyclus::Trade;
242 
243  std::vector<cyclus::Trade<cyclus::Material> >::const_iterator it;
244  for (int i = 0; i < trades.size(); i++) {
245  std::string commod = trades[i].request->commodity();
246  if (commod == leftover_commod) {
247  double amt = std::min(leftover.quantity(), trades[i].amt);
248  Material::Ptr m = leftover.Pop(amt, cyclus::eps_rsrc());
249  responses.push_back(std::make_pair(trades[i], m));
250  } else if (streambufs.count(commod) > 0) {
251  double amt = std::min(streambufs[commod].quantity(), trades[i].amt);
252  Material::Ptr m = streambufs[commod].Pop(amt, cyclus::eps_rsrc());
253  responses.push_back(std::make_pair(trades[i], m));
254  } else {
255  throw ValueError("invalid commodity " + commod +
256  " on trade matched to prototype " + prototype());
257  }
258  }
259 }
260 
262  const std::vector<std::pair<cyclus::Trade<Material>, Material::Ptr> >&
263  responses) {
264  std::vector<std::pair<cyclus::Trade<cyclus::Material>,
265  cyclus::Material::Ptr> >::const_iterator trade;
266 
267  for (trade = responses.begin(); trade != responses.end(); ++trade) {
268  feed.Push(trade->second);
269  }
270 }
271 
272 std::set<cyclus::BidPortfolio<Material>::Ptr> Separations::GetMatlBids(
273  cyclus::CommodMap<Material>::type& commod_requests) {
274  using cyclus::BidPortfolio;
275  bool exclusive = false;
276  std::set<BidPortfolio<Material>::Ptr> ports;
277 
278  // bid streams
279  std::map<std::string, ResBuf<Material> >::iterator it;
280  for (it = streambufs.begin(); it != streambufs.end(); ++it) {
281  std::string commod = it->first;
282  std::vector<Request<Material>*>& reqs = commod_requests[commod];
283  if (reqs.size() == 0) {
284  continue;
285  } else if (streambufs[commod].quantity() < cyclus::eps_rsrc()) {
286  continue;
287  }
288 
289  MatVec mats = streambufs[commod].PopN(streambufs[commod].count());
290  streambufs[commod].Push(mats);
291 
292  BidPortfolio<Material>::Ptr port(new BidPortfolio<Material>());
293 
294  for (int j = 0; j < reqs.size(); j++) {
295  Request<Material>* req = reqs[j];
296  double tot_bid = 0;
297  for (int k = 0; k < mats.size(); k++) {
298  Material::Ptr m = mats[k];
299  tot_bid += m->quantity();
300 
301  // this fix the problem of the cyclus exchange manager which crashes
302  // when a bid with a quantity <=0 is offered.
303  if (m->quantity() > cyclus::eps_rsrc()) {
304  port->AddBid(req, m, this, exclusive);
305  }
306 
307  if (tot_bid >= req->target()->quantity()) {
308  break;
309  }
310  }
311  }
312 
313  double tot_qty = streambufs[commod].quantity();
314  cyclus::CapacityConstraint<Material> cc(tot_qty);
315  port->AddConstraint(cc);
316  ports.insert(port);
317  }
318 
319  // bid leftovers
320  std::vector<Request<Material>*>& reqs = commod_requests[leftover_commod];
321  if (reqs.size() > 0 && leftover.quantity() >= cyclus::eps_rsrc()) {
322  MatVec mats = leftover.PopN(leftover.count());
323  leftover.Push(mats);
324 
325  BidPortfolio<Material>::Ptr port(new BidPortfolio<Material>());
326 
327  for (int j = 0; j < reqs.size(); j++) {
328  Request<Material>* req = reqs[j];
329  double tot_bid = 0;
330  for (int k = 0; k < mats.size(); k++) {
331  Material::Ptr m = mats[k];
332  tot_bid += m->quantity();
333 
334  // this fix the problem of the cyclus exchange manager which crashes
335  // when a bid with a quantity <=0 is offered.
336  if (m->quantity() > cyclus::eps_rsrc()) {
337  port->AddBid(req, m, this, exclusive);
338  }
339 
340  if (tot_bid >= req->target()->quantity()) {
341  break;
342  }
343  }
344  }
345 
346  cyclus::CapacityConstraint<Material> cc(leftover.quantity());
347  port->AddConstraint(cc);
348  ports.insert(port);
349  }
350 
351  return ports;
352 }
353 
354 void Separations::Tock() {}
355 
357  if (leftover.count() > 0) {
358  return false;
359  }
360 
361  std::map<std::string, ResBuf<Material> >::iterator it;
362  for (it = streambufs.begin(); it != streambufs.end(); ++it) {
363  if (it->second.count() > 0) {
364  return false;
365  }
366  }
367 
368  return true;
369 }
370 
372  std::string specification = this->spec();
373  context()
374  ->NewDatum("AgentPosition")
375  ->AddVal("Spec", specification)
376  ->AddVal("Prototype", this->prototype())
377  ->AddVal("AgentId", id())
378  ->AddVal("Latitude", latitude)
379  ->AddVal("Longitude", longitude)
380  ->Record();
381 }
382 
383 void Separations::Record(std::string name, double val, std::string type) {
384  context()
385  ->NewDatum("SeparationEvents")
386  ->AddVal("AgentId", id())
387  ->AddVal("Time", context()->time())
388  ->AddVal("Event", name)
389  ->AddVal("Value", val)
390  ->AddVal("Type", type)
391  ->Record();
392 }
393 
394 extern "C" cyclus::Agent* ConstructSeparations(cyclus::Context* ctx) {
395  return new Separations(ctx);
396 }
397 
398 } // namespace cycamore
cyclus::toolkit::ResBuf< cyclus::Material > leftover
virtual cyclus::Inventories SnapshotInv()
void Record(std::string name, double val, std::string type)
void RecordPosition()
Records an agent&#39;s latitude and longitude to the output db.
double longitude
cyclus::Agent * ConstructSeparations(cyclus::Context *ctx)
std::map< std::string, cyclus::toolkit::ResBuf< cyclus::Material > > streambufs
cycamore::GrowthRegion string
virtual void AcceptMatlTrades(const std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
virtual std::set< cyclus::RequestPortfolio< cyclus::Material >::Ptr > GetMatlRequests()
std::map< std::string, std::pair< double, std::map< int, double > > > streams_
virtual std::set< cyclus::BidPortfolio< cyclus::Material >::Ptr > GetMatlBids(cyclus::CommodMap< cyclus::Material >::type &commod_requests)
cyclus::toolkit::ResBuf< cyclus::Material > feed
virtual void InitInv(cyclus::Inventories &inv)
cyclus::toolkit::Position coordinates
std::pair< double, std::map< int, double > > Stream
std::vector< std::string > feed_commods
virtual void GetMatlTrades(const std::vector< cyclus::Trade< cyclus::Material > > &trades, std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
Material::Ptr SepMaterial(std::map< int, double > effs, Material::Ptr mat)
std::map< std::string, Stream > StreamSet