Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add random behavior for size of sink request #550

Merged
merged 6 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 46 additions & 9 deletions src/sink.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Sink::~Sink() {}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Sink::EnterNotify() {
cyclus::Facility::EnterNotify();
LOG(cyclus::LEV_INFO4, "SnkFac") << " using random behavior " << random_size_type;

if (in_commod_prefs.size() == 0) {
for (int i = 0; i < in_commods.size(); ++i) {
Expand All @@ -52,6 +53,10 @@ void Sink::EnterNotify() {
<< " values, expected " << in_commods.size();
throw cyclus::ValueError(ss.str());
}
/// Create first requestAmt. Only used in testing, as a simulation will
/// overwrite this on Tick()
SetRequestAmt();

RecordPosition();
}

Expand Down Expand Up @@ -85,17 +90,21 @@ Sink::GetMatlRequests() {

std::set<RequestPortfolio<Material>::Ptr> ports;
RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
double amt = RequestAmt();
Material::Ptr mat;

/// for testing
if (requestAmt > SpaceAvailable()) {
SetRequestAmt();
}

if (recipe_name.empty()) {
mat = cyclus::NewBlankMaterial(amt);
mat = cyclus::NewBlankMaterial(requestAmt);
} else {
Composition::Ptr rec = this->context()->GetRecipe(recipe_name);
mat = cyclus::Material::CreateUntracked(amt, rec);
mat = cyclus::Material::CreateUntracked(requestAmt, rec);
}

if (amt > cyclus::eps()) {
if (requestAmt > cyclus::eps()) {
std::vector<Request<Material>*> mutuals;
for (int i = 0; i < in_commods.size(); i++) {
mutuals.push_back(port->AddRequest(mat, this, in_commods[i], in_commod_prefs[i]));
Expand All @@ -118,16 +127,15 @@ Sink::GetGenRsrcRequests() {
std::set<RequestPortfolio<Product>::Ptr> ports;
RequestPortfolio<Product>::Ptr
port(new RequestPortfolio<Product>());
double amt = RequestAmt();

if (amt > cyclus::eps()) {
CapacityConstraint<Product> cc(amt);
if (requestAmt > cyclus::eps()) {
CapacityConstraint<Product> cc(requestAmt);
port->AddConstraint(cc);

std::vector<std::string>::const_iterator it;
for (it = in_commods.begin(); it != in_commods.end(); ++it) {
std::string quality = ""; // not clear what this should be..
Product::Ptr rsrc = Product::CreateUntracked(amt, quality);
Product::Ptr rsrc = Product::CreateUntracked(requestAmt, quality);
port->AddRequest(rsrc, this, *it);
}

Expand Down Expand Up @@ -164,9 +172,15 @@ void Sink::Tick() {
using std::vector;
LOG(cyclus::LEV_INFO3, "SnkFac") << prototype() << " is ticking {";

double requestAmt = RequestAmt();
SetRequestAmt();

LOG(cyclus::LEV_INFO3, "SnkFac") << prototype() << " has default request amount " << requestAmt;

// inform the simulation about what the sink facility will be requesting
if (requestAmt > cyclus::eps()) {
LOG(cyclus::LEV_INFO4, "SnkFac") << prototype()
<< " has request amount " << requestAmt
<< " kg of " << in_commods[0] << ".";
for (vector<string>::iterator commod = in_commods.begin();
commod != in_commods.end();
commod++) {
Expand Down Expand Up @@ -205,6 +219,29 @@ void Sink::RecordPosition() {
->Record();
}

void Sink::SetRequestAmt() {
double amt = SpaceAvailable();
if (amt < cyclus::eps()) {
requestAmt = 0;
}

if (random_size_type == "None") {
requestAmt = amt;
}
else if (random_size_type == "UniformReal") {
requestAmt = context()->random_uniform_real(0, amt);
}
else if (random_size_type == "NormalReal") {
requestAmt = context()->random_normal_real(amt * random_size_mean,
amt * random_size_stddev,
0, amt);
}
else {
requestAmt = amt;
}
return;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
extern "C" cyclus::Agent* ConstructSink(cyclus::Context* ctx) {
return new Sink(ctx);
Expand Down
46 changes: 45 additions & 1 deletion src/sink.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ class Sink
const std::vector< std::pair<cyclus::Trade<cyclus::Product>,
cyclus::Product::Ptr> >& responses);

/// @brief SinkFacilities update request amount using random behavior
virtual void SetRequestAmt();

/// add a commodity to the set of input commodities
/// @param name the commodity name
inline void AddCommodity(std::string name) { in_commods.push_back(name); }
Expand All @@ -87,7 +90,7 @@ class Sink
inline double InventorySize() const { return inventory.quantity(); }

/// determines the amount to request
inline double RequestAmt() const {
inline double SpaceAvailable() const {
return std::min(capacity, std::max(0.0, inventory.space()));
}

Expand All @@ -107,6 +110,7 @@ class Sink
input_commodity_preferences() const { return in_commod_prefs; }

private:
double requestAmt;
/// all facilities must have at least one input commodity
#pragma cyclus var {"tooltip": "input commodities", \
"doc": "commodities that the sink facility accepts", \
Expand Down Expand Up @@ -154,6 +158,46 @@ class Sink
#pragma cyclus var {'capacity': 'max_inv_size'}
cyclus::toolkit::ResBuf<cyclus::Resource> inventory;

/// random status (size of request)
#pragma cyclus var {"default": "None", \
"tooltip": "type of random behavior when setting the " \
"size of the request", \
"uitype": "combobox", \
"uilabel": "Random Size", \
"categorical": ["None", "UniformReal", "UniformInt", "NormalReal", "NormalInt"], \
"doc": "type of random behavior to use. Default None, " \
"other options are 'UniformReal', 'UniformInt', " \
"'NormalReal', and 'NormalInt'"}
std::string random_size_type;

// random size mean (as a fraction of available space)
#pragma cyclus var {"default": 1.0, \
"tooltip": "fraction of available space to determine the mean", \
"uilabel": "Random Size Mean", \
"uitype": "range", \
"range": [0.0, 1e299], \
"doc": "When a normal distribution is used to determine the " \
"size of the request, this is the fraction of available " \
"space to use as the mean. Default 1.0. Note " \
"that values significantly above 1 without a " \
"correspondingly large std dev may result in " \
"inefficient use of the random number generator."}
double random_size_mean;

// random size std dev (as a fraction of available space)
#pragma cyclus var {"default": 0.1, \
"tooltip": "fraction of available space to determine the std dev", \
"uilabel": "Random Size Std Dev", \
"uitype": "range", \
"range": [0.0, 1e299], \
"doc": "When a normal distribution is used to determine the " \
"size of the request, this is the fraction of available " \
"space to use as the standard deviation. Default 0.1"}
double random_size_stddev;


// random status (frequencing/timing of request)

#pragma cyclus var { \
"default": 0.0, \
"uilabel": "Geographical latitude in degrees as a double", \
Expand Down
74 changes: 71 additions & 3 deletions src/sink_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ TEST_F(SinkTest, InitialState) {
EXPECT_DOUBLE_EQ(0.0, src_facility->InventorySize());
EXPECT_DOUBLE_EQ(capacity_, src_facility->Capacity());
EXPECT_DOUBLE_EQ(inv_, src_facility->MaxInventorySize());
EXPECT_DOUBLE_EQ(capacity_, src_facility->RequestAmt());
EXPECT_DOUBLE_EQ(capacity_, src_facility->SpaceAvailable());
EXPECT_DOUBLE_EQ(0.0, src_facility->InventorySize());
std::string arr[] = {commod1_, commod2_};
std::vector<std::string> vexp (arr, arr + sizeof(arr) / sizeof(arr[0]) );
Expand All @@ -66,7 +66,7 @@ TEST_F(SinkTest, Clone) {
EXPECT_DOUBLE_EQ(0.0, cloned_fac->InventorySize());
EXPECT_DOUBLE_EQ(capacity_, cloned_fac->Capacity());
EXPECT_DOUBLE_EQ(inv_, cloned_fac->MaxInventorySize());
EXPECT_DOUBLE_EQ(capacity_, cloned_fac->RequestAmt());
EXPECT_DOUBLE_EQ(capacity_, cloned_fac->SpaceAvailable());
std::string arr[] = {commod1_, commod2_};
std::vector<std::string> vexp (arr, arr + sizeof(arr) / sizeof(arr[0]) );
EXPECT_EQ(vexp, cloned_fac->input_commodities());
Expand Down Expand Up @@ -104,7 +104,7 @@ TEST_F(SinkTest, DISABLED_XMLInit) {
EXPECT_EQ(vexp, fac.input_commodities());
EXPECT_DOUBLE_EQ(capacity_, fac.Capacity());
EXPECT_DOUBLE_EQ(inv_, fac.MaxInventorySize());
EXPECT_DOUBLE_EQ(capacity_, fac.RequestAmt());
EXPECT_DOUBLE_EQ(capacity_, fac.SpaceAvailable());
EXPECT_DOUBLE_EQ(0.0, fac.InventorySize());
}

Expand Down Expand Up @@ -342,6 +342,74 @@ TEST_F(SinkTest, PositionInitialize2) {

}

TEST_F(SinkTest, RandomUniform) {
using cyclus::QueryResult;
using cyclus::Cond;

std::string config =
" <in_commods>"
" <val>commods_1</val>"
" </in_commods>"
" <capacity>10</capacity>"
" <random_size_type>UniformReal</random_size_type> ";

int simdur = 1;
cyclus::MockSim sim(cyclus::AgentSpec
(":cycamore:Sink"), config, simdur);
sim.AddSource("commods_1").capacity(10).Finalize();
int id = sim.Run();

QueryResult qr = sim.db().Query("Resources", NULL);
EXPECT_EQ(qr.rows.size(), 1);
EXPECT_NEAR(qr.GetVal<double>("Quantity"), 9.41273, 0.0001);
}

TEST_F(SinkTest, RandomNormal) {
using cyclus::QueryResult;
using cyclus::Cond;

std::string config =
" <in_commods>"
" <val>commods_1</val>"
" </in_commods>"
" <capacity>10</capacity>"
" <random_size_type>NormalReal</random_size_type> ";

int simdur = 1;
cyclus::MockSim sim(cyclus::AgentSpec
(":cycamore:Sink"), config, simdur);
sim.AddSource("commods_1").capacity(10).Finalize();
int id = sim.Run();

QueryResult qr = sim.db().Query("Resources", NULL);
EXPECT_EQ(qr.rows.size(), 1);
EXPECT_NEAR(qr.GetVal<double>("Quantity"), 9.60929, 0.0001);
}

TEST_F(SinkTest, RandomNormalWithMeanSttdev) {
using cyclus::QueryResult;
using cyclus::Cond;

std::string config =
" <in_commods>"
" <val>commods_1</val>"
" </in_commods>"
" <capacity>10</capacity>"
" <random_size_type>NormalReal</random_size_type> "
" <random_size_mean>0.5</random_size_mean> "
" <random_size_stddev>0.2</random_size_stddev> ";

int simdur = 1;
cyclus::MockSim sim(cyclus::AgentSpec
(":cycamore:Sink"), config, simdur);
sim.AddSource("commods_1").capacity(10).Finalize();
int id = sim.Run();

QueryResult qr = sim.db().Query("Resources", NULL);
EXPECT_EQ(qr.rows.size(), 1);
EXPECT_NEAR(qr.GetVal<double>("Quantity"), 1.52979, 0.0001);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cyclus::Agent* SinkConstructor(cyclus::Context* ctx) {
return new cycamore::Sink(ctx);
Expand Down