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