Skip to content

Commit

Permalink
Merge pull request cyclus#1750 from nuclearkatie/transportation
Browse files Browse the repository at this point in the history
Transport units
  • Loading branch information
gonuke authored Jun 23, 2024
2 parents 57729fb + 5e03a51 commit 3066938
Show file tree
Hide file tree
Showing 15 changed files with 596 additions and 62 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Since last release
====================

**Added:**
* Added TransportUnits (#1750)

**Changed:**

Expand Down
13 changes: 12 additions & 1 deletion share/cyclus-flat.rng.in
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
</element>
</zeroOrMore>

<zeroOrMore>
<zeroOrMore>
<element name="package">
<interleave>
<element name="name"><text/></element>
Expand All @@ -158,6 +158,17 @@ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
</element>
</zeroOrMore>

<zeroOrMore>
<element name="transportunit">
<interleave>
<element name="name"><text/></element>
<element name="fill_min"><data type="nonNegativeInteger"/></element>
<element name="fill_max"><data type="nonNegativeInteger"/></element>
<element name="strategy"><text/></element>
</interleave>
</element>
</zeroOrMore>

</interleave>
</element><!-- end of simulation -->
</start>
Expand Down
11 changes: 11 additions & 0 deletions share/cyclus.rng.in
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,17 @@ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
</element>
</zeroOrMore>

<zeroOrMore>
<element name="transportunit">
<interleave>
<element name="name"><text/></element>
<element name="fill_min"><data type="nonNegativeInteger"/></element>
<element name="fill_max"><data type="nonNegativeInteger"/></element>
<element name="strategy"><text/></element>
</interleave>
</element>
</zeroOrMore>

</interleave> </element>

</start>
Expand Down
36 changes: 36 additions & 0 deletions src/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,42 @@ Package::Ptr Context::GetPackage(std::string name) {
return packages_[name];
}

void Context::AddTransportUnit(std::string name, int fill_min, int fill_max,
std::string strategy) {
if (transport_units_.count(name) == 0) {
TransportUnit::Ptr tu = TransportUnit::Create(name, fill_min, fill_max,
strategy);
transport_units_[name] = tu;
RecordTransportUnit(tu);
} else {
throw KeyError("TransportUnit " + name + " already exists!");
}
}

void Context::RecordTransportUnit(TransportUnit::Ptr tu) {
NewDatum("TransportUnit")
->AddVal("TransportUnitName", tu->name())
->AddVal("FillMin", tu->fill_min())
->AddVal("FillMax", tu->fill_max())
->AddVal("Strategy", tu->strategy())
->Record();
}

/// Retrieve a registered transport unit
TransportUnit::Ptr Context::GetTransportUnit(std::string name) {
if (name == TransportUnit::unrestricted_name()) {
return TransportUnit::unrestricted();
}
if (transport_units_.size() == 0 ) {
throw KeyError("No user-created transport units exist");
}
if (transport_units_.count(name) == 0) {
throw KeyError("Invalid transport unit name " + name);
}
return transport_units_[name];
}


void Context::InitSim(SimInfo si) {
NewDatum("Info")
->AddVal("Handle", si.handle)
Expand Down
14 changes: 14 additions & 0 deletions src/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,19 @@ class Context {
/// Retrieve a registered package.
Package::Ptr GetPackage(std::string name);

/// Adds a transport unit type to a simulation-wide accessible list.
/// Agents should NOT add their own transport units.
void AddTransportUnit(std::string name, int fill_min = 0,
int fill_max = std::numeric_limits<int>::max(),
std::string strategy = "first");

/// Records transport unit information. Should be used first on unrestricted,
/// then to record user-declared transport units
void RecordTransportUnit(TransportUnit::Ptr);

/// Retrieve a registered transport unit.
TransportUnit::Ptr GetTransportUnit(std::string name);

int random();

/// Generates a random number on the range [0,1)]
Expand Down Expand Up @@ -356,6 +369,7 @@ class Context {
std::map<std::string, Agent*> protos_;
std::map<std::string, Composition::Ptr> recipes_;
std::map<std::string, Package::Ptr> packages_;
std::map<std::string, TransportUnit::Ptr> transport_units_;
std::set<Agent*> agent_list_;
std::set<Trader*> traders_;
std::map<std::string, int> n_prototypes_;
Expand Down
93 changes: 93 additions & 0 deletions src/package.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,99 @@ Package::Package(std::string name, double fill_min, double fill_max,
throw ValueError("can't create a new package with name 'unpackaged'");
}
}
if (strategy != "first" && strategy != "equal") {
throw ValueError("Invalid strategy for package: " + strategy_);
}
}

TransportUnit::Ptr TransportUnit::unrestricted_ = NULL;

TransportUnit::Ptr TransportUnit::Create(std::string name, int fill_min, int fill_max, std::string strategy) {
if (fill_min < 0 || fill_max < 0) {
throw ValueError("fill_min and fill_max must be non-negative");
}
else if (fill_min > fill_max) {
throw ValueError("fill_min must be less than or equal to fill_max");
}
Ptr t(new TransportUnit(name, fill_min, fill_max, strategy));
return t;
}

// singleton pattern:
// if the static member is not yet set, create a new object
// otherwise return the object that already exists
TransportUnit::Ptr& TransportUnit::unrestricted() {
if (!unrestricted_) {
unrestricted_ = Ptr(new TransportUnit(unrestricted_name_));
}
return unrestricted_;
}

int TransportUnit::GetTransportUnitFill(int qty) {
if (qty < fill_min_) {
// less than one TransportUnit of material available
return 0;
}

if (strategy_ == "first") {
return fill_max_;
} else if (strategy_ == "equal" || strategy_ == "hybrid") {
// int division automatically rounds down. don't need floor in min, and
// get ceil by hand instead
int num_at_min_fill = qty / fill_min_;
int num_at_max_fill = (qty + fill_max_ - 1) / fill_max_;

if (num_at_min_fill >= num_at_max_fill) {
// all material *might* fit transport units. However, this is more
// challenging than packages because transport units are discrete.
double dbl_fill_mass = (double)qty / (double)num_at_max_fill;
return std::floor(dbl_fill_mass);
}
// some material will remain unrestricted, fill up as many transport
// units as possible. Or, perfect fill is possible but not with integer
// fill (see above).
}
return fill_max_;
}

int TransportUnit::MaxShippablePackages(int pkgs) {
int TU_fill;
int shippable = 0;

if (pkgs == 0 || pkgs < fill_min_) {
return 0;

} else if (name_ == unrestricted_name_) {
return pkgs;

} else if (strategy_ == "first" || strategy_ == "equal") {
TU_fill = GetTransportUnitFill(pkgs);
if (TU_fill == 0) {
return 0;
}
shippable = std::min(pkgs, (pkgs / TU_fill) * TU_fill);
return shippable;

} else if (strategy_ == "hybrid") {
while ((pkgs > 0) && (pkgs >= fill_min_)) {
TU_fill = GetTransportUnitFill(pkgs);
shippable += TU_fill;
pkgs -= TU_fill;
}
return shippable;
}
}

TransportUnit::TransportUnit(std::string name, int fill_min, int fill_max, std::string strategy) :
name_(name), fill_min_(fill_min), fill_max_(fill_max), strategy_(strategy) {
if (name == unrestricted_name_) {
if (unrestricted_) {
throw ValueError("can't create a new transport unit with name 'unrestricted'");
}
}
if (strategy != "first" && strategy != "equal" && strategy != "hybrid") {
throw ValueError("Invalid strategy for transport unit: " + strategy_);
}
}

} // namespace cyclus
70 changes: 69 additions & 1 deletion src/package.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

namespace cyclus {

/// Packager is a class that packages materials into discrete items in ways that mimic realistic nuclear material handling. Packages will eventually be a required parameter of resources.
/// Package is a class that packages materials into discrete items in ways
// that mimic realistic nuclear material handling. Package is a parameter
// of materials and products, with default unpackaged
class Package {
public:
typedef boost::shared_ptr<Package> Ptr;
Expand Down Expand Up @@ -68,6 +70,72 @@ class Package {
std::string strategy_;
};

/// TransportUnit is a class that can be used in conjunction with packages to
/// restrict the amount of material that can be traded between facilities.
/// Unlike Packages, TransportUnits are not a property of resources. They are
/// simply applied at the response to request for bids phase and then the trade
/// execution to determine whether the available number of packages is
/// allowable given the TransportUnit parameters. Default is unrestricted
/// Strategy "first" simply fill transport units one by one to max fill
/// Strategy "equal" tries to fill all transport units with the
/// Strategy "hybrid" is iterative, recursively filling transport units
/// with the max fill until the remaining quantity can be filled with the
/// at least the min fill. This is the most efficient strategy
class TransportUnit {
public:
typedef boost::shared_ptr<TransportUnit> Ptr;

/// create a new transport unit type. Should be called by the context only
/// (see Context::AddTransportUnit), unless you want an untracked transport
/// unit type (which you probably don't)
static Ptr Create(std::string name, int fill_min = 0,
int fill_max = std::numeric_limits<int>::max(),
std::string strategy = "first");

/// Returns number of packages for each transport unit.
/// same number of packages
int GetTransportUnitFill(int qty);

/// Returns the max number of transport units that can be shipped from the
/// available quantity
int MaxShippablePackages(int pkgs);

// returns transport unit name
std::string name() const { return name_; }
// returns transport unit fill min
int fill_min() const { return fill_min_; }
// returns transport unit fill max
int fill_max() const { return fill_max_; }
// returns transport unit strategy
std::string strategy() const { return strategy_; }

// returns the unrestricted id (1)
static int unrestricted_id() { return unrestricted_id_; }

// returns the unrestricted transport unit name
static std::string unrestricted_name() { return unrestricted_name_; }

// returns the unrestricted singleton object
static Ptr& unrestricted();

private:
TransportUnit(std::string name,
int fill_min = 0,
int fill_max = std::numeric_limits<int>::max(),
std::string strategy = "hybrid");

static const int unrestricted_id_ = 1;
static constexpr char unrestricted_name_[13] = "unrestricted";
static Ptr unrestricted_;
static int next_tranport_unit_id_;

std::string name_;
int id_;
int fill_min_;
int fill_max_;
std::string strategy_;
};

} // namespace cyclus

#endif // CYCLUS_SRC_PACKAGE_H_
Loading

0 comments on commit 3066938

Please sign in to comment.