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