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