Skip to content

Commit

Permalink
Merge pull request #613 from nuclearkatie/source_packaging
Browse files Browse the repository at this point in the history
Source can package
  • Loading branch information
gonuke authored Jul 18, 2024
2 parents 1a670d2 + a9d8f20 commit 2bbf4bc
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Since last release

**Added:**
* Added package parameter to storage (#603, #612)
* Added package parameter to source (#613)

**Changed:**

Expand Down
102 changes: 84 additions & 18 deletions src/source.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ Source::Source(cyclus::Context* ctx)
inventory_size(std::numeric_limits<double>::max()),
latitude(0.0),
longitude(0.0),
package(cyclus::Package::unpackaged_name()),
transport_unit(cyclus::TransportUnit::unrestricted_name()),
coordinates(latitude, longitude) {}

Source::~Source() {}

void Source::InitFrom(Source* m) {
#pragma cyclus impl initfromcopy cycamore::Source
cyclus::toolkit::CommodityProducer::Copy(m);
RecordPosition();
}

void Source::InitFrom(cyclus::QueryableBackend* b) {
#pragma cyclus impl initfromdb cycamore::Source
namespace tk = cyclus::toolkit;
tk::CommodityProducer::Add(tk::Commodity(outcommod),
tk::CommodInfo(throughput, throughput));
RecordPosition();
}

std::string Source::str() {
Expand All @@ -47,18 +47,39 @@ std::string Source::str() {
<< " commod producer members: "
<< " produces " << outcommod << "?: " << ans
<< " throughput: " << cyclus::toolkit::CommodityProducer::Capacity(outcommod)
<< " with package type: " << package
<< " and transport unit type: " << transport_unit
<< " cost: " << cyclus::toolkit::CommodityProducer::Cost(outcommod);
return ss.str();
}

void Source::EnterNotify() {
using cyclus::CompMap;
using cyclus::Composition;
using cyclus::Material;
cyclus::Facility::EnterNotify();
RecordPosition();

// create all source inventory and place into buf
cyclus::Material::Ptr all_inv;
Composition::Ptr blank_comp = Composition::CreateFromMass(CompMap());

all_inv = (outrecipe.empty() || context() == NULL) ? \
Material::Create(this, inventory_size, blank_comp) : \
Material::Create(this, inventory_size, context()->GetRecipe(outrecipe));
inventory.Push(all_inv);
}

std::set<cyclus::BidPortfolio<cyclus::Material>::Ptr> Source::GetMatlBids(
cyclus::CommodMap<cyclus::Material>::type& commod_requests) {
using cyclus::BidPortfolio;
using cyclus::CapacityConstraint;
using cyclus::Material;
using cyclus::Package;
using cyclus::Request;
using cyclus::TransportUnit;

double max_qty = std::min(throughput, inventory_size);
double max_qty = std::min(throughput, inventory.quantity());
cyclus::toolkit::RecordTimeSeries<double>("supply"+outcommod, this,
max_qty);
LOG(cyclus::LEV_INFO3, "Source") << prototype() << " is bidding up to "
Expand All @@ -79,11 +100,35 @@ std::set<cyclus::BidPortfolio<cyclus::Material>::Ptr> Source::GetMatlBids(
Request<Material>* req = *it;
Material::Ptr target = req->target();
double qty = std::min(target->quantity(), max_qty);
Material::Ptr m = Material::CreateUntracked(qty, target->comp());
if (!outrecipe.empty()) {
m = Material::CreateUntracked(qty, context()->GetRecipe(outrecipe));

// calculate packaging
double bid_qty = context()->GetPackage(package)->GetFillMass(qty);
int n_full_bids = static_cast<int>(std::floor(qty / bid_qty));
Package::ExceedsSplitLimits(n_full_bids);

std::vector<double> bids;
bids.assign(n_full_bids, bid_qty);

double remaining_qty = qty - (n_full_bids * bid_qty);
if ((remaining_qty > cyclus::eps()) && (remaining_qty >= context()->GetPackage(package)->fill_min())) {
bids.push_back(remaining_qty);
}

// calculate transport units
int shippable_pkgs = context()->GetTransportUnit(transport_unit)
->MaxShippablePackages(bids.size());
if (shippable_pkgs < bids.size()) {
bids.erase(bids.begin() + shippable_pkgs, bids.end());
}

std::vector<double>::iterator bit;
for (bit = bids.begin(); bit != bids.end(); ++bit) {
Material::Ptr m;
m = outrecipe.empty() ? \
Material::CreateUntracked(*bit, target->comp()) : \
Material::CreateUntracked(*bit, context()->GetRecipe(outrecipe));
port->AddBid(req, m, this);
}
port->AddBid(req, m, this);
}

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

int shippable_trades = context()->GetTransportUnit(transport_unit)
->MaxShippablePackages(trades.size());

std::vector<Trade<Material> >::const_iterator it;
for (it = trades.begin(); it != trades.end(); ++it) {
double qty = it->amt;
inventory_size -= qty;

Material::Ptr response;
if (!outrecipe.empty()) {
response = Material::Create(this, qty, context()->GetRecipe(outrecipe));
} else {
response = Material::Create(this, qty, it->request->target()->comp());
if (shippable_trades > 0) {
double qty = it->amt;

Material::Ptr m = inventory.Pop(qty);

std::vector<Material::Ptr> m_pkgd = m->Package<Material>(context()->GetPackage(package));

if (m->quantity() > cyclus::eps()) {
// If not all material is packaged successfully, return the excess
// amount to the inventory
inventory.Push(m);
}

Material::Ptr response;
if (m_pkgd.size() > 0) {
// Because we responded (in GetMatlBids) with individual package-sized
// bids, each packaged vector is guaranteed to have no more than one
// package in it. This single packaged resource is our response
response = m_pkgd[0];
shippable_trades -= 1;
}

if (outrecipe.empty() && response->comp() != it->request->target()->comp()) {
response->Transmute(it->request->target()->comp());
}

responses.push_back(std::make_pair(*it, response));
LOG(cyclus::LEV_INFO5, "Source") << prototype() << " sent an order"
<< " for " << response->quantity() << " of " << outcommod;
}
responses.push_back(std::make_pair(*it, response));
LOG(cyclus::LEV_INFO5, "Source") << prototype() << " sent an order"
<< " for " << qty << " of " << outcommod;
}
}

Expand Down
29 changes: 29 additions & 0 deletions src/source.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class Source : public cyclus::Facility,
GetMatlBids(cyclus::CommodMap<cyclus::Material>::type&
commod_requests);

virtual void EnterNotify();

virtual void GetMatlTrades(
const std::vector< cyclus::Trade<cyclus::Material> >& trades,
std::vector<std::pair<cyclus::Trade<cyclus::Material>,
Expand Down Expand Up @@ -116,6 +118,28 @@ class Source : public cyclus::Facility,
}
double throughput;

#pragma cyclus var { \
"default": "unpackaged", \
"tooltip": "name of package to provide material in", \
"doc": "Name of package that this source provides. Offers will only be" \
"made in packagable quantities of material.", \
"uilabel": "Output Package Type", \
"uitype": "package", \
}
std::string package;

#pragma cyclus var { \
"default": "unrestricted", \
"tooltip": "name of transport unit to ship packages in", \
"doc": "Name of transport unit that this source uses to ship packages of " \
"material. Offers will only be made in shippable quantities of " \
"packages. Optional if packaging is used, but use of transport " \
"units requires packaging type to also be set", \
"uilabel": "Output Transport Unit Type", \
"uitype": "transportunit", \
}
std::string transport_unit;

#pragma cyclus var { \
"default": 0.0, \
"uilabel": "Geographical latitude in degrees as a double", \
Expand All @@ -132,9 +156,14 @@ class Source : public cyclus::Facility,
}
double longitude;

#pragma cyclus var { \
"tooltip":"Material buffer"}
cyclus::toolkit::ResBuf<cyclus::Material> inventory;

cyclus::toolkit::Position coordinates;

void RecordPosition();
void SetPackage();
};

} // namespace cycamore
Expand Down
68 changes: 68 additions & 0 deletions src/source_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ void SourceTest::SetUp() {
trader = tc.trader();
InitParameters();
SetUpSource();
src_facility->EnterNotify();
}

