Skip to content

Commit

Permalink
Merge pull request #1683 from nuclearkatie/packaging
Browse files Browse the repository at this point in the history
Packaging with Resource Buffer Pop and Push
  • Loading branch information
gonuke committed Mar 26, 2024
2 parents bf6797c + 9fa1d03 commit cdab2fe
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 21 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Since last release
* Adds support for Cython3 (#1636)
* Adds TotalInvTracker, which allows an inventory cap to be set for multiple resource buffers, and is now required for material buy policy (#1646)
* AddMutalReqs and AddReciepe functions and exclusive bids in python API of DRE (#1584)
* Created Package class and optional declaration of packages in input files (#1673, #1699), package id is a member of resources (materials/products) (#1675)
* Created Package class and optional declaration of packages in input files (#1673, #1699), package id is a member of resources (materials/products) (#1675). Can pop resources as packaged from resource buffer, pushing resource onto a buffer defaults to stripping packaging (#1683)
* CI support for Rocky Linux (#1691)
* Added support for a ResBuf to behave as a single bulk storage with mixing & extraction of resources (#1687)

Expand Down
5 changes: 1 addition & 4 deletions src/material.cc
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,7 @@ void Material::Transmute(Composition::Ptr c) {
}

void Material::ChangePackageId(int new_package_id) {
if (ctx_ != NULL) {
throw ValueError("Package Id cannot be changed with NULL context");
}
if (new_package_id == package_id_) {
if (new_package_id == package_id_ || ctx_ == NULL) {
// no change needed
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/material.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,11 @@ class Material: public Resource {
/// DEPRECATED - use non-const comp() function.
Composition::Ptr comp() const;

int package_id();
virtual int package_id();

/// Changes the package id. Checks that the resource fits the package
/// type minimum and maximum mass criteria.
void ChangePackageId(int new_package_id = default_package_id_);
virtual void ChangePackageId(int new_package_id = default_package_id_);

protected:
Material(Context* ctx, double quantity, Composition::Ptr c, int package_id = default_package_id_);
Expand Down
44 changes: 44 additions & 0 deletions src/package.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,50 @@ namespace cyclus {

int Package::next_id_ = 1;

double Package::GetFillMass(Resource::Ptr r) {
if (r->quantity() < fill_min_) {
// less than one pkg of material available
return 0;
}

std::vector<Resource::Ptr> rs;
Resource::Ptr r_pkgd;
double fill_mass;
if (strategy_ == "first") {
fill_mass = fill_max_;
} else if (strategy_ == "equal") {
int num_min_fill = std::floor(r->quantity() / fill_min_);
int num_max_fill = std::ceil(r->quantity() / fill_max_);
if (num_min_fill >= num_max_fill) {
// all material can fit in a package
double fill_mass = r->quantity() / num_max_fill;
} else {
// some material will remain unpackaged, fill up as many max packages as possible
fill_mass = fill_max_;
}
}
return fill_mass;
}

template <class T>
std::vector<typename T::Ptr> Package::PackageResource(typename T::Ptr r) {
std::vector<typename T::Ptr> rs_pkgd;
typename T::Ptr r_pkgd;

double fill_mass = GetFillMass(r);
if (fill_mass ==0) {
return rs_pkgd;
}

while (r->quantity() > fill_min_) {
double pkg_fill = std::min(r->quantity(), fill_mass);
r_pkgd = boost::dynamic_pointer_cast<T>(r->ExtractRes(pkg_fill));
r_pkgd->ChangePackageId(id_);
rs_pkgd.push_back(r_pkgd);
}
return rs_pkgd;
}

Package::Ptr Package::Create() {
Ptr p(new Package());
return p;
Expand Down
26 changes: 26 additions & 0 deletions src/package.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

#include <limits>
#include <string>
#include <vector>
#include <cmath>
#include <boost/shared_ptr.hpp>
#include "resource.h"

namespace cyclus {

Expand All @@ -13,6 +16,29 @@ class Package {
public:
typedef boost::shared_ptr<Package> Ptr;

/// Returns optimal fill mass for a resource to be packaged. Can be used
/// to determine how to respond to requests for material, and to actually
/// package and send off trades.
/// Packaging strategy "first" simply fills the packages one by one to the
/// maximum fill. Therefore, it should always try to max fill.
/// Packaging strategy "equal" tries to fill all packages to the same mass.
/// This tries to find the optimal number and fill mass of packages given
/// the packaging limitations. It does this by calculating bounding fills,
/// floor(quantity/fill_min) and ceiling(quantity/fill_max).
/// There might be a scenario where there is no solution, i.e. an integer
/// number of packages cannot be filled with no remainder. In this case,
/// the most effective fill strategy is to fill to the max. Numeric example:
/// quantity = 5, fill_min = 3, fill_max = 4. num_min_fill = floor(5/3) = 1,
/// num_max_fill = ceil(5/4) = 2. num_min_fill < num_max_fill, so fill to
/// the max.
double GetFillMass(Resource::Ptr r);

/// Repackages a single resource into a package. If some quantity of the
/// resource cannot be packaged using the given packaging strategy and
/// restrictions, the remainder is left in the resource object.
template <class T>
std::vector<typename T::Ptr> PackageResource(typename T::Ptr r);

// create a new package type with default values
static Ptr Create();

Expand Down
6 changes: 3 additions & 3 deletions src/product.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ class Product : public Resource {
/// @throws ValueError 'other' resource is of different quality
void Absorb(Product::Ptr other);

// Returns the package id.
int package_id();
/// Returns the package id.
virtual int package_id();

/// Changes the product's package id
void ChangePackageId(int new_package_id);
virtual void ChangePackageId(int new_package_id = default_package_id_);

private:
/// @param ctx the simulation context
Expand Down
6 changes: 6 additions & 0 deletions src/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ class Resource {
/// @param res pointer to a resource to be absorbed by this resource
virtual void Absorb(Ptr res) { throw Error("cannot absorb resource type " + this->type()); };

/// Returns the package id.
virtual int package_id() { return default_package_id_; };

/// Changes the product's package id
virtual void ChangePackageId(int new_package_id = default_package_id_ ) {};

protected:
const static int default_package_id_ = 1;
private:
Expand Down
40 changes: 30 additions & 10 deletions src/toolkit/res_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ typedef std::vector<Product::Ptr> ProdVec;
template <class T>
class ResBuf {
public:
ResBuf(bool is_bulk=false) : cap_(INFINITY), qty_(0), is_bulk_(is_bulk) { }
ResBuf(bool is_bulk=false, bool unpackaged=true) : cap_(INFINITY), qty_(0), is_bulk_(is_bulk), unpackaged_(unpackaged) { }

virtual ~ResBuf() {}

Expand Down Expand Up @@ -101,16 +101,15 @@ class ResBuf {
/// Returns true if there are no resources in the buffer.
inline bool empty() const { return rs_.empty(); }

/// Pops and returns the specified quantity from the buffer as a single
/// resource object.
/// Pops and returns the specified quantity from the buffer as a vector of
/// resources.
/// Resources are split if necessary in order to pop the exact quantity
/// requested (within eps_rsrc()). Resources are retrieved in the order they
/// were pushed (i.e. oldest first) and are squashed into a single object
/// when returned.
/// were pushed (i.e. oldest first).
///
/// @throws ValueError the specified pop quantity is larger than the
/// buffer's current inventory.
typename T::Ptr Pop(double qty) {
std::vector<typename T::Ptr> PopVector(double qty) {
if (qty > this->quantity()) {
std::stringstream ss;
ss << std::setprecision(17) << "removal quantity " << qty
Expand Down Expand Up @@ -143,7 +142,17 @@ class ResBuf {

UpdateQty();

return Squash(rs);
return rs;
}

/// Pops and returns the specified quantity from the buffer as a single
/// resource object.
/// Resources are split if necessary in order to pop the exact quantity
/// requested (within eps_rsrc()). Resources are retrieved in the order they
/// were pushed (i.e. oldest first) and are squashed into a single object
/// when returned.
typename T::Ptr Pop(double qty) {
return Squash(PopVector(qty));
}

/// Same behavior as Pop(double) except a non-zero eps may be specified. eps
Expand All @@ -161,7 +170,7 @@ class ResBuf {
return Squash(PopN(count()));
}
return Pop(qty);
}
}

/// Pops the specified number of resource objects from the buffer.
/// Resources are not split and are retrieved in the order they were
Expand Down Expand Up @@ -241,8 +250,8 @@ class ResBuf {
/// @throws ValueError the pushing of the given resource object would cause
/// the buffer to exceed its capacity.
///
/// @throws KeyError the resource object to be pushed is already present in
/// the buffer.
/// @throws KeyError the resource object to be pushed is already present
/// in the buffer.
void Push(Resource::Ptr r) {
typename T::Ptr m = boost::dynamic_pointer_cast<T>(r);
if (m == NULL) {
Expand All @@ -255,7 +264,12 @@ class ResBuf {
} else if (rs_present_.count(m) == 1) {
throw KeyError("duplicate resource push attempted");
}

if (!is_bulk_ || rs_.size() == 0) {
// strip package id and set as default
if (unpackaged_) {
m->ChangePackageId();
}
rs_.push_back(m);
rs_present_.insert(m);
} else {
Expand Down Expand Up @@ -305,6 +319,9 @@ class ResBuf {

for (int i = 0; i < rss.size(); i++) {
if (!is_bulk_ || rs_.size() == 0) {
if (unpackaged_) {
rss[i]->ChangePackageId();
}
rs_.push_back(rss[i]);
rs_present_.insert(rss[i]);
} else {
Expand Down Expand Up @@ -340,6 +357,9 @@ class ResBuf {

/// Whether materials should be stored as a single squashed item or as individual resource objects
bool is_bulk_;
/// Whether materials should be stripped of their packaging before being
/// pushed onto the resbuf. If res_buf is bulk, this is assumed true.
bool unpackaged_;

/// List of constituent resource objects forming the buffer's inventory
std::list<typename T::Ptr> rs_;
Expand Down
3 changes: 3 additions & 0 deletions src/toolkit/res_manip.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Product::Ptr Squash(std::vector<Product::Ptr> ps) {
for (int i = 1; i < ps.size(); ++i) {
p->Absorb(ps[i]);
}
// squash always removes package id (results in default packaging)
p->ChangePackageId();
return p;
}

Expand All @@ -25,6 +27,7 @@ Material::Ptr Squash(std::vector<Material::Ptr> ms) {
for (int i = 1; i < ms.size(); ++i) {
m->Absorb(ms[i]);
}
m->ChangePackageId();
return m;
}

Expand Down
2 changes: 1 addition & 1 deletion src/xml_file_loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ void XMLFileLoader::LoadPackages() {
std::string name = cyclus::OptionalQuery<std::string>(qe, "name", "default");
CLOG(LEV_DEBUG3) << "loading package: " << name;

double fill_min = cyclus::OptionalQuery<double>(qe, "fill_min", 0);
double fill_min = cyclus::OptionalQuery<double>(qe, "fill_min", eps());
double fill_max = cyclus::OptionalQuery<double>(qe, "fill_max", std::numeric_limits<double>::max());

std::string strategy = cyclus::OptionalQuery<std::string>(qe, "strategy", "first");
Expand Down

0 comments on commit cdab2fe

Please sign in to comment.