CYCAMORE
Loading...
Searching...
No Matches
build/cycamore/enrichment.cc
Go to the documentation of this file.
1#line 1 "/cycamore/src/enrichment.cc"
2// Implements the Enrichment class
3#include "enrichment.h"
4
5#include <algorithm>
6#include <cmath>
7#include <limits>
8#include <sstream>
9#include <vector>
10
11#include <boost/lexical_cast.hpp>
12
13using cyclus::Material;
14
15namespace cycamore {
16
17// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
18Enrichment::Enrichment(cyclus::Context* ctx)
19 : cyclus::Facility(ctx),
20 tails_assay(0),
21 swu_capacity(0),
22 max_enrich(1),
23 initial_feed(0),
24 feed_commod(""),
25 feed_recipe(""),
27 tails_commod(""),
28 order_prefs(true) {}
29
30// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
32
33// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
34std::string Enrichment::str() {
35 std::stringstream ss;
36 ss << cyclus::Facility::str() << " with enrichment facility parameters:"
37 << " * SWU capacity: " << SwuCapacity()
38 << " * Tails assay: " << tails_assay << " * Feed assay: " << FeedAssay()
39 << " * Input cyclus::Commodity: " << feed_commod
40 << " * Output cyclus::Commodity: " << product_commod
41 << " * Tails cyclus::Commodity: " << tails_commod;
42 return ss.str();
43}
44
45// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
46void Enrichment::Build(cyclus::Agent* parent) {
47 Facility::Build(parent);
48 if (initial_feed > 0) {
49 inventory.Push(Material::Create(this, initial_feed,
50 context()->GetRecipe(feed_recipe)));
51 }
52
53 LOG(cyclus::LEV_DEBUG2, "EnrFac") << "Enrichment "
54 << " entering the simuluation: ";
55 LOG(cyclus::LEV_DEBUG2, "EnrFac") << str();
56}
57
59 cyclus::Facility::EnterNotify();
60 InitializePosition();
61}
62
63// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
68
69// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
71 using cyclus::toolkit::RecordTimeSeries;
72 LOG(cyclus::LEV_INFO4, "EnrFac") << prototype() << " used "
73 << intra_timestep_swu_ << " SWU";
74 RecordTimeSeries<cyclus::toolkit::ENRICH_SWU>(this, intra_timestep_swu_);
75 LOG(cyclus::LEV_INFO4, "EnrFac") << prototype() << " used "
76 << intra_timestep_feed_ << " feed";
77 RecordTimeSeries<cyclus::toolkit::ENRICH_FEED>(this, intra_timestep_feed_);
78 RecordTimeSeries<double>("demand"+feed_commod, this, intra_timestep_feed_);
79}
80
81// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
82std::set<cyclus::RequestPortfolio<Material>::Ptr>
84 using cyclus::RequestPortfolio;
85
86 std::set<RequestPortfolio<Material>::Ptr> ports;
87 RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
88 Material::Ptr mat = Request_();
89 double amt = mat->quantity();
90
91 if (amt > cyclus::eps_rsrc()) {
92 port->AddRequest(mat, this, feed_commod);
93 ports.insert(port);
94 }
95
96 return ports;
97}
98
99// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
100bool SortBids(cyclus::Bid<Material>* i,
101 cyclus::Bid<Material>* j) {
102 Material::Ptr mat_i = i->offer();
103 Material::Ptr mat_j = j->offer();
104
105 cyclus::toolkit::MatQuery mq_i(mat_i);
106 cyclus::toolkit::MatQuery mq_j(mat_j);
107
108 return ((mq_i.mass(922350000) / mq_i.qty()) <=
109 (mq_j.mass(922350000) / mq_j.qty()));
110}
111// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
112// Sort offers of input material to have higher preference for more
113// U-235 content
115 cyclus::PrefMap<Material>::type& prefs) {
116 using cyclus::Bid;
117
118 if (order_prefs == false) {
119 return;
120 }
121
122 cyclus::PrefMap<Material>::type::iterator reqit;
123
124 // Loop over all requests
125 for (reqit = prefs.begin(); reqit != prefs.end(); ++reqit) {
126 std::vector<Bid<Material>*> bids_vector;
127 std::map<Bid<Material>*, double>::iterator mit;
128 for (mit = reqit->second.begin(); mit != reqit->second.end(); ++mit) {
129 Bid<Material>* bid = mit->first;
130 bids_vector.push_back(bid);
131 }
132 std::sort(bids_vector.begin(), bids_vector.end(), SortBids);
133
134 // Assign preferences to the sorted vector
135 double n_bids = bids_vector.size();
136 bool u235_mass = 0;
137
138 for (int bidit = 0; bidit < bids_vector.size(); bidit++) {
139 int new_pref = bidit + 1;
140
141 // For any bids with U-235 qty=0, set pref to zero.
142 if (!u235_mass) {
143 Material::Ptr mat = bids_vector[bidit]->offer();
144 cyclus::toolkit::MatQuery mq(mat);
145 if (mq.mass(922350000) == 0) {
146 new_pref = -1;
147 } else {
148 u235_mass = true;
149 }
150 }
151 (reqit->second)[bids_vector[bidit]] = new_pref;
152 } // each bid
153 } // each Material Request
154}
155
156// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
158 const std::vector<std::pair<cyclus::Trade<Material>,
159 Material::Ptr> >& responses) {
160 // see
161 // http://stackoverflow.com/questions/5181183/boostshared-ptr-and-inheritance
162 std::vector<std::pair<cyclus::Trade<Material>,
163 Material::Ptr> >::const_iterator it;
164 for (it = responses.begin(); it != responses.end(); ++it) {
165 AddMat_(it->second);
166 }
167}
168
169// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
170std::set<cyclus::BidPortfolio<Material>::Ptr> Enrichment::GetMatlBids(
171 cyclus::CommodMap<Material>::type& out_requests) {
172 using cyclus::BidPortfolio;
173 using cyclus::CapacityConstraint;
174 using cyclus::Converter;
175 using cyclus::Request;
176 using cyclus::toolkit::MatVec;
177 using cyclus::toolkit::RecordTimeSeries;
178
179 std::set<BidPortfolio<Material>::Ptr> ports;
180
181 RecordTimeSeries<double>("supply" + tails_commod, this, tails.quantity());
182 RecordTimeSeries<double>("supply" + product_commod, this, inventory.quantity());
183 if ((out_requests.count(tails_commod) > 0) && (tails.quantity() > 0)) {
184 BidPortfolio<Material>::Ptr tails_port(new BidPortfolio<Material>());
185
186 std::vector<Request<Material>*>& tails_requests =
187 out_requests[tails_commod];
188 std::vector<Request<Material>*>::iterator it;
189 for (it = tails_requests.begin(); it != tails_requests.end(); ++it) {
190 // offer bids for all tails material, keeping discrete quantities
191 // to preserve possible variation in composition
192 MatVec mats = tails.PopN(tails.count());
193 tails.Push(mats);
194 for (int k = 0; k < mats.size(); k++) {
195 Material::Ptr m = mats[k];
196 Request<Material>* req = *it;
197 tails_port->AddBid(req, m, this);
198 }
199 }
200 // overbidding (bidding on every offer)
201 // add an overall capacity constraint
202 CapacityConstraint<Material> tails_constraint(tails.quantity());
203 tails_port->AddConstraint(tails_constraint);
204 LOG(cyclus::LEV_INFO5, "EnrFac") << prototype()
205 << " adding tails capacity constraint of "
206 << tails.capacity();
207 ports.insert(tails_port);
208 }
209
210 if ((out_requests.count(product_commod) > 0) && (inventory.quantity() > 0)) {
211 BidPortfolio<Material>::Ptr commod_port(new BidPortfolio<Material>());
212
213 std::vector<Request<Material>*>& commod_requests =
214 out_requests[product_commod];
215 std::vector<Request<Material>*>::iterator it;
216 for (it = commod_requests.begin(); it != commod_requests.end(); ++it) {
217 Request<Material>* req = *it;
218 Material::Ptr mat = req->target();
219 double request_enrich = cyclus::toolkit::UraniumAssayMass(mat);
220 if (ValidReq(req->target()) &&
221 ((request_enrich < max_enrich) ||
222 (cyclus::AlmostEq(request_enrich, max_enrich)))) {
223 Material::Ptr offer = Offer_(req->target());
224 commod_port->AddBid(req, offer, this);
225 }
226 }
227
228 Converter<Material>::Ptr sc(new SWUConverter(FeedAssay(), tails_assay));
229 Converter<Material>::Ptr nc(new NatUConverter(FeedAssay(), tails_assay));
230 CapacityConstraint<Material> swu(swu_capacity, sc);
231 CapacityConstraint<Material> natu(inventory.quantity(), nc);
232 commod_port->AddConstraint(swu);
233 commod_port->AddConstraint(natu);
234
235 LOG(cyclus::LEV_INFO5, "EnrFac")
236 << prototype() << " adding a swu constraint of " << swu.capacity();
237 LOG(cyclus::LEV_INFO5, "EnrFac")
238 << prototype() << " adding a natu constraint of " << natu.capacity();
239 ports.insert(commod_port);
240 }
241 return ports;
242}
243
244// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
245bool Enrichment::ValidReq(const Material::Ptr mat) {
246 cyclus::toolkit::MatQuery q(mat);
247 double u235 = q.atom_frac(922350000);
248 double u238 = q.atom_frac(922380000);
249 return (u238 > 0 && u235 / (u235 + u238) > tails_assay);
250}
251
252// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
254 const std::vector<cyclus::Trade<Material> >& trades,
255 std::vector<std::pair<cyclus::Trade<Material>,
256 Material::Ptr> >& responses) {
257 using cyclus::Trade;
258
261
262 std::vector<Trade<Material>>::const_iterator it;
263 for (it = trades.begin(); it != trades.end(); ++it) {
264 double qty = it->amt;
265 std::string commod_type = it->bid->request()->commodity();
266 Material::Ptr response;
267 // Figure out whether material is tails or enriched,
268 // if tails then make transfer of material
269 if (commod_type == tails_commod) {
270 LOG(cyclus::LEV_INFO5, "EnrFac")
271 << prototype() << " just received an order"
272 << " for " << it->amt << " of " << tails_commod;
273 double pop_qty = std::min(qty, tails.quantity());
274 response = tails.Pop(pop_qty, cyclus::eps_rsrc());
275 } else {
276 LOG(cyclus::LEV_INFO5, "EnrFac")
277 << prototype() << " just received an order"
278 << " for " << it->amt << " of " << product_commod;
279 response = Enrich_(it->bid->offer(), qty);
280 }
281 responses.push_back(std::make_pair(*it, response));
282 }
283
284 if (cyclus::IsNegative(tails.quantity())) {
285 std::stringstream ss;
286 ss << "is being asked to provide more than its current inventory.";
287 throw cyclus::ValueError(Agent::InformErrorMsg(ss.str()));
288 }
289 if (cyclus::IsNegative(current_swu_capacity)) {
290 throw cyclus::ValueError("EnrFac " + prototype() +
291 " is being asked to provide more than" +
292 " its SWU capacity.");
293 }
294
295}
296// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
297void Enrichment::AddMat_(Material::Ptr mat) {
298 // Elements and isotopes other than U-235, U-238 are sent directly to tails
299 cyclus::CompMap cm = mat->comp()->atom();
300 bool extra_u = false;
301 bool other_elem = false;
302 for (cyclus::CompMap::const_iterator it = cm.begin(); it != cm.end(); ++it) {
303 if (pyne::nucname::znum(it->first) == 92) {
304 if (pyne::nucname::anum(it->first) != 235 &&
305 pyne::nucname::anum(it->first) != 238 && it->second > 0) {
306 extra_u = true;
307 }
308 } else if (it->second > 0) {
309 other_elem = true;
310 }
311 }
312 if (extra_u) {
313 cyclus::Warn<cyclus::VALUE_WARNING>(
314 "More than 2 isotopes of U. "
315 "Istopes other than U-235, U-238 are sent directly to tails.");
316 }
317 if (other_elem) {
318 cyclus::Warn<cyclus::VALUE_WARNING>(
319 "Non-uranium elements are "
320 "sent directly to tails.");
321 }
322
323 LOG(cyclus::LEV_INFO5, "EnrFac") << prototype() << " is initially holding "
324 << inventory.quantity() << " total.";
325
326 try {
327 inventory.Push(mat);
328 } catch (cyclus::Error& e) {
329 e.msg(Agent::InformErrorMsg(e.msg()));
330 throw e;
331 }
332
333 LOG(cyclus::LEV_INFO5, "EnrFac")
334 << prototype() << " added " << mat->quantity() << " of " << feed_commod
335 << " to its inventory, which is holding " << inventory.quantity()
336 << " total.";
337}
338
339// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
340Material::Ptr Enrichment::Request_() {
341 double qty = std::max(0.0, inventory.capacity() - inventory.quantity());
342 return Material::CreateUntracked(qty,
343 context()->GetRecipe(feed_recipe));
344}
345
346// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
347Material::Ptr Enrichment::Offer_(Material::Ptr mat) {
348 cyclus::toolkit::MatQuery q(mat);
349 cyclus::CompMap comp;
350 comp[922350000] = q.atom_frac(922350000);
351 comp[922380000] = q.atom_frac(922380000);
352 return Material::CreateUntracked(
353 mat->quantity(), cyclus::Composition::CreateFromAtom(comp));
354}
355// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
356Material::Ptr Enrichment::Enrich_(Material::Ptr mat,
357 double qty) {
358 using cyclus::toolkit::Assays;
359 using cyclus::toolkit::UraniumAssayMass;
360 using cyclus::toolkit::SwuRequired;
361 using cyclus::toolkit::FeedQty;
362 using cyclus::toolkit::TailsQty;
363
364 // get enrichment parameters
365 Assays assays(FeedAssay(), UraniumAssayMass(mat), tails_assay);
366 double swu_req = SwuRequired(qty, assays);
367 double natu_req = FeedQty(qty, assays);
368
369 // Determine the composition of the natural uranium
370 // (ie. U-235+U-238/TotalMass)
371 double pop_qty = inventory.quantity();
372 Material::Ptr natu_matl = inventory.Pop(pop_qty, cyclus::eps_rsrc());
373 inventory.Push(natu_matl);
374
375 cyclus::toolkit::MatQuery mq(natu_matl);
376 std::set<cyclus::Nuc> nucs;
377 nucs.insert(922350000);
378 nucs.insert(922380000);
379 double natu_frac = mq.mass_frac(nucs);
380 double feed_req = natu_req / natu_frac;
381
382 // pop amount from inventory and blob it into one material
383 Material::Ptr r;
384 try {
385 // required so popping doesn't take out too much
386 if (cyclus::AlmostEq(feed_req, inventory.quantity())) {
387 r = cyclus::toolkit::Squash(inventory.PopN(inventory.count()));
388 } else {
389 r = inventory.Pop(feed_req, cyclus::eps_rsrc());
390 }
391 } catch (cyclus::Error& e) {
392 NatUConverter nc(FeedAssay(), tails_assay);
393 std::stringstream ss;
394 ss << " tried to remove " << feed_req << " from its inventory of size "
395 << inventory.quantity()
396 << " and the conversion of the material into natu is "
397 << nc.convert(mat);
398 throw cyclus::ValueError(Agent::InformErrorMsg(ss.str()));
399 }
400
401 // "enrich" it, but pull out the composition and quantity we require from the
402 // blob
403 cyclus::Composition::Ptr comp = mat->comp();
404 Material::Ptr response = r->ExtractComp(qty, comp);
405 tails.Push(r);
406
407 current_swu_capacity -= swu_req;
408
409 intra_timestep_swu_ += swu_req;
410 intra_timestep_feed_ += feed_req;
411 RecordEnrichment_(feed_req, swu_req);
412
413 LOG(cyclus::LEV_INFO5, "EnrFac") << prototype()
414 << " has performed an enrichment: ";
415 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Feed Qty: " << feed_req;
416 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Feed Assay: "
417 << assays.Feed() * 100;
418 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Product Qty: " << qty;
419 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Product Assay: "
420 << assays.Product() * 100;
421 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Tails Qty: "
422 << TailsQty(qty, assays);
423 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Tails Assay: "
424 << assays.Tails() * 100;
425 LOG(cyclus::LEV_INFO5, "EnrFac") << " * SWU: " << swu_req;
426 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Current SWU capacity: "
428
429 return response;
430}
431
432// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
433void Enrichment::RecordEnrichment_(double natural_u, double swu) {
434 using cyclus::Context;
435 using cyclus::Agent;
436
437 LOG(cyclus::LEV_DEBUG1, "EnrFac") << prototype()
438 << " has enriched a material:";
439 LOG(cyclus::LEV_DEBUG1, "EnrFac") << " * Amount: " << natural_u;
440 LOG(cyclus::LEV_DEBUG1, "EnrFac") << " * SWU: " << swu;
441
442 Context* ctx = Agent::context();
443 ctx->NewDatum("Enrichments")
444 ->AddVal("AgentId", id())
445 ->AddVal("Time", ctx->time())
446 ->AddVal("Natural_Uranium", natural_u)
447 ->AddVal("SWU", swu)
448 ->Record();
449}
450// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
452 if (inventory.empty()) {
453 return 0;
454 }
455 double pop_qty = inventory.quantity();
456 Material::Ptr fission_matl =
457 inventory.Pop(pop_qty, cyclus::eps_rsrc());
458 inventory.Push(fission_matl);
459 return cyclus::toolkit::UraniumAssayMass(fission_matl);
460}
461
462// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
463extern "C" cyclus::Agent* ConstructEnrichment(cyclus::Context* ctx) {
464 return new Enrichment(ctx);
465}
466
467} // namespace cycamore
The Enrichment facility is a simple Agent that enriches natural uranium in a Cyclus simulation.
cyclus::Material::Ptr Request_()
generates a request for this facility given its current state.
cyclus::Material::Ptr Enrich_(cyclus::Material::Ptr mat, double qty)
cyclus::Material::Ptr Offer_(cyclus::Material::Ptr req)
Generates a material offer for a given request.
virtual std::set< cyclus::RequestPortfolio< cyclus::Material >::Ptr > GetMatlRequests()
The Enrichment request Materials of its given commodity.
virtual void Tock()
Each facility is prompted to its end-of-time-step stuff on the tock of the timer.
cyclus::toolkit::ResBuf< cyclus::Material > tails
bool ValidReq(const cyclus::Material::Ptr mat)
Determines if a particular material is a valid request to respond to.
virtual ~Enrichment()
Destructor for the Enrichment class.
virtual void AdjustMatlPrefs(cyclus::PrefMap< cyclus::Material >::type &prefs)
The Enrichment adjusts preferences for offers of natural uranium it has received to maximize U-235 co...
virtual std::string str()
Print information about this agent.
virtual void AcceptMatlTrades(const std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
The Enrichment place accepted trade Materials in their Inventory.
double FeedAssay()
calculates the feed assay based on the unenriched inventory
virtual std::set< cyclus::BidPortfolio< cyclus::Material >::Ptr > GetMatlBids(cyclus::CommodMap< cyclus::Material >::type &commod_requests)
Responds to each request for this facility's commodity.
virtual void Tick()
Each facility is prompted to do its beginning-of-time-step stuff at the tick of the timer.
void RecordEnrichment_(double natural_u, double swu)
records and enrichment with the cyclus::Recorder
Enrichment(cyclus::Context *ctx)
Constructor for the Enrichment class.
cyclus::toolkit::ResBuf< cyclus::Material > inventory
virtual void GetMatlTrades(const std::vector< cyclus::Trade< cyclus::Material > > &trades, std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
respond to each trade with a material enriched to the appropriate level given this facility's invento...
virtual void Build(cyclus::Agent *parent)
perform module-specific tasks when entering the simulation
void AddMat_(cyclus::Material::Ptr mat)
adds a material into the natural uranium inventory
cyclus::Agent * ConstructEnrichment(cyclus::Context *ctx)
bool SortBids(cyclus::Bid< Material > *i, cyclus::Bid< Material > *j)