void SourceTest::TearDown() {
Expand All @@ -24,6 +25,8 @@ void SourceTest::TearDown() {
void SourceTest::InitParameters() {
commod = "commod";
recipe_name = "recipe";
package_name = "testpackage";
tu_name = "testtu";
capacity = 5; // some magic number..

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

src_facility->EnterNotify();

std::set<BidPortfolio<Material>::Ptr> ports =
src_facility->GetMatlBids(ec.get()->commod_requests);

Expand Down Expand Up @@ -153,6 +158,69 @@ TEST_F(SourceTest, Longitude) {

}

TEST_F(SourceTest, Package) {
using cyclus::QueryResult;
using cyclus::Cond;

std::string config =
"<outcommod>commod</outcommod>"
"<package>testpackage</package>"
"<throughput>5</throughput>";

int simdur = 3;
cyclus::MockSim sim(cyclus::AgentSpec (":cycamore:Source"), config, simdur);

sim.context()->AddPackage(package_name, 3, 4, "first");
package = sim.context()->GetPackage(package_name);

sim.AddSink("commod").Finalize();

EXPECT_NO_THROW(sim.Run());

QueryResult qr_tr = sim.db().Query("Transactions", NULL);
EXPECT_EQ(qr_tr.rows.size(), 3);

std::vector<Cond> conds;
conds.push_back(Cond("PackageName", "==", package->name()));
QueryResult qr_res = sim.db().Query("Resources", &conds);

EXPECT_EQ(qr_res.rows.size(), 3);
}

TEST_F(SourceTest, TransportUnit) {
using cyclus::QueryResult;
using cyclus::Cond;

std::string config =
"<outcommod>commod</outcommod>"
"<package>testpackage</package>"
"<transport_unit>testtu</transport_unit>"
"<throughput>10</throughput>";

int simdur = 2;
cyclus::MockSim sim(cyclus::AgentSpec (":cycamore:Source"), config, simdur);

sim.context()->AddPackage(package_name, 3, 4, "equal");
package = sim.context()->GetPackage(package_name);
sim.context()->AddTransportUnit(tu_name, 2, 2);
tu = sim.context()->GetTransportUnit(tu_name);

sim.AddSink("commod").Finalize();

EXPECT_NO_THROW(sim.Run());

QueryResult qr_tr = sim.db().Query("Transactions", NULL);
EXPECT_EQ(qr_tr.rows.size(), 4);

std::vector<Cond> conds;
conds.push_back(Cond("PackageName", "==", package->name()));
QueryResult qr_res = sim.db().Query("Resources", &conds);

EXPECT_EQ(qr_res.rows.size(), 4);

QueryResult qr_allres = sim.db().Query("Resources", NULL);
}

boost::shared_ptr< cyclus::ExchangeContext<cyclus::Material> >
SourceTest::GetContext(int nreqs, std::string commod) {
using cyclus::Material;
Expand Down
4 changes: 3 additions & 1 deletion src/source_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ class SourceTest : public ::testing::Test {
cyclus::TestContext tc;
TestFacility* trader;
cycamore::Source* src_facility;
std::string commod, recipe_name;
std::string commod, recipe_name, package_name, tu_name;
double capacity;
cyclus::Composition::Ptr recipe;
cyclus::Package::Ptr package;
cyclus::TransportUnit::Ptr tu;

virtual void SetUp();
virtual void TearDown();
Expand Down

0 comments on commit 2bbf4bc

Please sign in to comment.