Skip to content

Commit 2bbf4bc

Browse files
authored
Merge pull request #613 from nuclearkatie/source_packaging
Source can package
2 parents 1a670d2 + a9d8f20 commit 2bbf4bc

File tree

5 files changed

+185
-19
lines changed

5 files changed

+185
-19
lines changed

CHANGELOG.rst

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Since last release
77

88
**Added:**
99
* Added package parameter to storage (#603, #612)
10+
* Added package parameter to source (#613)
1011

1112
**Changed:**
1213

src/source.cc

+84-18
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,22 @@ Source::Source(cyclus::Context* ctx)
1313
inventory_size(std::numeric_limits<double>::max()),
1414
latitude(0.0),
1515
longitude(0.0),
16+
package(cyclus::Package::unpackaged_name()),
17+
transport_unit(cyclus::TransportUnit::unrestricted_name()),
1618
coordinates(latitude, longitude) {}
1719

1820
Source::~Source() {}
1921

2022
void Source::InitFrom(Source* m) {
2123
#pragma cyclus impl initfromcopy cycamore::Source
2224
cyclus::toolkit::CommodityProducer::Copy(m);
23-
RecordPosition();
2425
}
2526

2627
void Source::InitFrom(cyclus::QueryableBackend* b) {
2728
#pragma cyclus impl initfromdb cycamore::Source
2829
namespace tk = cyclus::toolkit;
2930
tk::CommodityProducer::Add(tk::Commodity(outcommod),
3031
tk::CommodInfo(throughput, throughput));
31-
RecordPosition();
3232
}
3333

3434
std::string Source::str() {
@@ -47,18 +47,39 @@ std::string Source::str() {
4747
<< " commod producer members: "
4848
<< " produces " << outcommod << "?: " << ans
4949
<< " throughput: " << cyclus::toolkit::CommodityProducer::Capacity(outcommod)
50+
<< " with package type: " << package
51+
<< " and transport unit type: " << transport_unit
5052
<< " cost: " << cyclus::toolkit::CommodityProducer::Cost(outcommod);
5153
return ss.str();
5254
}
5355

56+
void Source::EnterNotify() {
57+
using cyclus::CompMap;
58+
using cyclus::Composition;
59+
using cyclus::Material;
60+
cyclus::Facility::EnterNotify();
61+
RecordPosition();
62+
63+
// create all source inventory and place into buf
64+
cyclus::Material::Ptr all_inv;
65+
Composition::Ptr blank_comp = Composition::CreateFromMass(CompMap());
66+
67+
all_inv = (outrecipe.empty() || context() == NULL) ? \
68+
Material::Create(this, inventory_size, blank_comp) : \
69+
Material::Create(this, inventory_size, context()->GetRecipe(outrecipe));
70+
inventory.Push(all_inv);
71+
}
72+
5473
std::set<cyclus::BidPortfolio<cyclus::Material>::Ptr> Source::GetMatlBids(
5574
cyclus::CommodMap<cyclus::Material>::type& commod_requests) {
5675
using cyclus::BidPortfolio;
5776
using cyclus::CapacityConstraint;
5877
using cyclus::Material;
78+
using cyclus::Package;
5979
using cyclus::Request;
80+
using cyclus::TransportUnit;
6081

61-
double max_qty = std::min(throughput, inventory_size);
82+
double max_qty = std::min(throughput, inventory.quantity());
6283
cyclus::toolkit::RecordTimeSeries<double>("supply"+outcommod, this,
6384
max_qty);
6485
LOG(cyclus::LEV_INFO3, "Source") << prototype() << " is bidding up to "
@@ -79,11 +100,35 @@ std::set<cyclus::BidPortfolio<cyclus::Material>::Ptr> Source::GetMatlBids(
79100
Request<Material>* req = *it;
80101
Material::Ptr target = req->target();
81102
double qty = std::min(target->quantity(), max_qty);
82-
Material::Ptr m = Material::CreateUntracked(qty, target->comp());
83-
if (!outrecipe.empty()) {
84-
m = Material::CreateUntracked(qty, context()->GetRecipe(outrecipe));
103+
104+
// calculate packaging
105+
double bid_qty = context()->GetPackage(package)->GetFillMass(qty);
106+
int n_full_bids = static_cast<int>(std::floor(qty / bid_qty));
107+
Package::ExceedsSplitLimits(n_full_bids);
108+
109+
std::vector<double> bids;
110+
bids.assign(n_full_bids, bid_qty);
111+
112+
double remaining_qty = qty - (n_full_bids * bid_qty);
113+
if ((remaining_qty > cyclus::eps()) && (remaining_qty >= context()->GetPackage(package)->fill_min())) {
114+
bids.push_back(remaining_qty);
115+
}
116+
117+
// calculate transport units
118+
int shippable_pkgs = context()->GetTransportUnit(transport_unit)
119+
->MaxShippablePackages(bids.size());
120+
if (shippable_pkgs < bids.size()) {
121+
bids.erase(bids.begin() + shippable_pkgs, bids.end());
122+
}
123+
124+
std::vector<double>::iterator bit;
125+
for (bit = bids.begin(); bit != bids.end(); ++bit) {
126+
Material::Ptr m;
127+
m = outrecipe.empty() ? \
128+
Material::CreateUntracked(*bit, target->comp()) : \
129+
Material::CreateUntracked(*bit, context()->GetRecipe(outrecipe));
130+
port->AddBid(req, m, this);
85131
}
86-
port->AddBid(req, m, this);
87132
}
88133

89134
CapacityConstraint<Material> cc(max_qty);
@@ -99,20 +144,41 @@ void Source::GetMatlTrades(
99144
using cyclus::Material;
100145
using cyclus::Trade;
101146

147+
int shippable_trades = context()->GetTransportUnit(transport_unit)
148+
->MaxShippablePackages(trades.size());
149+
102150
std::vector<Trade<Material> >::const_iterator it;
103151
for (it = trades.begin(); it != trades.end(); ++it) {
104-
double qty = it->amt;
105-
inventory_size -= qty;
106-
107-
Material::Ptr response;
108-
if (!outrecipe.empty()) {
109-
response = Material::Create(this, qty, context()->GetRecipe(outrecipe));
110-
} else {
111-
response = Material::Create(this, qty, it->request->target()->comp());
152+
if (shippable_trades > 0) {
153+
double qty = it->amt;
154+
155+
Material::Ptr m = inventory.Pop(qty);
156+
157+
std::vector<Material::Ptr> m_pkgd = m->Package<Material>(context()->GetPackage(package));
158+
159+
if (m->quantity() > cyclus::eps()) {
160+
// If not all material is packaged successfully, return the excess
161+
// amount to the inventory
162+
inventory.Push(m);
163+
}
164+
165+
Material::Ptr response;
166+
if (m_pkgd.size() > 0) {
167+
// Because we responded (in GetMatlBids) with individual package-sized
168+
// bids, each packaged vector is guaranteed to have no more than one
169+
// package in it. This single packaged resource is our response
170+
response = m_pkgd[0];
171+
shippable_trades -= 1;
172+
}
173+
174+
if (outrecipe.empty() && response->comp() != it->request->target()->comp()) {
175+
response->Transmute(it->request->target()->comp());
176+
}
177+
178+
responses.push_back(std::make_pair(*it, response));
179+
LOG(cyclus::LEV_INFO5, "Source") << prototype() << " sent an order"
180+
<< " for " << response->quantity() << " of " << outcommod;
112181
}
113-
responses.push_back(std::make_pair(*it, response));
114-
LOG(cyclus::LEV_INFO5, "Source") << prototype() << " sent an order"
115-
<< " for " << qty << " of " << outcommod;
116182
}
117183
}
118184

src/source.h

+29
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ class Source : public cyclus::Facility,
6767
GetMatlBids(cyclus::CommodMap<cyclus::Material>::type&
6868
commod_requests);
6969

70+
virtual void EnterNotify();
71+
7072
virtual void GetMatlTrades(
7173
const std::vector< cyclus::Trade<cyclus::Material> >& trades,
7274
std::vector<std::pair<cyclus::Trade<cyclus::Material>,
@@ -116,6 +118,28 @@ class Source : public cyclus::Facility,
116118
}
117119
double throughput;
118120

121+
#pragma cyclus var { \
122+
"default": "unpackaged", \
123+
"tooltip": "name of package to provide material in", \
124+
"doc": "Name of package that this source provides. Offers will only be" \
125+
"made in packagable quantities of material.", \
126+
"uilabel": "Output Package Type", \
127+
"uitype": "package", \
128+
}
129+
std::string package;
130+
131+
#pragma cyclus var { \
132+
"default": "unrestricted", \
133+
"tooltip": "name of transport unit to ship packages in", \
134+
"doc": "Name of transport unit that this source uses to ship packages of " \
135+
"material. Offers will only be made in shippable quantities of " \
136+
"packages. Optional if packaging is used, but use of transport " \
137+
"units requires packaging type to also be set", \
138+
"uilabel": "Output Transport Unit Type", \
139+
"uitype": "transportunit", \
140+
}
141+
std::string transport_unit;
142+
119143
#pragma cyclus var { \
120144
"default": 0.0, \
121145
"uilabel": "Geographical latitude in degrees as a double", \
@@ -132,9 +156,14 @@ class Source : public cyclus::Facility,
132156
}
133157
double longitude;
134158

159+
#pragma cyclus var { \
160+
"tooltip":"Material buffer"}
161+
cyclus::toolkit::ResBuf<cyclus::Material> inventory;
162+
135163
cyclus::toolkit::Position coordinates;
136164

137165
void RecordPosition();
166+
void SetPackage();
138167
};
139168

140169
} // namespace cycamore

