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