CYCAMORE
Loading...
Searching...
No Matches
src/fuel_fab.cc
Go to the documentation of this file.
1#include "fuel_fab.h"
2
3#include <sstream>
4
5using cyclus::Material;
6using cyclus::Composition;
7using pyne::simple_xs;
8
9#define SHOW(X) \
10 std::cout << std::setprecision(17) << __FILE__ << ":" << __LINE__ \
11 << ": " #X " = " << X << "\n"
12
13namespace cycamore {
14
15class FissConverter : public cyclus::Converter<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 Material::Ptr m, cyclus::Arc const* a = NULL,
29 cyclus::ExchangeTranslationContext<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 cyclus::CY_LARGE_DOUBLE;
42 }
43 }
44
45 private:
46 std::string spec_;
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
55class FillConverter : public cyclus::Converter<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 Material::Ptr m, cyclus::Arc const* a = NULL,
69 cyclus::ExchangeTranslationContext<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 cyclus::CY_LARGE_DOUBLE;
81 }
82 }
83
84 private:
85 std::string spec_;
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
94class TopupConverter : public cyclus::Converter<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 Material::Ptr m, cyclus::Arc const* a = NULL,
108 cyclus::ExchangeTranslationContext<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 cyclus::CY_LARGE_DOUBLE;
120 }
121 }
122
123 private:
124 std::string spec_;
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
133FuelFab::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
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 }
167}
168
169std::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
233bool 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<Material>,
246 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
279std::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(), cyclus::CY_NEAR_ZERO),
379 fissconv);
380 cyclus::CapacityConstraint<Material> fillc(std::max(fill.quantity(), cyclus::CY_NEAR_ZERO),
381 fillconv);
382 cyclus::CapacityConstraint<Material> topupc(std::max(topup.quantity(), cyclus::CY_NEAR_ZERO),
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<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
510extern "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.
527double CosiWeight(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.
698double 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
720double 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
735double 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.
741bool 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
FillConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss, Composition::Ptr c_topup, std::string spectrum)
virtual double convert(Material::Ptr m, cyclus::Arc const *a=NULL, cyclus::ExchangeTranslationContext< Material > const *ctx=NULL) const
FissConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss, Composition::Ptr c_topup, std::string spectrum)
virtual double convert(Material::Ptr m, cyclus::Arc const *a=NULL, cyclus::ExchangeTranslationContext< Material > const *ctx=NULL) const
FuelFab(cyclus::Context *ctx)
void RecordPosition()
Records an agent's latitude and longitude to the output db.
virtual void AcceptMatlTrades(const std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
cyclus::toolkit::ResBuf< cyclus::Material > fill
std::map< cyclus::Request< cyclus::Material > *, std::string > req_inventories_
virtual void GetMatlTrades(const std::vector< cyclus::Trade< cyclus::Material > > &trades, std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
virtual std::set< cyclus::RequestPortfolio< cyclus::Material >::Ptr > GetMatlRequests()
std::vector< double > fill_commod_prefs
virtual std::set< cyclus::BidPortfolio< cyclus::Material >::Ptr > GetMatlBids(cyclus::CommodMap< cyclus::Material >::type &commod_requests)
cyclus::toolkit::ResBuf< cyclus::Material > topup
cyclus::toolkit::ResBuf< cyclus::Material > fiss
std::vector< std::string > fiss_commods
std::vector< std::string > fill_commods
std::vector< double > fiss_commod_prefs
virtual double convert(Material::Ptr m, cyclus::Arc const *a=NULL, cyclus::ExchangeTranslationContext< Material > const *ctx=NULL) const
TopupConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss, Composition::Ptr c_topup, std::string spectrum)
double HighFrac(double w_low, double w_target, double w_high, double eps)
double CosiWeight(Composition::Ptr c, const std::string &spectrum)
cyclus::Agent * ConstructFuelFab(cyclus::Context *ctx)
bool ValidWeights(double w_low, double w_target, double w_high)
double AtomToMassFrac(double atomfrac, Composition::Ptr c1, Composition::Ptr c2)
bool Contains(std::vector< std::string > vec, std::string s)
double LowFrac(double w_low, double w_target, double w_high, double eps)
cyclus::toolkit::Position coordinates