src/source_tests.cc

+68
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ void SourceTest::SetUp() {
1515
trader = tc.trader();
1616
InitParameters();
1717
SetUpSource();
18+
src_facility->EnterNotify();
1819
}
1920

2021
void SourceTest::TearDown() {
@@ -24,6 +25,8 @@ void SourceTest::TearDown() {
2425
void SourceTest::InitParameters() {
2526
commod = "commod";
2627
recipe_name = "recipe";
28+
package_name = "testpackage";
29+
tu_name = "testtu";
2730
capacity = 5; // some magic number..
2831

2932
recipe = cyclus::Composition::CreateFromAtom(cyclus::CompMap());
@@ -64,6 +67,8 @@ TEST_F(SourceTest, AddBids) {
6467
boost::shared_ptr< ExchangeContext<Material> >
6568
ec = GetContext(nreqs, commod);
6669

70+
src_facility->EnterNotify();
71+
6772
std::set<BidPortfolio<Material>::Ptr> ports =
6873
src_facility->GetMatlBids(ec.get()->commod_requests);
6974

@@ -153,6 +158,69 @@ TEST_F(SourceTest, Longitude) {
153158

154159
}
155160

161+
TEST_F(SourceTest, Package) {
162+
using cyclus::QueryResult;
163+
using cyclus::Cond;
164+
165+
std::string config =
166+
"<outcommod>commod</outcommod>"
167+
"<package>testpackage</package>"
168+
"<throughput>5</throughput>";
169+
170+
int simdur = 3;
171+
cyclus::MockSim sim(cyclus::AgentSpec (":cycamore:Source"), config, simdur);
172+
173+
sim.context()->AddPackage(package_name, 3, 4, "first");
174+
package = sim.context()->GetPackage(package_name);
175+
176+
sim.AddSink("commod").Finalize();
177+
178+
EXPECT_NO_THROW(sim.Run());
179+
180+
QueryResult qr_tr = sim.db().Query("Transactions", NULL);
181+
EXPECT_EQ(qr_tr.rows.size(), 3);
182+
183+
std::vector<Cond> conds;
184+
conds.push_back(Cond("PackageName", "==", package->name()));
185+
QueryResult qr_res = sim.db().Query("Resources", &conds);
186+
187+
EXPECT_EQ(qr_res.rows.size(), 3);
188+
}
189+
190+
TEST_F(SourceTest, TransportUnit) {
191+
using cyclus::QueryResult;
192+
using cyclus::Cond;
193+
194+
std::string config =
195+
"<outcommod>commod</outcommod>"
196+
"<package>testpackage</package>"
197+
"<transport_unit>testtu</transport_unit>"
198+
"<throughput>10</throughput>";
199+
200+
int simdur = 2;
201+
cyclus::MockSim sim(cyclus::AgentSpec (":cycamore:Source"), config, simdur);
202+
203+
sim.context()->AddPackage(package_name, 3, 4, "equal");
204+
package = sim.context()->GetPackage(package_name);
205+
sim.context()->AddTransportUnit(tu_name, 2, 2);
206+
tu = sim.context()->GetTransportUnit(tu_name);
207+
208+
sim.AddSink("commod").Finalize();
209+
210+
EXPECT_NO_THROW(sim.Run());
211+
212+
QueryResult qr_tr = sim.db().Query("Transactions", NULL);
213+
EXPECT_EQ(qr_tr.rows.size(), 4);
214+
215+
std::vector<Cond> conds;
216+
conds.push_back(Cond("PackageName", "==", package->name()));
217+
QueryResult qr_res = sim.db().Query("Resources", &conds);
218+
219+
EXPECT_EQ(qr_res.rows.size(), 4);
220+
221+
QueryResult qr_allres = sim.db().Query("Resources", NULL);
222+
}
223+
156224
boost::shared_ptr< cyclus::ExchangeContext<cyclus::Material> >
157225
SourceTest::GetContext(int nreqs, std::string commod) {
158226
using cyclus::Material;

src/source_tests.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ class SourceTest : public ::testing::Test {
1919
cyclus::TestContext tc;
2020
TestFacility* trader;
2121
cycamore::Source* src_facility;
22-
std::string commod, recipe_name;
22+
std::string commod, recipe_name, package_name, tu_name;
2323
double capacity;
2424
cyclus::Composition::Ptr recipe;
25+
cyclus::Package::Ptr package;
26+
cyclus::TransportUnit::Ptr tu;
2527

2628
virtual void SetUp();
2729
virtual void TearDown();

0 commit comments

Comments
 (0)