CYCAMORE
src/fuel_fab.cc
Go to the documentation of this file.
1 #include "fuel_fab.h"
2 
3 #include <sstream>
4 
5 using cyclus::Material;
6 using cyclus::Composition;
7 using pyne::simple_xs;
8 
9 #define SHOW(X) \
10  std::cout << std::setprecision(17) << __FILE__ << ":" << __LINE__ \
11  << ": " #X " = " << X << "\n"
12 
13 namespace cycamore {
14 
15 class FissConverter : public cyclus::Converter<cyclus::Material> {
16  public:
17  FissConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss,
18  Composition::Ptr c_topup, std::string spectrum)
19  : c_fiss_(c_fiss), c_topup_(c_topup), c_fill_(c_fill), spec_(spectrum) {
20  w_fiss_ = CosiWeight(c_fiss, spectrum);
21  w_fill_ = CosiWeight(c_fill, spectrum);
22  w_topup_ = CosiWeight(c_topup, spectrum);
23  }
24 
25  virtual ~FissConverter() {}
26 
27  virtual double convert(
28  cyclus::Material::Ptr m, cyclus::Arc const* a = NULL,
29  cyclus::ExchangeTranslationContext<cyclus::Material> const* ctx =
30  NULL) const {
31  double w_tgt = CosiWeight(m->comp(), spec_);
32  if (ValidWeights(w_fill_, w_tgt, w_fiss_)) {
33  double frac = HighFrac(w_fill_, w_tgt, w_fiss_);
34  return AtomToMassFrac(frac, c_fiss_, c_fill_) * m->quantity();
35  } else if (ValidWeights(w_fiss_, w_tgt, w_topup_)) {
36  // use fiss inventory as filler, and topup as fissile
37  double frac = LowFrac(w_fiss_, w_tgt, w_topup_);
38  return AtomToMassFrac(frac, c_fiss_, c_topup_) * m->quantity();
39  } else {
40  // don't bid at all
41  return 1e200;
42  }
43  }
44 
45  private:
47  double w_fiss_;
48  double w_topup_;
49  double w_fill_;
50  Composition::Ptr c_fiss_;
51  Composition::Ptr c_fill_;
52  Composition::Ptr c_topup_;
53 };
54 
55 class FillConverter : public cyclus::Converter<cyclus::Material> {
56  public:
57  FillConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss,
58  Composition::Ptr c_topup, std::string spectrum)
59  : c_fiss_(c_fiss), c_topup_(c_topup), c_fill_(c_fill), spec_(spectrum) {
60  w_fiss_ = CosiWeight(c_fiss, spectrum);
61  w_fill_ = CosiWeight(c_fill, spectrum);
62  w_topup_ = CosiWeight(c_topup, spectrum);
63  }
64 
65  virtual ~FillConverter() {}
66 
67  virtual double convert(
68  cyclus::Material::Ptr m, cyclus::Arc const* a = NULL,
69  cyclus::ExchangeTranslationContext<cyclus::Material> const* ctx =
70  NULL) const {
71  double w_tgt = CosiWeight(m->comp(), spec_);
72  if (ValidWeights(w_fill_, w_tgt, w_fiss_)) {
73  double frac = LowFrac(w_fill_, w_tgt, w_fiss_);
74  return AtomToMassFrac(frac, c_fill_, c_fiss_) * m->quantity();
75  } else if (ValidWeights(w_fiss_, w_tgt, w_topup_)) {
76  // switched fissile inventory to filler so don't need any filler inventory
77  return 0;
78  } else {
79  // don't bid at all
80  return 1e200;
81  }
82  }
83 
84  private:
86  double w_fiss_;
87  double w_topup_;
88  double w_fill_;
89  Composition::Ptr c_fiss_;
90  Composition::Ptr c_fill_;
91  Composition::Ptr c_topup_;
92 };
93 
94 class TopupConverter : public cyclus::Converter<cyclus::Material> {
95  public:
96  TopupConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss,
97  Composition::Ptr c_topup, std::string spectrum)
98  : c_fiss_(c_fiss), c_topup_(c_topup), c_fill_(c_fill), spec_(spectrum) {
99  w_fiss_ = CosiWeight(c_fiss, spectrum);
100  w_fill_ = CosiWeight(c_fill, spectrum);
101  w_topup_ = CosiWeight(c_topup, spectrum);
102  }
103 
104  virtual ~TopupConverter() {}
105 
106  virtual double convert(
107  cyclus::Material::Ptr m, cyclus::Arc const* a = NULL,
108  cyclus::ExchangeTranslationContext<cyclus::Material> const* ctx =
109  NULL) const {
110  double w_tgt = CosiWeight(m->comp(), spec_);
111  if (ValidWeights(w_fill_, w_tgt, w_fiss_)) {
112  return 0;
113  } else if (ValidWeights(w_fiss_, w_tgt, w_topup_)) {
114  // switched fissile inventory to filler and topup as fissile
115  double frac = HighFrac(w_fiss_, w_tgt, w_topup_);
116  return AtomToMassFrac(frac, c_topup_, c_fiss_) * m->quantity();
117  } else {
118  // don't bid at all
119  return 1e200;
120  }
121  }
122 
123  private:
125  double w_fiss_;
126  double w_topup_;
127  double w_fill_;
128  Composition::Ptr c_fiss_;
129  Composition::Ptr c_fill_;
130  Composition::Ptr c_topup_;
131 };
132 
133 FuelFab::FuelFab(cyclus::Context* ctx)
134  : cyclus::Facility(ctx),
135  fill_size(0),
136  fiss_size(0),
137  throughput(0),
138  latitude(0.0),
139  longitude(0.0),
141 
142 void FuelFab::EnterNotify() {
143  cyclus::Facility::EnterNotify();
144 
145  if (fiss_commod_prefs.empty()) {
146  for (int i = 0; i < fiss_commods.size(); i++) {
147  fiss_commod_prefs.push_back(cyclus::kDefaultPref);
148  }
149  } else if (fiss_commod_prefs.size() != fiss_commods.size()) {
150  std::stringstream ss;
151  ss << "prototype '" << prototype() << "' has " << fiss_commod_prefs.size()
152  << " fiss_commod_prefs vals, expected " << fiss_commods.size();
153  throw cyclus::ValidationError(ss.str());
154  }
155 
156  if (fill_commod_prefs.empty()) {
157  for (int i = 0; i < fill_commods.size(); i++) {
158  fill_commod_prefs.push_back(cyclus::kDefaultPref);
159  }
160  } else if (fill_commod_prefs.size() != fill_commods.size()) {
161  std::stringstream ss;
162  ss << "prototype '" << prototype() << "' has " << fill_commod_prefs.size()
163  << " fill_commod_prefs vals, expected " << fill_commods.size();
164  throw cyclus::ValidationError(ss.str());
165  }
166  RecordPosition();
167 }
168 
169 std::set<cyclus::RequestPortfolio<Material>::Ptr> FuelFab::GetMatlRequests() {
170  using cyclus::RequestPortfolio;
171 
172  std::set<RequestPortfolio<Material>::Ptr> ports;
173 
174  bool exclusive = false;
175 
176  if (fiss.space() > cyclus::eps_rsrc()) {
177  RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
178 
179  Material::Ptr m = cyclus::NewBlankMaterial(fiss.space());
180  if (!fiss_recipe.empty()) {
181  Composition::Ptr c = context()->GetRecipe(fiss_recipe);
182  m = Material::CreateUntracked(fiss.space(), c);
183  }
184 
185  std::vector<cyclus::Request<Material>*> reqs;
186  for (int i = 0; i < fiss_commods.size(); i++) {
187  std::string commod = fiss_commods[i];
188  double pref = fiss_commod_prefs[i];
189  reqs.push_back(port->AddRequest(m, this, commod, pref, exclusive));
190  req_inventories_[reqs.back()] = "fiss";
191  }
192  port->AddMutualReqs(reqs);
193  ports.insert(port);
194  }
195 
196  if (fill.space() > cyclus::eps_rsrc()) {
197  RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
198 
199  Material::Ptr m = cyclus::NewBlankMaterial(fill.space());
200  if (!fill_recipe.empty()) {
201  Composition::Ptr c = context()->GetRecipe(fill_recipe);
202  m = Material::CreateUntracked(fill.space(), c);
203  }
204 
205  std::vector<cyclus::Request<Material>*> reqs;
206  for (int i = 0; i < fill_commods.size(); i++) {
207  std::string commod = fill_commods[i];
208  double pref = fill_commod_prefs[i];
209  reqs.push_back(port->AddRequest(m, this, commod, pref, exclusive));
210  req_inventories_[reqs.back()] = "fill";
211  }
212  port->AddMutualReqs(reqs);
213  ports.insert(port);
214  }
215 
216  if (topup.space() > cyclus::eps_rsrc()) {
217  RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
218 
219  Material::Ptr m = cyclus::NewBlankMaterial(topup.space());
220  if (!topup_recipe.empty()) {
221  Composition::Ptr c = context()->GetRecipe(topup_recipe);
222  m = Material::CreateUntracked(topup.space(), c);
223  }
224  cyclus::Request<Material>* r =
225  port->AddRequest(m, this, topup_commod, topup_pref, exclusive);
226  req_inventories_[r] = "topup";
227  ports.insert(port);
228  }
229 
230  return ports;
231 }
232 
233 bool Contains(std::vector<std::string> vec, std::string s) {
234  for (int i = 0; i < vec.size(); i++) {
235  if (vec[i] == s) {
236  return true;
237  }
238  }
239  return false;
240 }
241 
243  const std::vector<std::pair<cyclus::Trade<Material>, Material::Ptr> >&
244  responses) {
245  std::vector<std::pair<cyclus::Trade<cyclus::Material>,
246  cyclus::Material::Ptr> >::const_iterator trade;
247 
248  for (trade = responses.begin(); trade != responses.end(); ++trade) {
249  std::string commod = trade->first.request->commodity();
250  double req_qty = trade->first.request->target()->quantity();
251  cyclus::Request<Material>* req = trade->first.request;
252  Material::Ptr m = trade->second;
253  if (req_inventories_[req] == "fill") {
254  fill.Push(m);
255  } else if (req_inventories_[req] == "topup") {
256  topup.Push(m);
257  } else if (req_inventories_[req] == "fiss") {
258  fiss.Push(m);
259  } else {
260  throw cyclus::ValueError("cycamore::FuelFab was overmatched on requests");
261  }
262  }
263 
264  req_inventories_.clear();
265 
266  // IMPORTANT - each buffer needs to be a single homogenous composition or
267  // the inventory mixing constraints for bids don't work
268  if (fill.count() > 1) {
269  fill.Push(cyclus::toolkit::Squash(fill.PopN(fill.count())));
270  }
271  if (fiss.count() > 1) {
272  fiss.Push(cyclus::toolkit::Squash(fiss.PopN(fiss.count())));
273  }
274  if (topup.count() > 1) {
275  topup.Push(cyclus::toolkit::Squash(topup.PopN(topup.count())));
276  }
277 }
278 
279 std::set<cyclus::BidPortfolio<Material>::Ptr> FuelFab::GetMatlBids(
280  cyclus::CommodMap<Material>::type& commod_requests) {
281  using cyclus::BidPortfolio;
282 
283  std::set<BidPortfolio<Material>::Ptr> ports;
284  std::vector<cyclus::Request<Material>*>& reqs = commod_requests[outcommod];
285 
286  if (throughput == 0) {
287  return ports;
288  } else if (reqs.size() == 0) {
289  return ports;
290  }
291 
292  double w_fill = 0;
293  Composition::Ptr
294  c_fill; // no default needed - this is non-optional parameter
295  if (fill.count() > 0) {
296  c_fill = fill.Peek()->comp();
297  w_fill = CosiWeight(c_fill, spectrum);
298  } else {
299  c_fill = context()->GetRecipe(fill_recipe);
300  w_fill = CosiWeight(c_fill, spectrum);
301  }
302 
303  double w_topup = 0;
304  Composition::Ptr c_topup = c_fill;
305  if (topup.count() > 0) {
306  c_topup = topup.Peek()->comp();
307  w_topup = CosiWeight(c_topup, spectrum);
308  } else if (!topup_recipe.empty()) {
309  c_topup = context()->GetRecipe(topup_recipe);
310  w_topup = CosiWeight(c_topup, spectrum);
311  }
312 
313  double w_fiss =
314  w_fill; // this allows trading just fill with no fiss inventory
315  Composition::Ptr c_fiss = c_fill;
316  if (fiss.count() > 0) {
317  c_fiss = fiss.Peek()->comp();
318  w_fiss = CosiWeight(c_fiss, spectrum);
319  } else if (!fiss_recipe.empty()) {
320  c_fiss = context()->GetRecipe(fiss_recipe);
321  w_fiss = CosiWeight(c_fiss, spectrum);
322  }
323 
324  BidPortfolio<Material>::Ptr port(new BidPortfolio<Material>());
325  for (int j = 0; j < reqs.size(); j++) {
326  cyclus::Request<Material>* req = reqs[j];
327 
328  Composition::Ptr tgt = req->target()->comp();
329  double w_tgt = CosiWeight(tgt, spectrum);
330  double tgt_qty = req->target()->quantity();
331  if (ValidWeights(w_fill, w_tgt, w_fiss)) {
332  double fiss_frac = HighFrac(w_fill, w_tgt, w_fiss);
333  double fill_frac = 1 - fiss_frac;
334  fiss_frac = AtomToMassFrac(fiss_frac, c_fiss, c_fill);
335  fill_frac = AtomToMassFrac(fill_frac, c_fill, c_fiss);
336  Material::Ptr m1 = Material::CreateUntracked(fiss_frac * tgt_qty, c_fiss);
337  Material::Ptr m2 = Material::CreateUntracked(fill_frac * tgt_qty, c_fill);
338  m1->Absorb(m2);
339 
340  bool exclusive = false;
341  port->AddBid(req, m1, this, exclusive);
342  } else if (topup.count() > 0 && ValidWeights(w_fiss, w_tgt, w_topup)) {
343  // only bid with topup if we have filler - otherwise we might be able to
344  // meet target with filler when we get it. we should only use topup
345  // when the fissile has too poor neutronics.
346  double topup_frac = HighFrac(w_fiss, w_tgt, w_topup);
347  double fiss_frac = 1 - topup_frac;
348  fiss_frac = AtomToMassFrac(fiss_frac, c_fiss, c_topup);
349  topup_frac = AtomToMassFrac(topup_frac, c_topup, c_fiss);
350  Material::Ptr m1 =
351  Material::CreateUntracked(topup_frac * tgt_qty, c_topup);
352  Material::Ptr m2 = Material::CreateUntracked(fiss_frac * tgt_qty, c_fiss);
353  m1->Absorb(m2);
354 
355  bool exclusive = false;
356  port->AddBid(req, m1, this, exclusive);
357  } else if (fiss.count() > 0 && fill.count() > 0 ||
358  fiss.count() > 0 && topup.count() > 0) {
359  // else can't meet the target weight - don't bid. Just a plain else
360  // doesn't work because we set w_fiss = w_fill if we don't have any fiss
361  // or fill inventory.
362  std::stringstream ss;
363  ss << "prototype '" << prototype()
364  << "': Input stream weights/reactivity do not span "
365  "the requested material weight.";
366  cyclus::Warn<cyclus::VALUE_WARNING>(ss.str());
367  }
368  }
369 
370  cyclus::Converter<Material>::Ptr fissconv(
371  new FissConverter(c_fill, c_fiss, c_topup, spectrum));
372  cyclus::Converter<Material>::Ptr fillconv(
373  new FillConverter(c_fill, c_fiss, c_topup, spectrum));
374  cyclus::Converter<Material>::Ptr topupconv(
375  new TopupConverter(c_fill, c_fiss, c_topup, spectrum));
376  // important! - the std::max calls prevent CapacityConstraint throwing a zero
377  // cap exception
378  cyclus::CapacityConstraint<Material> fissc(std::max(fiss.quantity(), 1e-10),
379  fissconv);
380  cyclus::CapacityConstraint<Material> fillc(std::max(fill.quantity(), 1e-10),
381  fillconv);
382  cyclus::CapacityConstraint<Material> topupc(std::max(topup.quantity(), 1e-10),
383  topupconv);
384  port->AddConstraint(fillc);
385  port->AddConstraint(fissc);
386  port->AddConstraint(topupc);
387 
388  cyclus::CapacityConstraint<Material> cc(throughput);
389  port->AddConstraint(cc);
390  ports.insert(port);
391  return ports;
392 }
393 
395  const std::vector<cyclus::Trade<Material> >& trades,
396  std::vector<std::pair<cyclus::Trade<Material>, Material::Ptr> >&
397  responses) {
398  using cyclus::Trade;
399 
400  // guard against cases where a buffer is empty - this is okay because some
401  // trades may not need that particular buffer.
402  double w_fill = 0;
403  if (fill.count() > 0) {
404  w_fill = CosiWeight(fill.Peek()->comp(), spectrum);
405  }
406  double w_topup = 0;
407  if (topup.count() > 0) {
408  w_topup = CosiWeight(topup.Peek()->comp(), spectrum);
409  }
410  double w_fiss = 0;
411  if (fiss.count() > 0) {
412  w_fiss = CosiWeight(fiss.Peek()->comp(), spectrum);
413  }
414 
415  std::vector<cyclus::Trade<cyclus::Material> >::const_iterator it;
416  double tot = 0;
417  for (int i = 0; i < trades.size(); i++) {
418  Material::Ptr tgt = trades[i].request->target();
419 
420  double w_tgt = CosiWeight(tgt->comp(), spectrum);
421  double qty = trades[i].amt;
422  double wfiss = w_fiss;
423 
424  tot += qty;
425  if (tot > throughput + cyclus::eps_rsrc()) {
426  std::stringstream ss;
427  ss << "FuelFab was matched above throughput limit: " << tot << " > "
428  << throughput;
429  throw cyclus::ValueError(ss.str());
430  }
431 
432  if (fiss.count() == 0) {
433  // use straight filler to satisfy this request
434  double fillqty = qty;
435  if (std::abs(fillqty - fill.quantity()) < cyclus::eps_rsrc()) {
436  fillqty = std::min(fill.quantity(), qty);
437  }
438  responses.push_back(
439  std::make_pair(trades[i], fill.Pop(fillqty, cyclus::eps_rsrc())));
440  } else if (fill.count() == 0 && ValidWeights(w_fill, w_tgt, w_fiss)) {
441  // use straight fissile to satisfy this request
442  double fissqty = qty;
443  if (std::abs(fissqty - fiss.quantity()) < cyclus::eps_rsrc()) {
444  fissqty = std::min(fiss.quantity(), qty);
445  }
446  responses.push_back(
447  std::make_pair(trades[i], fiss.Pop(fissqty, cyclus::eps_rsrc())));
448  } else if (ValidWeights(w_fill, w_tgt, w_fiss)) {
449  double fiss_frac = HighFrac(w_fill, w_tgt, w_fiss);
450  double fill_frac = LowFrac(w_fill, w_tgt, w_fiss);
451  fiss_frac =
452  AtomToMassFrac(fiss_frac, fiss.Peek()->comp(), fill.Peek()->comp());
453  fill_frac =
454  AtomToMassFrac(fill_frac, fill.Peek()->comp(), fiss.Peek()->comp());
455 
456  double fissqty = fiss_frac * qty;
457  if (std::abs(fissqty - fiss.quantity()) < cyclus::eps_rsrc()) {
458  fissqty = std::min(fiss.quantity(), fiss_frac * qty);
459  }
460  double fillqty = fill_frac * qty;
461  if (std::abs(fillqty - fill.quantity()) < cyclus::eps_rsrc()) {
462  fillqty = std::min(fill.quantity(), fill_frac * qty);
463  }
464 
465  Material::Ptr m = fiss.Pop(fissqty, cyclus::eps_rsrc());
466  // this if block prevents zero qty ResBuf pop exceptions
467  if (fill_frac > 0) {
468  m->Absorb(fill.Pop(fillqty, cyclus::eps_rsrc()));
469  }
470  responses.push_back(std::make_pair(trades[i], m));
471  } else {
472  double topup_frac = HighFrac(w_fiss, w_tgt, w_topup);
473  double fiss_frac = 1 - topup_frac;
474  topup_frac =
475  AtomToMassFrac(topup_frac, topup.Peek()->comp(), fiss.Peek()->comp());
476  fiss_frac =
477  AtomToMassFrac(fiss_frac, fiss.Peek()->comp(), topup.Peek()->comp());
478 
479  double fissqty = fiss_frac * qty;
480  if (std::abs(fissqty - fiss.quantity()) < cyclus::eps_rsrc()) {
481  fissqty = std::min(fiss.quantity(), fiss_frac * qty);
482  }
483  double topupqty = topup_frac * qty;
484  if (std::abs(topupqty - topup.quantity()) < cyclus::eps_rsrc()) {
485  topupqty = std::min(topup.quantity(), topup_frac * qty);
486  }
487 
488  Material::Ptr m = fiss.Pop(fissqty, cyclus::eps_rsrc());
489  // this if block prevents zero qty ResBuf pop exceptions
490  if (topup_frac > 0) {
491  m->Absorb(topup.Pop(topupqty, cyclus::eps_rsrc()));
492  }
493  responses.push_back(std::make_pair(trades[i], m));
494  }
495  }
496 }
497 
499  std::string specification = this->spec();
500  context()
501  ->NewDatum("AgentPosition")
502  ->AddVal("Spec", specification)
503  ->AddVal("Prototype", this->prototype())
504  ->AddVal("AgentId", id())
505  ->AddVal("Latitude", latitude)
506  ->AddVal("Longitude", longitude)
507  ->Record();
508 }
509 
510 extern "C" cyclus::Agent* ConstructFuelFab(cyclus::Context* ctx) {
511  return new FuelFab(ctx);
512 }
513 
514 // Returns the weight of c using 1 group cross sections of type spectrum
515 // which must be one of:
516 //
517 // * thermal
518 // * thermal_maxwell_ave
519 // * fission_spectrum_ave
520 // * resonance_integral
521 // * fourteen_MeV
522 //
523 // The weight is calculated as "(nu*sigma_f - sigma_a) * N". Since weights
524 // are computed based on nuclide atom fractions, corresponding computed
525 // material/mixing fractions will also be atom-based naturally and will need
526 // to be converted to mass-based for actual material object mixing.
527 double CosiWeight(cyclus::Composition::Ptr c, const std::string& spectrum) {
528  cyclus::CompMap cm = c->atom();
529  cyclus::compmath::Normalize(&cm);
530 
531  if (spectrum == "thermal") {
532  double nu_pu239 = 2.85;
533  double nu_u233 = 2.5;
534  double nu_u235 = 2.43;
535  double nu_u238 = 0;
536  double nu_pu241 = nu_pu239;
537 
538  static std::map<int, double> absorb_xs;
539  static std::map<int, double> fiss_xs;
540  static double p_u238 = 0;
541  static double p_pu239 = 0;
542  if (p_u238 == 0) {
543  double fiss_u238 = simple_xs(922380000, "fission", "thermal");
544  double absorb_u238 = simple_xs(922380000, "absorption", "thermal");
545  p_u238 = nu_u238 * fiss_u238 - absorb_u238;
546 
547  double fiss_pu239 = simple_xs(942390000, "fission", "thermal");
548  double absorb_pu239 = simple_xs(942390000, "absorption", "thermal");
549  p_pu239 = nu_pu239 * fiss_pu239 - absorb_pu239;
550  }
551 
552  cyclus::CompMap::iterator it;
553  double w = 0;
554  for (it = cm.begin(); it != cm.end(); ++it) {
555  cyclus::Nuc nuc = it->first;
556  double nu = 0;
557  if (nuc == 922350000) {
558  nu = nu_u235;
559  } else if (nuc == 922330000) {
560  nu = nu_u233;
561  } else if (nuc == 942390000) {
562  nu = nu_pu239;
563  } else if (nuc == 942410000) {
564  nu = nu_pu241;
565  }
566 
567  double fiss = 0;
568  double absorb = 0;
569  if (absorb_xs.count(nuc) == 0) {
570  try {
571  fiss = simple_xs(nuc, "fission", "thermal");
572  absorb = simple_xs(nuc, "absorption", "thermal");
573  absorb_xs[nuc] = absorb;
574  fiss_xs[nuc] = fiss;
575  } catch (pyne::InvalidSimpleXS err) {
576  fiss = 0;
577  absorb = 0;
578  }
579  } else {
580  fiss = fiss_xs[nuc];
581  absorb = absorb_xs[nuc];
582  }
583 
584  double p = nu * fiss - absorb;
585  w += it->second * (p - p_u238) / (p_pu239 - p_u238);
586  }
587  return w;
588  } else if (spectrum == "fission_spectrum_ave") {
589  double nu_pu239 = 3.1;
590  double nu_u233 = 2.63;
591  double nu_u235 = 2.58;
592  double nu_u238 = 0;
593  double nu_pu241 = nu_pu239;
594 
595  static std::map<int, double> absorb_xs;
596  static std::map<int, double> fiss_xs;
597  static double p_u238 = 0;
598  static double p_pu239 = 0;
599  if (p_u238 == 0) {
600  double fiss_u238 =
601  simple_xs(922380000, "fission", "fission_spectrum_ave");
602  double absorb_u238 =
603  simple_xs(922380000, "absorption", "fission_spectrum_ave");
604  p_u238 = nu_u238 * fiss_u238 - absorb_u238;
605 
606  double fiss_pu239 =
607  simple_xs(942390000, "fission", "fission_spectrum_ave");
608  double absorb_pu239 =
609  simple_xs(942390000, "absorption", "fission_spectrum_ave");
610  p_pu239 = nu_pu239 * fiss_pu239 - absorb_pu239;
611  }
612 
613  cyclus::CompMap::iterator it;
614  double w = 0;
615  for (it = cm.begin(); it != cm.end(); ++it) {
616  cyclus::Nuc nuc = it->first;
617  double nu = 0;
618  if (nuc == 922350000) {
619  nu = nu_u235;
620  } else if (nuc == 922330000) {
621  nu = nu_u233;
622  } else if (nuc == 942390000) {
623  nu = nu_pu239;
624  } else if (nuc == 942410000) {
625  nu = nu_pu241;
626  }
627 
628  double fiss = 0;
629  double absorb = 0;
630  if (absorb_xs.count(nuc) == 0) {
631  try {
632  fiss = simple_xs(nuc, "fission", "fission_spectrum_ave");
633  absorb = simple_xs(nuc, "absorption", "fission_spectrum_ave");
634  absorb_xs[nuc] = absorb;
635  fiss_xs[nuc] = fiss;
636  } catch (pyne::InvalidSimpleXS err) {
637  fiss = 0;
638  absorb = 0;
639  }
640  } else {
641  fiss = fiss_xs[nuc];
642  absorb = absorb_xs[nuc];
643  }
644 
645  double p = nu * fiss - absorb;
646  w += it->second * (p - p_u238) / (p_pu239 - p_u238);
647  }
648  return w;
649  } else {
650  double nu_pu239 = 3.1;
651  double nu_u233 = 2.63;
652  double nu_u235 = 2.58;
653  double nu_u238 = 0;
654  double nu_pu241 = nu_pu239;
655 
656  double fiss_u238 = simple_xs(922380000, "fission", spectrum);
657  double absorb_u238 = simple_xs(922380000, "absorption", spectrum);
658  double p_u238 = nu_u238 * fiss_u238 - absorb_u238;
659 
660  double fiss_pu239 = simple_xs(942390000, "fission", spectrum);
661  double absorb_pu239 = simple_xs(942390000, "absorption", spectrum);
662  double p_pu239 = nu_pu239 * fiss_pu239 - absorb_pu239;
663 
664  cyclus::CompMap::iterator it;
665  double w = 0;
666  for (it = cm.begin(); it != cm.end(); ++it) {
667  cyclus::Nuc nuc = it->first;
668  double nu = 0;
669  if (nuc == 922350000) {
670  nu = nu_u235;
671  } else if (nuc == 922330000) {
672  nu = nu_u233;
673  } else if (nuc == 942390000) {
674  nu = nu_pu239;
675  } else if (nuc == 942410000) {
676  nu = nu_pu241;
677  }
678 
679  double fiss = 0;
680  double absorb = 0;
681  try {
682  fiss = simple_xs(nuc, "fission", spectrum);
683  absorb = simple_xs(nuc, "absorption", spectrum);
684  } catch (pyne::InvalidSimpleXS err) {
685  fiss = 0;
686  absorb = 0;
687  }
688 
689  double p = nu * fiss - absorb;
690  w += it->second * (p - p_u238) / (p_pu239 - p_u238);
691  }
692  return w;
693  }
694 }
695 
696 // Convert an atom frac (n1/(n1+n2) to a mass frac (m1/(m1+m2) given
697 // corresponding compositions c1 and c2.
698 double AtomToMassFrac(double atomfrac, Composition::Ptr c1,
699  Composition::Ptr c2) {
700  cyclus::CompMap n1 = c1->atom();
701  cyclus::CompMap n2 = c2->atom();
702  cyclus::compmath::Normalize(&n1, atomfrac);
703  cyclus::compmath::Normalize(&n2, 1 - atomfrac);
704 
705  cyclus::CompMap::iterator it;
706 
707  double mass1 = 0;
708  for (it = n1.begin(); it != n1.end(); ++it) {
709  mass1 += it->second * pyne::atomic_mass(it->first);
710  }
711 
712  double mass2 = 0;
713  for (it = n2.begin(); it != n2.end(); ++it) {
714  mass2 += it->second * pyne::atomic_mass(it->first);
715  }
716 
717  return mass1 / (mass1 + mass2);
718 }
719 
720 double HighFrac(double w_low, double w_target, double w_high, double eps) {
721  if (!ValidWeights(w_low, w_target, w_high)) {
722  throw cyclus::ValueError("low and high weights cannot meet target");
723  } else if (w_low == w_high && w_target == w_low) {
724  return 1;
725  }
726  double f = std::abs((w_target - w_low) / (w_high - w_low));
727  if (1 - f < eps) {
728  return 1;
729  } else if (f < eps) {
730  return 0;
731  }
732  return f;
733 }
734 
735 double LowFrac(double w_low, double w_target, double w_high, double eps) {
736  return 1 - HighFrac(w_low, w_target, w_high, eps);
737 }
738 
739 // Returns true if the given weights can be used to linearly interpolate valid
740 // mixing fractions of the filler and fissile streams to hit the target.
741 bool ValidWeights(double w_low, double w_target, double w_high) {
742  // w_tgt must be in between w_fill and w_fiss for the equivalence
743  // interpolation to work.
744  return w_low <= w_target && w_target <= w_high;
745 }
746 
747 } // namespace cycamore
virtual double convert(cyclus::Material::Ptr m, cyclus::Arc const *a=NULL, cyclus::ExchangeTranslationContext< cyclus::Material > const *ctx=NULL) const
FissConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss, Composition::Ptr c_topup, std::string spectrum)
Definition: src/fuel_fab.cc:17
double HighFrac(double w_low, double w_target, double w_high, double eps)
bool Contains(std::vector< std::string > vec, std::string s)
double longitude
double AtomToMassFrac(double atomfrac, Composition::Ptr c1, Composition::Ptr c2)
double CosiWeight(cyclus::Composition::Ptr c, const std::string &spectrum)
FuelFab takes in 2 streams of material and mixes them in ratios in order to supply material that matc...
cycamore::GrowthRegion string
cyclus::Agent * ConstructFuelFab(cyclus::Context *ctx)
virtual void AcceptMatlTrades(const std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
TopupConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss, Composition::Ptr c_topup, std::string spectrum)
Definition: src/fuel_fab.cc:96
FuelFab(cyclus::Context *ctx)
FillConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss, Composition::Ptr c_topup, std::string spectrum)
Definition: src/fuel_fab.cc:57
virtual void GetMatlTrades(const std::vector< cyclus::Trade< cyclus::Material > > &trades, std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
cyclus::toolkit::Position coordinates
void RecordPosition()
Records an agent&#39;s latitude and longitude to the output db.
bool ValidWeights(double w_low, double w_target, double w_high)
void RecordPosition()
Records an agent&#39;s latitude and longitude to the output db.
virtual std::set< cyclus::RequestPortfolio< cyclus::Material >::Ptr > GetMatlRequests()
virtual double convert(cyclus::Material::Ptr m, cyclus::Arc const *a=NULL, cyclus::ExchangeTranslationContext< cyclus::Material > const *ctx=NULL) const
Definition: src/fuel_fab.cc:27
double LowFrac(double w_low, double w_target, double w_high, double eps)
virtual double convert(cyclus::Material::Ptr m, cyclus::Arc const *a=NULL, cyclus::ExchangeTranslationContext< cyclus::Material > const *ctx=NULL) const
Definition: src/fuel_fab.cc:67
virtual std::set< cyclus::BidPortfolio< cyclus::Material >::Ptr > GetMatlBids(cyclus::CommodMap< cyclus::Material >::type &commod_requests)