improved simulation stuff
This commit is contained in:
parent
d2da0dd619
commit
8ad6fc0a30
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace sim::coolant
|
||||||
|
{
|
||||||
|
|
||||||
|
template <class A>
|
||||||
|
class valve
|
||||||
|
{
|
||||||
|
A* a;
|
||||||
|
|
||||||
|
const double max;
|
||||||
|
const double pressure;
|
||||||
|
|
||||||
|
double state = 0;
|
||||||
|
double rate = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
constexpr valve(A& a, double max, double pressure) : a(&a), max(max), pressure(pressure)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr double get_state() const
|
||||||
|
{
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void set_state(double v)
|
||||||
|
{
|
||||||
|
if(v > 1) v = 1;
|
||||||
|
if(v < 0) v = 0;
|
||||||
|
state = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void open(double v)
|
||||||
|
{
|
||||||
|
set_state(state + v);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void update(double secs)
|
||||||
|
{
|
||||||
|
rate = a->extract_steam(secs, state * max, pressure) / secs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& o, const valve& v)
|
||||||
|
{
|
||||||
|
o << "Opened: " << (v.state * 100) << " %\n";
|
||||||
|
o << "Rate: " << v.rate << " g/s\n";
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
80
src/main.cpp
80
src/main.cpp
|
@ -6,6 +6,7 @@
|
||||||
#include "reactor/coolant/heater.hpp"
|
#include "reactor/coolant/heater.hpp"
|
||||||
#include "reactor/coolant/vessel.hpp"
|
#include "reactor/coolant/vessel.hpp"
|
||||||
#include "coolant/fluid_t.hpp"
|
#include "coolant/fluid_t.hpp"
|
||||||
|
#include "coolant/valve.hpp"
|
||||||
#include "display.hpp"
|
#include "display.hpp"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
@ -14,6 +15,9 @@
|
||||||
#include <curses.h>
|
#include <curses.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
const bool do_graphics = true;
|
||||||
|
const bool do_clock = true;
|
||||||
|
|
||||||
unsigned long get_now()
|
unsigned long get_now()
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
@ -23,29 +27,38 @@ unsigned long get_now()
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 rand(rd());
|
||||||
|
|
||||||
|
if(do_graphics)
|
||||||
|
{
|
||||||
initscr();
|
initscr();
|
||||||
cbreak();
|
cbreak();
|
||||||
noecho();
|
noecho();
|
||||||
keypad(stdscr, TRUE);
|
keypad(stdscr, TRUE);
|
||||||
nodelay(stdscr, TRUE);
|
nodelay(stdscr, TRUE);
|
||||||
curs_set(0);
|
curs_set(0);
|
||||||
|
}
|
||||||
|
|
||||||
sim::reactor::coolant::vessel vessel(200, 400, sim::coolant::WATER);
|
sim::reactor::coolant::vessel vessel(200, 400, sim::coolant::WATER);
|
||||||
sim::reactor::reactor<5, 5> reactor = sim::reactor::builder<5, 5>(
|
sim::reactor::reactor<5, 5> reactor = sim::reactor::builder<5, 5>(
|
||||||
sim::reactor::fuel::fuel_rod(2000, 4000),
|
sim::reactor::fuel::fuel_rod(2000, 4000),
|
||||||
sim::reactor::control::control_rod(10000, 1),
|
sim::reactor::control::control_rod(vessel, 10000, 1),
|
||||||
sim::reactor::coolant::pipe(vessel), {
|
sim::reactor::coolant::pipe(vessel), {
|
||||||
"# ##",
|
"#C#C#",
|
||||||
"#FCF ",
|
"CFCFC",
|
||||||
" CHC ",
|
"#C#C#",
|
||||||
" FCF#",
|
"CFCFC",
|
||||||
"## #"
|
"#C#C#"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sim::coolant::valve<sim::reactor::coolant::vessel> valve(vessel, 1, 101000);
|
||||||
|
|
||||||
double secs = 0;
|
double secs = 0;
|
||||||
long clock = get_now();
|
long clock = get_now();
|
||||||
double speed = 1;
|
double speed = 1;
|
||||||
int framerate = 100;
|
int framerate = 100;
|
||||||
|
int steps_extra = 1;
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
|
@ -80,29 +93,23 @@ secs: ss << s << "s\n";
|
||||||
ss << "Speed: " << speed << "x\n\n";
|
ss << "Speed: " << speed << "x\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
int skip = 1;
|
for(int i = 0; i < steps_extra; i++)
|
||||||
|
|
||||||
while(speed / framerate / skip > 1)
|
|
||||||
{
|
{
|
||||||
skip *= 2;
|
double dt = speed / framerate / steps_extra;
|
||||||
}
|
reactor.update(rand, dt);
|
||||||
|
|
||||||
for(int i = 0; i < skip; i++)
|
|
||||||
{
|
|
||||||
double dt = speed / framerate / skip;
|
|
||||||
|
|
||||||
reactor.update(dt);
|
|
||||||
vessel.update();
|
vessel.update();
|
||||||
|
valve.update(dt);
|
||||||
vessel.extract_steam(dt, 0.01, 101000);
|
secs += dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
secs += speed / framerate;
|
|
||||||
|
|
||||||
ss << "Vessel\n" << vessel << "\n";
|
ss << "Vessel\n" << vessel << "\n";
|
||||||
|
ss << "Steam Valve\n" << valve << "\n";
|
||||||
|
|
||||||
|
if(do_graphics)
|
||||||
|
{
|
||||||
erase();
|
erase();
|
||||||
display::draw_text(1, 0, ss.str().c_str());
|
display::draw_text(1, 0, ss.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
const int X = 1, Y = 30;
|
const int X = 1, Y = 30;
|
||||||
const int W = 36, H = 11;
|
const int W = 36, H = 11;
|
||||||
|
@ -110,7 +117,8 @@ secs: ss << s << "s\n";
|
||||||
for(int x = 0; x < reactor.width; x++)
|
for(int x = 0; x < reactor.width; x++)
|
||||||
for(int y = 0; y < reactor.height; y++)
|
for(int y = 0; y < reactor.height; y++)
|
||||||
{
|
{
|
||||||
sim::reactor::rod* r = reactor.rods[x][y];
|
int id = y * reactor.width + x;
|
||||||
|
sim::reactor::rod* r = reactor.rods[id];
|
||||||
|
|
||||||
if(!r->should_display())
|
if(!r->should_display())
|
||||||
{
|
{
|
||||||
|
@ -123,23 +131,30 @@ secs: ss << s << "s\n";
|
||||||
int px = X + (H - 1) * y;
|
int px = X + (H - 1) * y;
|
||||||
int py = Y + (W - 1) * x;
|
int py = Y + (W - 1) * x;
|
||||||
|
|
||||||
|
if(do_graphics)
|
||||||
|
{
|
||||||
display::draw_text(px + 1, py + 2, ss.str().c_str());
|
display::draw_text(px + 1, py + 2, ss.str().c_str());
|
||||||
display::draw_box(px, py, H, W);
|
display::draw_box(px, py, H, W);
|
||||||
|
}
|
||||||
|
|
||||||
if(r->should_select() && x == reactor.cursor_x && y == reactor.cursor_y)
|
if(do_graphics && r->should_select() && id == reactor.cursor)
|
||||||
{
|
{
|
||||||
display::draw_text(px + 1, py + W - 5, "[ ]");
|
display::draw_text(px + 1, py + W - 5, "[ ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r->is_selected())
|
if(do_graphics && r->is_selected())
|
||||||
{
|
{
|
||||||
display::draw_text(px + 1, py + W - 4, "#");
|
display::draw_text(px + 1, py + W - 4, "#");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh();
|
int c = 0;
|
||||||
|
|
||||||
int c = getch();
|
if(do_graphics)
|
||||||
|
{
|
||||||
|
refresh();
|
||||||
|
c = getch();
|
||||||
|
}
|
||||||
|
|
||||||
switch(c)
|
switch(c)
|
||||||
{
|
{
|
||||||
|
@ -150,10 +165,10 @@ secs: ss << s << "s\n";
|
||||||
reactor.move_cursor(1);
|
reactor.move_cursor(1);
|
||||||
break;
|
break;
|
||||||
case KEY_UP:
|
case KEY_UP:
|
||||||
reactor.update_selected(0.01);
|
reactor.update_selected(1);
|
||||||
break;
|
break;
|
||||||
case KEY_DOWN:
|
case KEY_DOWN:
|
||||||
reactor.update_selected(-0.01);
|
reactor.update_selected(-1);
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
reactor.toggle_selected();
|
reactor.toggle_selected();
|
||||||
|
@ -164,8 +179,16 @@ secs: ss << s << "s\n";
|
||||||
case 'g':
|
case 'g':
|
||||||
speed /= 10;
|
speed /= 10;
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
valve.open(0.001);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
valve.open(-0.001);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(do_clock)
|
||||||
|
{
|
||||||
long now = get_now();
|
long now = get_now();
|
||||||
|
|
||||||
while(clock + 1e6 / framerate > now)
|
while(clock + 1e6 / framerate > now)
|
||||||
|
@ -176,6 +199,7 @@ secs: ss << s << "s\n";
|
||||||
|
|
||||||
clock += 1e6 / framerate;
|
clock += 1e6 / framerate;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,9 @@
|
||||||
|
|
||||||
using namespace sim::reactor::control;
|
using namespace sim::reactor::control;
|
||||||
|
|
||||||
control_rod::control_rod(double limit, double max)
|
control_rod::control_rod(coolant::vessel& v, double limit, double max) : coolant::pipe(v), limit(limit), max(max)
|
||||||
{
|
{
|
||||||
this->limit = limit;
|
|
||||||
this->max = max;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void control_rod::display(std::ostream& o) const
|
void control_rod::display(std::ostream& o) const
|
||||||
|
@ -17,11 +16,6 @@ void control_rod::display(std::ostream& o) const
|
||||||
o << "Use: " << absorbed << " / " << limit << " mol\n";
|
o << "Use: " << absorbed << " / " << limit << " mol\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
double control_rod::get_k(val_t type) const
|
|
||||||
{
|
|
||||||
return 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
void control_rod::set_reactivity(double a)
|
void control_rod::set_reactivity(double a)
|
||||||
{
|
{
|
||||||
inserted = 1 - a;
|
inserted = 1 - a;
|
||||||
|
@ -31,13 +25,16 @@ void control_rod::update(double secs)
|
||||||
{
|
{
|
||||||
update_rod(secs);
|
update_rod(secs);
|
||||||
|
|
||||||
double m = 1 - std::pow(0.5, (1 - absorbed / limit) * inserted * max);
|
double k = (1 - absorbed / limit) * inserted * max;
|
||||||
|
double m = 1 - std::pow(0.5, secs * -std::log2(1 - k));
|
||||||
double r_fast = vals[val_t::N_FAST] * m;
|
double r_fast = vals[val_t::N_FAST] * m;
|
||||||
double r_slow = vals[val_t::N_SLOW] * m;
|
double r_slow = vals[val_t::N_SLOW] * m;
|
||||||
|
|
||||||
vals[val_t::N_FAST] -= r_fast;
|
vals[val_t::N_FAST] -= r_fast;
|
||||||
vals[val_t::N_SLOW] -= r_slow;
|
vals[val_t::N_SLOW] -= r_slow;
|
||||||
absorbed += r_fast + r_slow;
|
absorbed += r_fast + r_slow;
|
||||||
|
|
||||||
|
update_pipe(secs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void control_rod::update_selected(double a)
|
void control_rod::update_selected(double a)
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../rod.hpp"
|
#include "../coolant/pipe.hpp"
|
||||||
|
|
||||||
namespace sim::reactor::control
|
namespace sim::reactor::control
|
||||||
{
|
{
|
||||||
|
|
||||||
class control_rod : public sim::reactor::rod
|
class control_rod : public sim::reactor::coolant::pipe
|
||||||
{
|
{
|
||||||
|
const double limit;
|
||||||
|
const double max;
|
||||||
|
|
||||||
double inserted = 1;
|
double inserted = 1;
|
||||||
double absorbed = 0;
|
double absorbed = 0;
|
||||||
double limit;
|
|
||||||
double max;
|
|
||||||
|
|
||||||
virtual double get_k(sim::reactor::rod::val_t type) const;
|
|
||||||
virtual void display(std::ostream& o) const;
|
virtual void display(std::ostream& o) const;
|
||||||
|
|
||||||
virtual const char* get_name() const { return "Control Rod"; }
|
virtual const char* get_name() const { return "Control Rod"; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
control_rod(double limit, double max);
|
control_rod(coolant::vessel& v, double limit, double max);
|
||||||
|
|
||||||
virtual void update(double secs);
|
virtual void update(double secs);
|
||||||
void set_reactivity(double a);
|
void set_reactivity(double a);
|
||||||
|
|
|
@ -26,9 +26,8 @@ void graphite_rod::update(double secs)
|
||||||
{
|
{
|
||||||
update_rod(secs);
|
update_rod(secs);
|
||||||
|
|
||||||
double v = vals[val_t::N_FAST];
|
vals[val_t::N_SLOW] = vals[val_t::N_FAST];
|
||||||
vals_in[val_t::N_FAST] -= v;
|
vals[val_t::N_FAST] = 0;
|
||||||
vals_in[val_t::N_SLOW] += v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void graphite_rod::update_selected(double a)
|
void graphite_rod::update_selected(double a)
|
||||||
|
|
|
@ -10,10 +10,10 @@ class graphite_rod : public sim::reactor::rod
|
||||||
{
|
{
|
||||||
double inserted = 0;
|
double inserted = 0;
|
||||||
|
|
||||||
virtual double get_k(sim::reactor::rod::val_t type) const;
|
|
||||||
virtual void display(std::ostream& o) const;
|
virtual void display(std::ostream& o) const;
|
||||||
|
|
||||||
virtual const char* get_name() const { return "Graphite Rod"; }
|
virtual const char* get_name() const { return "Graphite Rod"; }
|
||||||
|
virtual double get_k(val_t type) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ void heater::update(double secs)
|
||||||
{
|
{
|
||||||
update_rod(secs);
|
update_rod(secs);
|
||||||
|
|
||||||
vals_in[val_t::HEAT] += rate * secs;
|
vals[val_t::HEAT] += rate * secs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void heater::update_selected(double a)
|
void heater::update_selected(double a)
|
||||||
|
@ -15,11 +15,6 @@ void heater::update_selected(double a)
|
||||||
rate += a;
|
rate += a;
|
||||||
}
|
}
|
||||||
|
|
||||||
double heater::get_k(sim::reactor::rod::val_t type) const
|
|
||||||
{
|
|
||||||
return 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
void heater::display(std::ostream& o) const
|
void heater::display(std::ostream& o) const
|
||||||
{
|
{
|
||||||
o << "Rate: " << rate << " C/s\n";
|
o << "Rate: " << rate << " C/s\n";
|
||||||
|
|
|
@ -10,10 +10,10 @@ class heater : public sim::reactor::rod
|
||||||
{
|
{
|
||||||
double rate = 0;
|
double rate = 0;
|
||||||
|
|
||||||
virtual double get_k(sim::reactor::rod::val_t type) const;
|
|
||||||
virtual void display(std::ostream& o) const;
|
virtual void display(std::ostream& o) const;
|
||||||
|
|
||||||
virtual const char* get_name() const { return "Heater"; }
|
virtual const char* get_name() const { return "Heater"; }
|
||||||
|
virtual double get_k(val_t type) const { return 0.5; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -16,16 +16,14 @@ double pipe::get_k(val_t type) const
|
||||||
|
|
||||||
void pipe::update(double secs)
|
void pipe::update(double secs)
|
||||||
{
|
{
|
||||||
double v;
|
|
||||||
|
|
||||||
update_rod(secs);
|
update_rod(secs);
|
||||||
|
update_pipe(secs);
|
||||||
v = vessel->add_heat(vals[val_t::HEAT]);
|
}
|
||||||
steam = vals[val_t::HEAT] - v;
|
|
||||||
vals[val_t::HEAT] = v;
|
void pipe::update_pipe(double secs)
|
||||||
|
{
|
||||||
v = vals[val_t::N_FAST];
|
vals[val_t::HEAT] = vessel->add_heat(vals[val_t::HEAT]);
|
||||||
vals_in[val_t::N_FAST] -= v;
|
vals[val_t::N_SLOW] += vals[val_t::N_FAST];
|
||||||
vals_in[val_t::N_SLOW] += v;
|
vals[val_t::N_FAST] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,20 +9,22 @@ namespace sim::reactor::coolant
|
||||||
|
|
||||||
class pipe : public sim::reactor::rod
|
class pipe : public sim::reactor::rod
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
coolant::vessel* vessel;
|
coolant::vessel* vessel;
|
||||||
double steam;
|
double steam;
|
||||||
|
|
||||||
virtual double get_k(sim::reactor::rod::val_t type) const;
|
virtual double get_k(sim::reactor::rod::val_t type) const;
|
||||||
|
|
||||||
virtual const char* get_name() const { return "Coolant"; }
|
virtual const char* get_name() const { return "Coolant"; }
|
||||||
|
void update_pipe(double secs);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
pipe(coolant::vessel& v);
|
pipe(coolant::vessel& v);
|
||||||
|
|
||||||
virtual bool should_display() const { return true; }
|
virtual bool should_display() const { return true; }
|
||||||
|
|
||||||
virtual void update(double secs);
|
virtual void update(double secs);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ void vessel::update()
|
||||||
|
|
||||||
double s = steam + n;
|
double s = steam + n;
|
||||||
double l = fluid.l_to_g(level) - n;
|
double l = fluid.l_to_g(level) - n;
|
||||||
|
double v = fluid.l_to_g(volume);
|
||||||
|
|
||||||
if(l < 0)
|
if(l < 0)
|
||||||
{
|
{
|
||||||
|
@ -28,12 +29,18 @@ void vessel::update()
|
||||||
l = 0;
|
l = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fluid.g_to_l(s) > volume)
|
if(s > v)
|
||||||
{
|
{
|
||||||
s = fluid.l_to_g(volume);
|
s = v;
|
||||||
l = 0;
|
l = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(l > v)
|
||||||
|
{
|
||||||
|
l = v;
|
||||||
|
s = 0;
|
||||||
|
}
|
||||||
|
|
||||||
double diff = s - steam;
|
double diff = s - steam;
|
||||||
|
|
||||||
steam = s;
|
steam = s;
|
||||||
|
@ -56,33 +63,22 @@ double vessel::extract_steam(double dt, double a, double p2)
|
||||||
{
|
{
|
||||||
// calculate the mass moved
|
// calculate the mass moved
|
||||||
double p1 = get_pressure();
|
double p1 = get_pressure();
|
||||||
double p = p1 - p2;
|
double p = (p1 - p2) * 0.001; // mPa or g/m/s^2
|
||||||
double m = 1;
|
|
||||||
|
|
||||||
if(p == 0)
|
if(p == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(p < 0)
|
double V = (volume - level) * 0.001; // m^3
|
||||||
{
|
double mass = std::min(dt * a * p / std::sqrt( V * std::abs(p) / steam ), steam);
|
||||||
m = -1;
|
|
||||||
p = -p;
|
|
||||||
|
|
||||||
|
if(std::isnan(mass))
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double V = (volume - level) * 0.001;
|
|
||||||
double v = std::sqrt( V * p / steam );
|
|
||||||
double mass = m * dt * a * p / v;
|
|
||||||
|
|
||||||
if(mass > steam)
|
|
||||||
{
|
|
||||||
mass = steam;
|
|
||||||
}
|
|
||||||
|
|
||||||
steam -= mass;
|
steam -= mass;
|
||||||
|
|
||||||
return mass;
|
return mass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,26 +12,22 @@ void fuel_rod::display(std::ostream& o) const
|
||||||
{
|
{
|
||||||
o << "Fuel: " << s.get_fuel() << " / " << s.get_mass() << " mol\n";
|
o << "Fuel: " << s.get_fuel() << " / " << s.get_mass() << " mol\n";
|
||||||
o << "Efficiency: " << (s.get_efficiency() * 100) << " %\n";
|
o << "Efficiency: " << (s.get_efficiency() * 100) << " %\n";
|
||||||
o << "Energy: +" << s.get_energy() << " C\n";
|
o << "Output: " << s.get_energy() << " W/s\n";
|
||||||
o << "Iodine: " << s.get_i_135() << " mol\n";
|
o << "Iodine: " << s.get_i_135() << " mol\n";
|
||||||
o << "Xenon: " << s.get_xe_135() << " mol\n";
|
o << "Xenon: " << s.get_xe_135() << " mol\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
double fuel_rod::get_k(val_t type) const
|
|
||||||
{
|
|
||||||
return 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fuel_rod::update(double secs)
|
void fuel_rod::update(double secs)
|
||||||
{
|
{
|
||||||
update_rod(secs);
|
update_rod(secs);
|
||||||
|
|
||||||
|
s.clear_energy();
|
||||||
|
s.clear_fast_neutrons();
|
||||||
s.add_slow_neutrons(vals[val_t::N_SLOW]);
|
s.add_slow_neutrons(vals[val_t::N_SLOW]);
|
||||||
|
|
||||||
vals_in[val_t::HEAT] += s.extract_energy();
|
|
||||||
vals_in[val_t::N_FAST] += s.extract_fast_neutrons();
|
|
||||||
vals_in[val_t::N_SLOW] -= vals[val_t::N_SLOW];
|
|
||||||
|
|
||||||
s.update(secs);
|
s.update(secs);
|
||||||
|
|
||||||
|
vals[val_t::HEAT] += s.get_energy() * secs;
|
||||||
|
vals[val_t::N_FAST] += s.get_fast_neutrons();
|
||||||
|
vals[val_t::N_SLOW] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ class fuel_rod : public sim::reactor::rod
|
||||||
{
|
{
|
||||||
sample s;
|
sample s;
|
||||||
|
|
||||||
virtual double get_k(sim::reactor::rod::val_t type) const;
|
virtual double get_k(val_t type) const { return 0.5; }
|
||||||
virtual void display(std::ostream& o) const;
|
virtual void display(std::ostream& o) const;
|
||||||
|
|
||||||
virtual const char* get_name() const { return "Fuel"; }
|
virtual const char* get_name() const { return "Fuel"; }
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include "sample.hpp"
|
#include "sample.hpp"
|
||||||
#include "half_life.hpp"
|
#include "half_life.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace sim::reactor::fuel;
|
using namespace sim::reactor::fuel;
|
||||||
|
|
||||||
static const double NEUTRON_BG = 1e-10;
|
static const double NEUTRON_BG = 1e-10;
|
||||||
|
@ -12,44 +14,11 @@ sample::sample(double fuel, double mass)
|
||||||
this->mass = mass;
|
this->mass = mass;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::absorb_slow_neutrons()
|
|
||||||
{
|
|
||||||
// absorb neutrons
|
|
||||||
double volume = get_volume();
|
|
||||||
double neutrons = slow_neutrons;
|
|
||||||
double neutrons_fuel = neutrons * (fuel / volume);
|
|
||||||
double neutrons_iodine = neutrons * (i_135 / volume);
|
|
||||||
double neutrons_xenon = neutrons * ((xe_135 * Xe_135_M) / volume);
|
|
||||||
double neutrons_total = neutrons;
|
|
||||||
slow_neutrons = 0;
|
|
||||||
|
|
||||||
xe_135 -= neutrons_xenon;
|
|
||||||
i_135 -= neutrons_iodine;
|
|
||||||
fuel -= neutrons_fuel;
|
|
||||||
|
|
||||||
// do the poison
|
|
||||||
te_135 += neutrons_fuel * (1.0 / 50.0);
|
|
||||||
xe_135 -= neutrons_xenon;
|
|
||||||
i_135 -= neutrons_iodine;
|
|
||||||
|
|
||||||
// deal with these edge cases
|
|
||||||
if(xe_135 < 0) { slow_neutrons -= xe_135; xe_135 = 0; }
|
|
||||||
if(i_135 < 0) { slow_neutrons -= i_135; i_135 = 0; }
|
|
||||||
if(fuel < 0) { slow_neutrons -= fuel; fuel = 0; }
|
|
||||||
|
|
||||||
efficiency = neutrons_fuel / neutrons_total;
|
|
||||||
|
|
||||||
// simulate fuel use
|
|
||||||
energy += neutrons_fuel;
|
|
||||||
waste.add_fissile(neutrons_fuel * 6);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void sample::update(double secs)
|
void sample::update(double secs)
|
||||||
{
|
{
|
||||||
double m;
|
double m;
|
||||||
|
|
||||||
// sim::reactor::fuelulate waste and extract products
|
// decay waste and extract products
|
||||||
waste.update(secs);
|
waste.update(secs);
|
||||||
fast_neutrons += waste.extract_neutrons();
|
fast_neutrons += waste.extract_neutrons();
|
||||||
energy += waste.extract_energy();
|
energy += waste.extract_energy();
|
||||||
|
@ -69,27 +38,29 @@ void sample::update(double secs)
|
||||||
te_135 *= m;
|
te_135 *= m;
|
||||||
|
|
||||||
// absorb neutrons
|
// absorb neutrons
|
||||||
slow_neutrons += NEUTRON_BG * secs;
|
double volume = get_volume();
|
||||||
absorb_slow_neutrons();
|
double neutrons = slow_neutrons + NEUTRON_BG * secs;
|
||||||
}
|
double neutrons_fuel = neutrons * (fuel / volume);
|
||||||
|
double neutrons_iodine = neutrons * (i_135 / volume);
|
||||||
|
double neutrons_xenon = neutrons * ((xe_135 * Xe_135_M) / volume);
|
||||||
|
double neutrons_total = neutrons;
|
||||||
|
slow_neutrons = 0;
|
||||||
|
|
||||||
double sample::extract_energy()
|
te_135 += neutrons_fuel * (1.0 / 50.0);
|
||||||
{
|
xe_135 -= neutrons_xenon;
|
||||||
double v = energy;
|
i_135 -= neutrons_iodine;
|
||||||
energy = 0;
|
fuel -= neutrons_fuel;
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
double sample::extract_fast_neutrons()
|
// deal with these edge cases
|
||||||
{
|
if(xe_135 < 0) { slow_neutrons += xe_135; xe_135 = 0; }
|
||||||
double v = fast_neutrons;
|
if(i_135 < 0) { slow_neutrons += i_135; i_135 = 0; }
|
||||||
fast_neutrons = 0;
|
if(fuel < 0) { slow_neutrons += fuel; fuel = 0; }
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sample::add_slow_neutrons(double a)
|
efficiency = neutrons_fuel / neutrons_total;
|
||||||
{
|
|
||||||
slow_neutrons += a;
|
// simulate fuel use
|
||||||
|
energy += neutrons_fuel / secs;
|
||||||
|
waste.add_fissile(neutrons_fuel * 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sample::display(std::ostream& o) const
|
void sample::display(std::ostream& o) const
|
||||||
|
|
|
@ -14,38 +14,41 @@ class sample
|
||||||
|
|
||||||
sim::reactor::fuel::waste waste;
|
sim::reactor::fuel::waste waste;
|
||||||
|
|
||||||
|
// mol
|
||||||
double fuel = 0;
|
double fuel = 0;
|
||||||
double i_135 = 0;
|
double i_135 = 0;
|
||||||
double xe_135 = 0;
|
double xe_135 = 0;
|
||||||
double te_135 = 0;
|
double te_135 = 0;
|
||||||
double mass = 0;
|
double mass = 0;
|
||||||
|
|
||||||
double energy = 0;
|
double energy = 0; // W/s
|
||||||
double fast_neutrons = 0;
|
double fast_neutrons = 0; // mol/s
|
||||||
double slow_neutrons = 0;
|
double slow_neutrons = 0; // mol/s
|
||||||
double efficiency = 0;
|
double efficiency = 0;
|
||||||
|
|
||||||
void display(std::ostream& o) const;
|
void display(std::ostream& o) const;
|
||||||
void absorb_slow_neutrons();
|
void absorb_slow_neutrons(double secs);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
sample(double fuel, double mass);
|
sample(double fuel, double mass);
|
||||||
|
|
||||||
void update(double secs);
|
void update(double secs);
|
||||||
double extract_energy();
|
|
||||||
double extract_fast_neutrons();
|
|
||||||
void add_slow_neutrons(double a);
|
|
||||||
|
|
||||||
constexpr double get_fuel() const { return fuel; }
|
constexpr double get_fuel() const { return fuel; }
|
||||||
constexpr double get_mass() const { return mass; }
|
constexpr double get_mass() const { return mass; }
|
||||||
constexpr double get_energy() const { return energy; }
|
constexpr double get_energy() const { return energy; }
|
||||||
|
constexpr double get_fast_neutrons() const { return fast_neutrons; }
|
||||||
constexpr double get_volume() const { return mass + xe_135 * Xe_135_M; }
|
constexpr double get_volume() const { return mass + xe_135 * Xe_135_M; }
|
||||||
constexpr double get_efficiency() const { return efficiency; }
|
constexpr double get_efficiency() const { return efficiency; }
|
||||||
constexpr double get_te_135() const { return te_135; }
|
constexpr double get_te_135() const { return te_135; }
|
||||||
constexpr double get_i_135() const { return i_135; }
|
constexpr double get_i_135() const { return i_135; }
|
||||||
constexpr double get_xe_135() const { return xe_135; }
|
constexpr double get_xe_135() const { return xe_135; }
|
||||||
|
|
||||||
|
constexpr void clear_energy() { energy = 0; }
|
||||||
|
constexpr void clear_fast_neutrons() { fast_neutrons = 0; }
|
||||||
|
constexpr void add_slow_neutrons(double a) { slow_neutrons += a; }
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& o, const sample& s)
|
friend std::ostream& operator<<(std::ostream& o, const sample& s)
|
||||||
{
|
{
|
||||||
s.display(o);
|
s.display(o);
|
||||||
|
|
|
@ -6,10 +6,10 @@ using namespace sim::reactor::fuel;
|
||||||
|
|
||||||
void waste::update(double secs)
|
void waste::update(double secs)
|
||||||
{
|
{
|
||||||
double hl = 1;
|
|
||||||
double next[waste::N - 1] = {0};
|
double next[waste::N - 1] = {0};
|
||||||
|
double hl = 1;
|
||||||
|
|
||||||
for(int i = 0; i < waste::N - 1; i++)
|
for(int i = 0; i < waste::N - 1; hl *= 2, i++)
|
||||||
{
|
{
|
||||||
double m = 1 - half_life::get(secs, hl);
|
double m = 1 - half_life::get(secs, hl);
|
||||||
double h = high[i] * m;
|
double h = high[i] * m;
|
||||||
|
@ -21,7 +21,6 @@ void waste::update(double secs)
|
||||||
|
|
||||||
neutrons += h;
|
neutrons += h;
|
||||||
energy += h + l;
|
energy += h + l;
|
||||||
hl *= 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < waste::N - 1; i++)
|
for(int i = 0; i < waste::N - 1; i++)
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
#include "rod.hpp"
|
#include "rod.hpp"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <random>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace sim::reactor
|
namespace sim::reactor
|
||||||
{
|
{
|
||||||
|
@ -11,99 +14,113 @@ namespace sim::reactor
|
||||||
template <int W, int H>
|
template <int W, int H>
|
||||||
struct reactor
|
struct reactor
|
||||||
{
|
{
|
||||||
const static int width = W;
|
constexpr const static int width = W;
|
||||||
const static int height = H;
|
constexpr const static int height = H;
|
||||||
|
constexpr const static int size = W*H;
|
||||||
|
|
||||||
std::array<std::array<rod*, H>, W> rods;
|
rod* rods[size];
|
||||||
|
|
||||||
int cursor_x = 0;
|
int cursor = 0;
|
||||||
int cursor_y = 0;
|
|
||||||
|
|
||||||
reactor(std::array<rod*, W * H> rods)
|
reactor(std::array<rod*, size> rods)
|
||||||
{
|
{
|
||||||
for(int y = 0; y < H; y++)
|
for(int i = 0; i < size; i++)
|
||||||
for(int x = 0; x < W; x++)
|
|
||||||
{
|
{
|
||||||
this->rods[x][y] = rods[y * W + x];
|
this->rods[i] = rods[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(double secs)
|
void update(std::mt19937& rand, double secs)
|
||||||
{
|
{
|
||||||
// do interactions
|
int rods_lookup[size];
|
||||||
for(int x = 1; x < W; x++)
|
|
||||||
|
for(int i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
rods[x][0]->interact(rods[x - 1][0], secs);
|
rods_lookup[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int y = 1; y < H; y++)
|
for(int i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
rods[0][y]->interact(rods[0][y - 1], secs);
|
rods[i]->update(secs);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int y = 1; y < H; y++)
|
update_interactions(rand, rods_lookup, secs / 2);
|
||||||
for(int x = 1; x < W; x++)
|
|
||||||
{
|
|
||||||
rod* r = rods[x][y];
|
|
||||||
r->interact(rods[x - 1][y], secs);
|
|
||||||
r->interact(rods[x][y - 1], secs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// do updates
|
void update_selected(int v)
|
||||||
for(int y = 0; y < H; y++)
|
|
||||||
for(int x = 0; x < W; x++)
|
|
||||||
{
|
{
|
||||||
rods[x][y]->update(secs);
|
for(int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
rod* r = rods[i];
|
||||||
|
|
||||||
|
if(r->is_selected())
|
||||||
|
{
|
||||||
|
r->update_rod_selected(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_selected(double v)
|
int move_cursor(int d)
|
||||||
{
|
{
|
||||||
for(int y = 0; y < H; y++)
|
for(int i = 0; i < size; i++)
|
||||||
for(int x = 0; x < W; x++)
|
|
||||||
if(rods[x][y]->is_selected())
|
|
||||||
{
|
{
|
||||||
rods[x][y]->update_selected(v);
|
cursor = (cursor + d) % size;
|
||||||
|
|
||||||
|
if(cursor < 0)
|
||||||
|
{
|
||||||
|
cursor += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rods[cursor]->should_select())
|
||||||
|
{
|
||||||
|
return cursor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void move_cursor(int d)
|
return 0;
|
||||||
{
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
cursor_x += d;
|
|
||||||
|
|
||||||
while(cursor_x >= W)
|
|
||||||
{
|
|
||||||
cursor_x -= W;
|
|
||||||
cursor_y += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(cursor_x < 0)
|
|
||||||
{
|
|
||||||
cursor_x += W;
|
|
||||||
cursor_y -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor_y %= H;
|
|
||||||
|
|
||||||
if(cursor_y < 0)
|
|
||||||
{
|
|
||||||
cursor_y += H;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rods[cursor_x][cursor_y]->should_select())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void toggle_selected()
|
void toggle_selected()
|
||||||
{
|
{
|
||||||
if(rods[cursor_x][cursor_y]->should_select())
|
if(rods[cursor]->should_select())
|
||||||
{
|
{
|
||||||
rods[cursor_x][cursor_y]->toggle_selected();
|
rods[cursor]->toggle_selected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void update_tile(std::mt19937& rand, double secs, int i, int x, int y)
|
||||||
|
{
|
||||||
|
std::array<int, 2> nb_lookup[4] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
|
||||||
|
std::shuffle(nb_lookup, &nb_lookup[3], rand);
|
||||||
|
|
||||||
|
for(int j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
int xp = x + nb_lookup[j][0];
|
||||||
|
int yp = y + nb_lookup[j][1];
|
||||||
|
|
||||||
|
if(xp >= 0 && yp >= 0 && xp < width && yp < height)
|
||||||
|
{
|
||||||
|
rods[i]->interact(rods[yp * width + xp], secs / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_interactions(std::mt19937& rand, int* rods_lookup, double secs)
|
||||||
|
{
|
||||||
|
std::shuffle(rods_lookup, &rods_lookup[size - 1], rand);
|
||||||
|
|
||||||
|
for(int id = 0; id < size; id++)
|
||||||
|
{
|
||||||
|
int i = rods_lookup[id];
|
||||||
|
int x = i % width;
|
||||||
|
int y = i / width;
|
||||||
|
|
||||||
|
for(int j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
update_tile(rand, secs, i, x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ double rod::get(val_t type) const
|
||||||
|
|
||||||
void rod::add(val_t type, double v)
|
void rod::add(val_t type, double v)
|
||||||
{
|
{
|
||||||
vals_in[type] += v;
|
vals[type] += v;
|
||||||
}
|
}
|
||||||
|
|
||||||
double rod::extract(val_t type, double s, double k, double o)
|
double rod::extract(val_t type, double s, double k, double o)
|
||||||
|
@ -20,14 +20,16 @@ double rod::extract(val_t type, double s, double k, double o)
|
||||||
k *= get_k(type);
|
k *= get_k(type);
|
||||||
|
|
||||||
double m = 1;
|
double m = 1;
|
||||||
|
k = 1 - k * get_k(type);
|
||||||
|
|
||||||
if(k < 1)
|
if(k > 0)
|
||||||
{
|
{
|
||||||
m = 1 - std::pow(0.5, s * -std::log2(1 - k * get_k(type)));
|
m = 1 - std::pow(0.5, s * -std::log2(k));
|
||||||
}
|
}
|
||||||
|
|
||||||
double v = m * 0.5 * (get(type) - o);
|
double v = m * 0.5 * (get(type) - o);
|
||||||
vals_in[type] -= v;
|
|
||||||
|
vals[type] -= v;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,18 +42,35 @@ void rod::interact(rod* o, double secs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double rod::get_speed() const
|
||||||
|
{
|
||||||
|
int m = motion < 0 ? -1 : 1;
|
||||||
|
return motion == 0 ? 0 : (std::pow(10, std::abs(motion)) * 1e-10 * m);
|
||||||
|
}
|
||||||
|
|
||||||
void rod::update_rod(double secs)
|
void rod::update_rod(double secs)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < rod::VAL_N; i++)
|
|
||||||
{
|
|
||||||
val_t v = (val_t)i;
|
|
||||||
vals[v] += vals_in[v];
|
|
||||||
vals_in[v] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// decay the free neutrons
|
// decay the free neutrons
|
||||||
double m = std::pow(0.5, secs / 879.4);
|
double m = std::pow(0.5, secs / 879.4);
|
||||||
vals[val_t::N_FAST] *= m;
|
vals[val_t::N_FAST] *= m;
|
||||||
vals[val_t::N_SLOW] *= m;
|
vals[val_t::N_SLOW] *= m;
|
||||||
|
|
||||||
|
if(motion != 0 && !is_selected())
|
||||||
|
{
|
||||||
|
motion = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(motion != 0)
|
||||||
|
{
|
||||||
|
update_selected(get_speed() * secs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rod::update_rod_selected(int m)
|
||||||
|
{
|
||||||
|
motion += m;
|
||||||
|
|
||||||
|
if(motion > 10) motion = 10;
|
||||||
|
if(motion < -10) motion = -10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,17 +27,24 @@ public:
|
||||||
|
|
||||||
virtual bool should_display() const { return false; }
|
virtual bool should_display() const { return false; }
|
||||||
virtual bool should_select() const { return false; }
|
virtual bool should_select() const { return false; }
|
||||||
virtual void update_selected(double a) { }
|
void update_rod_selected(int m);
|
||||||
|
|
||||||
constexpr void toggle_selected() { selected = !selected; }
|
constexpr void toggle_selected() { selected = !selected; }
|
||||||
constexpr bool is_selected() { return selected; }
|
constexpr bool is_selected() const { return selected; }
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& o, const rod& r)
|
friend std::ostream& operator<<(std::ostream& o, const rod& r)
|
||||||
{
|
{
|
||||||
if(!r.should_display()) return o;
|
if(!r.should_display()) return o;
|
||||||
|
|
||||||
o << r.get_name() << "\n";
|
o << r.get_name() << "\n";
|
||||||
|
|
||||||
|
if(r.is_selected())
|
||||||
|
{
|
||||||
|
o << "Speed: " << r.get_speed() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
r.display(o);
|
r.display(o);
|
||||||
|
|
||||||
o << "Heat: " << r.get(val_t::HEAT) << " C\n";
|
o << "Heat: " << r.get(val_t::HEAT) << " C\n";
|
||||||
o << "Fast: " << r.get(val_t::N_FAST) << " mol\n";
|
o << "Fast: " << r.get(val_t::N_FAST) << " mol\n";
|
||||||
o << "Slow: " << r.get(val_t::N_SLOW) << " mol\n";
|
o << "Slow: " << r.get(val_t::N_SLOW) << " mol\n";
|
||||||
|
@ -47,15 +54,17 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
double vals_in[VAL_N] = {0};
|
|
||||||
double vals[VAL_N] = {0};
|
double vals[VAL_N] = {0};
|
||||||
bool selected = false;
|
bool selected = false;
|
||||||
|
int motion = 0;
|
||||||
|
|
||||||
virtual void display(std::ostream& o) const { };
|
virtual void display(std::ostream& o) const { };
|
||||||
virtual double get_k(val_t type) const { return 0; }
|
virtual double get_k(val_t type) const { return 0; }
|
||||||
virtual const char* get_name() const { return "Empty"; }
|
virtual const char* get_name() const { return "Empty"; }
|
||||||
|
virtual void update_selected(double a) { }
|
||||||
|
|
||||||
void update_rod(double secs);
|
void update_rod(double secs);
|
||||||
|
double get_speed() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue