From: mlaurent Date: Fri, 31 Mar 2023 18:19:44 +0000 (+0200) Subject: Merge branch 'master' of https://framagit.org/simgrid/simgrid X-Git-Tag: v3.34~41^2~12^2~2 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/ce354758f86f0fad1ea536f1cbc0a337267b9987 Merge branch 'master' of https://framagit.org/simgrid/simgrid --- ce354758f86f0fad1ea536f1cbc0a337267b9987 diff --cc src/mc/api/strategy/Strategy.hpp index 8696b17924,c1bf76b415..92615d5ec5 --- a/src/mc/api/strategy/Strategy.hpp +++ b/src/mc/api/strategy/Strategy.hpp @@@ -17,9 -17,12 +17,14 @@@ protected std::map actors_to_run_; public: + /** Used to store penalties computed by the strategy to each actor */ + std::map penalties_; virtual ~Strategy() = default; + void operator=(const Strategy&) + { /* nothing to copy over while cloning */ + return; + } + virtual std::pair next_transition() const = 0; virtual void execute_next(aid_t aid, RemoteApp& app) = 0; virtual void consider_best() = 0; diff --cc src/plugins/battery.cpp index 0000000000,7e7f949cdc..b08de111a5 mode 000000,100644..100644 --- a/src/plugins/battery.cpp +++ b/src/plugins/battery.cpp @@@ -1,0 -1,598 +1,599 @@@ + #include + #include + #include + #include + #include + #include + #include + + #include "src/kernel/resource/CpuImpl.hpp" + #include "src/simgrid/module.hpp" + + #include + #include + + SIMGRID_REGISTER_PLUGIN(battery, "Battery management", &sg_battery_plugin_init) + + /** @defgroup plugin_battery plugin_battery Plugin Battery + + @beginrst + + This is the battery plugin, enabling management of batteries on hosts. + To activate this plugin, first call :cpp:func:`sg_battery_plugin_init()`. + + We consider a constant energy exchange model. + + Properties of batteries such as State of Charge and State of Health are lazily updated, ie., when reading values and + when the power is modified. + + State of Charge (SoC) + ..................... + + If the power of a battery is set to a negative value then the battery will act as a load and fill over time until it + reaches its maximal SoC. Conversely, if the power of a battery is set to a positive value then the battery will act as a + generator and deplete over time until it reaches its minimal SoC. When reaching either its maximal or minimal SoC it + will set its power to 0. + + The natural depletion of batteries over time is not taken into account. + + State of Health (SoH) + ..................... + + A battery starts with an energy budget :math:`E` such as: + + .. math:: + + E = C \times U \times D \times N \times 2 + + Where :math:`C` is the initial capacity, :math:`U` is the ratio of usable capacity, :math:`D` is the depth of discharge + and :math:`N` is the number of cycles of the battery. + + The SoH represents the consumption of this energy budget during the lifetime of the battery. + Use the battery reduces its SoH and its capacity in consequence. + When the SoH reaches 0, the battery becomes unusable. + + .. warning:: + + Due to the decrease of the battery capacity with the SoH, a large usable capacity leads to very tiny battery capacity + when reaching low SoH. This may results in charge and discharge cycles too short to be evaluated by the simulator. To + avoid this situation you should not try to reach a SoH of 0 with a usable capacity set to 1. + + Plotting the output of the example "battery-degradation" highlights the linear decrease of the SoH due to a continuous + use of the battery and the decreasing cycle duration as its capacity reduces: + + .. image:: /img/battery_degradation.svg + :align: center + + Batteries properties + .................... + + Properties of the batteries are defined as properties of hosts in the platform XML file. + + Here is an example of XML declaration: + + .. code-block:: xml + + + + + + + + + The different properties are: + + - ``battery_active``: Set the battery as active if set to 1 (default=0) -- ``battery_power``: Set the initial power of the battery in W (default=0). A negative value indicates that the battery act as a load and charge. A positive value indicates that the battery act as a generator and discharge ++- ``battery_power``: Set the initial power of the battery in W (default=0). A negative value indicates that the battery ++act as a load and charge. A positive value indicates that the battery act as a generator and discharge + - ``battery_state_of_charge``: Set the initial state of charge of the battery (default=0) + - ``battery_state_of_charge_min``: Set the minimal state of charge of the battery (default=0.2) + - ``battery_state_of_charge_max``: Set the maximal state of charge of the battery (default=0.8) + - ``battery_capacity``: Set the initial capacity of the battery in Wh (default=0) + - ``battery_usable_capacity``: Set the ratio of usable capacity of the battery (default=0.8) + - ``battery_depth_of_discharge``: Set the depth of discharge of the battery (default=0.9) + - ``battery_charge_efficiency``: Set the charge efficiency of the battery (default=1) + - ``battery_discharge_efficiency``: Set the charge efficiency of the battery (default=1) + - ``battery_cycles``: Set the number of cycle of the battery (default=1) + - ``battery_depth_of_discharge``: Set the number of cycle of the battery (default=1) + - ``battery_eval_cost``: Evaluate the cost of the battery during the simulation if set to 1 (defaulf=0) + - ``battery_investment_cost``: Set the investment cost of the battery (default=0) + - ``battery_static_maintenance_cost``: Set the static maintenance cost of the battery (default=0) + - ``battery_variable_maintenance_cost``: Set the variable maintenance cost of the battery (default=0) + + @endrst + */ + XBT_LOG_NEW_DEFAULT_SUBCATEGORY(battery, kernel, "Logging specific to the battery plugin"); + + namespace simgrid::plugin { + class Battery { + private: + simgrid::s4u::Host* host_ = nullptr; + + double state_of_charge_min_ = 0.2; + double state_of_charge_max_ = 0.8; + double charge_efficiency_ = 1; + double discharge_efficiency_ = 1; + double initial_capacity_wh_ = 0; + double cycles_ = 1; // total complete cycles (charge + discharge) the battery can do before complete depletion. + double depth_of_discharge_ = 0.9; + double usable_capacity_ = 0.8; + double energy_budget_j_ = 0; + + bool active_ = false; + double power_w_ = 0; // NEGATIVE when charging (consumes power) POSITIVE when discharging (generates power) + double state_of_charge_ = 0; + double capacity_wh_ = 0; + double next_event_ = -1; + double energy_exchanged_j_ = 0; + double last_updated_ = 0; + + // Calculation of costs from Bei Li thesis (link :https://tel.archives-ouvertes.fr/tel-02077668/document) (chapter 4) + bool eval_cost_ = false; + double cumulative_cost_ = 0; + double investment_cost_per_wh_ = 0; + double static_maintenance_cost_per_wh_times_h_ = 0; + double variable_maintenance_cost_per_wh_ = 0; + + void init_battery_params(); + void init_cost_params(); + void update(); + + void set_state_of_charge(double soc); + void set_state_of_charge_min(double soc); + void set_state_of_charge_max(double soc); + void set_capacity(double c); + void set_initial_capacity(double c); + void set_cycles(int c); + void set_depth_of_discharge(double d); + void set_usable_capacity(double c); + void set_charge_efficiency(double e); + void set_discharge_efficiency(double e); + void set_eval_cost(bool eval); + void set_investment_cost(double c); + void set_static_maintenance_cost(double c); + void set_variable_maintenance_cost(double c); + + bool is_charging(); + + public: + static simgrid::xbt::Extension EXTENSION_ID; + + explicit Battery(simgrid::s4u::Host* host); + ~Battery(); + + void set_state(bool state); + void set_power(const double power); + + bool is_active() const; + double get_power(); + double get_state_of_charge(); + double get_state_of_charge_min(); + double get_state_of_charge_max(); + double get_state_of_health(); + double get_capacity(); + double get_cumulative_cost(); + double get_next_event_date(); + }; + + simgrid::xbt::Extension Battery::EXTENSION_ID; + + void Battery::set_power(const double p) + { + update(); + xbt_assert(p == 0 or (p > 0 and state_of_charge_ > state_of_charge_min_) or + (p < 0 and state_of_charge_ < state_of_charge_max_), + "Incoherent power and state of charge. A battery cannot charge(discharge) past its maximal(minimal) state " + "of charge."); + xbt_assert(p == 0 or energy_exchanged_j_ < energy_budget_j_, "Cannot set power of a fully used battery."); + simgrid::kernel::actor::simcall_answered([this, p] { + power_w_ = p; + if (power_w_ == 0) { + next_event_ = -1; + return; + } + double soc_shutdown; + double soh_shutdown; + if (power_w_ > 0) { + soc_shutdown = capacity_wh_ * 3600 * (state_of_charge_ - state_of_charge_min_) / (power_w_ * charge_efficiency_); + soh_shutdown = (energy_budget_j_ - energy_exchanged_j_) / (power_w_ * charge_efficiency_); + } else { // power_w_ < 0 + soc_shutdown = + capacity_wh_ * 3600 * (state_of_charge_max_ - state_of_charge_) / (abs(power_w_) / discharge_efficiency_); + soh_shutdown = (energy_budget_j_ - energy_exchanged_j_) / (abs(power_w_) / discharge_efficiency_); + } + if (soh_shutdown <= 0) + next_event_ = simgrid::s4u::Engine::get_clock() + soc_shutdown; + else + next_event_ = simgrid::s4u::Engine::get_clock() + std::min(soc_shutdown, soh_shutdown); + }); + } + + void Battery::set_state(bool state) + { + update(); + simgrid::kernel::actor::simcall_answered([this, state] { active_ = state; }); + } + + void Battery::set_state_of_charge(double soc) + { + xbt_assert(soc > 0 and soc <= 1, " : state of charge should be in ]0,1] (provided: %f)", soc); + simgrid::kernel::actor::simcall_answered([this, soc] { state_of_charge_ = soc; }); + } + + void Battery::set_state_of_charge_min(double soc) + { + xbt_assert(soc > 0 and soc <= 1 and soc < state_of_charge_max_, + " : state of charge min should be in ]0,1] and below state of charge max (provided: %f)", soc); + simgrid::kernel::actor::simcall_answered([this, soc] { state_of_charge_min_ = soc; }); + } + + void Battery::set_state_of_charge_max(double soc) + { + xbt_assert(soc > 0 and soc <= 1 and soc > state_of_charge_min_, + " : state of charge max should be in ]0,1] and above state of charge min (provided: %f)", soc); + simgrid::kernel::actor::simcall_answered([this, soc] { state_of_charge_max_ = soc; }); + } + + void Battery::set_initial_capacity(double c) + { + xbt_assert(c > 0, " : capacity should be > 0 (provided: %f)", c); + simgrid::kernel::actor::simcall_answered([this, c] { initial_capacity_wh_ = c; }); + } + + void Battery::set_capacity(double c) + { + xbt_assert(c > 0, " : capacity should be > 0 (provided: %f)", c); + simgrid::kernel::actor::simcall_answered([this, c] { capacity_wh_ = c; }); + } + + void Battery::set_cycles(int c) + { + xbt_assert(c > 0, " : cycles should be > 0 (provided: %d)", c); + simgrid::kernel::actor::simcall_answered([this, c] { cycles_ = c; }); + } + + void Battery::set_depth_of_discharge(double d) + { + xbt_assert(d > 0 and d <= 1, " : depth of discharge should be in ]0, 1] (provided: %f)", d); + simgrid::kernel::actor::simcall_answered([this, d] { depth_of_discharge_ = d; }); + } + + void Battery::set_usable_capacity(double c) + { + xbt_assert(c > 0 and c <= 1, " : usable capacity should be in ]0, 1] (provided: %f)", c); + simgrid::kernel::actor::simcall_answered([this, c] { usable_capacity_ = c; }); + } + + void Battery::set_charge_efficiency(double e) + { + xbt_assert(e > 0 and e <= 1, " : charge efficiency should be in [0,1] (provided: %f)", e); + simgrid::kernel::actor::simcall_answered([this, e] { charge_efficiency_ = e; }); + } + + void Battery::set_discharge_efficiency(double e) + { + xbt_assert(e > 0 and e <= 1, " : discharge efficiency should be in [0,1] (provided: %f)", e); + simgrid::kernel::actor::simcall_answered([this, e] { discharge_efficiency_ = e; }); + } + + void Battery::set_eval_cost(bool eval) + { + simgrid::kernel::actor::simcall_answered([this, eval] { eval_cost_ = eval; }); + } + + void Battery::set_investment_cost(double c) + { + xbt_assert(c >= 0, " : investment cost should be >= 0 (provided: %f)", c); + simgrid::kernel::actor::simcall_answered([this, c] { investment_cost_per_wh_ = c; }); + } + + void Battery::set_static_maintenance_cost(double c) + { + xbt_assert(c >= 0, " : static maintenance cost should be >= 0 (provided: %f)", c); + simgrid::kernel::actor::simcall_answered([this, c] { static_maintenance_cost_per_wh_times_h_ = c; }); + } + + void Battery::set_variable_maintenance_cost(double c) + { + xbt_assert(c >= 0, " : variable maintenance cost should be >= 0 (provided: %f)", c); + simgrid::kernel::actor::simcall_answered([this, c] { variable_maintenance_cost_per_wh_ = c; }); + } + + bool Battery::is_charging() + { + update(); + return power_w_ < 0; + } + + bool Battery::is_active() const + { + return active_; + } + + double Battery::get_power() + { + update(); + return power_w_; + } + + double Battery::get_state_of_charge() + { + update(); + return state_of_charge_; + } + + double Battery::get_state_of_charge_min() + { + return state_of_charge_min_; + } + + double Battery::get_state_of_charge_max() + { + return state_of_charge_max_; + } + + double Battery::get_state_of_health() + { + update(); + return 1 - (energy_exchanged_j_ / energy_budget_j_); + } + + double Battery::get_capacity() + { + update(); + return capacity_wh_; + } + + double Battery::get_cumulative_cost() + { + update(); + return cumulative_cost_; + } + + double Battery::get_next_event_date() + { + update(); + return next_event_; + } + + void Battery::init_battery_params() + { + const char* prop_chars; + prop_chars = host_->get_property("battery_capacity"); + if (prop_chars) { + set_capacity(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + set_initial_capacity(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + } + prop_chars = host_->get_property("battery_usable_capacity"); + if (prop_chars) + set_usable_capacity(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_depth_of_discharge"); + if (prop_chars) + set_depth_of_discharge( + xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_cycles"); + if (prop_chars) + set_cycles(xbt_str_parse_int(prop_chars, ("cannot parse int: " + std::string(prop_chars)).c_str())); + simgrid::kernel::actor::simcall_answered([this] { + energy_budget_j_ = (initial_capacity_wh_ * usable_capacity_ * depth_of_discharge_ * 3600 * cycles_ * 2); + }); + prop_chars = host_->get_property("battery_active"); + if (prop_chars) + set_state(xbt_str_parse_int(prop_chars, ("cannot parse int: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_state_of_charge_min"); + if (prop_chars) + set_state_of_charge_min( + xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_state_of_charge_max"); + if (prop_chars) + set_state_of_charge_max( + xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_charge_efficiency"); + if (prop_chars) + set_charge_efficiency( + xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_discharge_efficiency"); + if (prop_chars) + set_discharge_efficiency( + xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_state_of_charge"); + if (prop_chars) + set_state_of_charge(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_eval_cost"); + if (prop_chars) + set_eval_cost(xbt_str_parse_int(prop_chars, ("cannot parse int: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_investment_cost"); + if (prop_chars) + set_investment_cost(xbt_str_parse_int(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_static_maintenance_cost"); + if (prop_chars) + set_static_maintenance_cost( + xbt_str_parse_int(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_variable_maintenance_cost"); + if (prop_chars) + set_variable_maintenance_cost( + xbt_str_parse_int(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + prop_chars = host_->get_property("battery_power"); + if (prop_chars) + set_power(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str())); + simgrid::kernel::actor::simcall_answered([this] { last_updated_ = simgrid::s4u::Engine::get_clock(); }); + } + + void Battery::update() + { + simgrid::kernel::actor::simcall_answered([this] { + double now = simgrid::s4u::Engine::get_clock(); + double time_delta_real = now - last_updated_; + if (time_delta_real <= 0 or not is_active()) + return; + double time_delta_until_event = next_event_ - last_updated_; + bool event = next_event_ != -1 and time_delta_until_event <= time_delta_real; + double power_real_w = power_w_ < 0 ? power_w_ * charge_efficiency_ : power_w_ / discharge_efficiency_; + state_of_charge_ -= power_real_w * (event ? time_delta_until_event : time_delta_real) / (3600 * capacity_wh_); + energy_exchanged_j_ += (event ? time_delta_until_event : time_delta_real) * abs(power_real_w); + capacity_wh_ = initial_capacity_wh_ * usable_capacity_ * (1 - (energy_exchanged_j_ / energy_budget_j_)) + + initial_capacity_wh_ * (1 - usable_capacity_); + capacity_wh_ = std::max(capacity_wh_, 0.0); + if (eval_cost_) { + double usage_cost_per_wh = + (investment_cost_per_wh_ / (depth_of_discharge_ * cycles_ * 2) + variable_maintenance_cost_per_wh_); + double usage_cost = + usage_cost_per_wh * abs(power_real_w) * (event ? time_delta_until_event : time_delta_real) / 3600; + double static_maintenance_cost = + static_maintenance_cost_per_wh_times_h_ * initial_capacity_wh_ * time_delta_real / 3600; + cumulative_cost_ += usage_cost + static_maintenance_cost; + } + if (event) { + power_w_ = 0; + next_event_ = -1; + } + last_updated_ = now; + }); + } + + Battery::Battery(simgrid::s4u::Host* host) : host_(host) + { + init_battery_params(); + } + + Battery::~Battery() = default; + } // namespace simgrid::plugin + + using simgrid::plugin::Battery; + + /* **************************** events callback *************************** */ + + static void on_creation(simgrid::s4u::Host& host) + { + if (dynamic_cast(&host)) // Ignore virtual machines + return; + host.extension_set(new Battery(&host)); + } + + /* **************************** Public interface *************************** */ + + static void ensure_plugin_inited() + { + if (not Battery::EXTENSION_ID.valid()) + throw simgrid::xbt::InitializationError("The Battery plugin is not active. Please call sg_battery_plugin_init() " + "before calling any function related to that plugin."); + } + + /** @ingroup plugin_battery + * @brief Enable battery plugin. + */ + void sg_battery_plugin_init() + { + if (Battery::EXTENSION_ID.valid()) + return; + Battery::EXTENSION_ID = simgrid::s4u::Host::extension_create(); + simgrid::s4u::Host::on_creation_cb(&on_creation); + } + + /** @ingroup plugin_battery + * @param state The state to set. + * @brief Set the state of the battery. + * A battery set to inactive (false) will neither update its state of charge nor its state of health. + */ + void sg_battery_set_state(const_sg_host_t host, bool state) + { + ensure_plugin_inited(); + host->extension()->set_state(state); + } + + /** @ingroup plugin_battery + * @param power The power to set in W. + * @brief Set the power of the battery. + * @note A negative value makes the battery act as a load and charge. + * A positive value makes the battery act as a generator and discharge. + */ + void sg_battery_set_power(const_sg_host_t host, double power) + { + ensure_plugin_inited(); + host->extension()->set_power(power); + } + + /** @ingroup plugin_battery + * @brief Return true if the battery is active. + */ + bool sg_battery_is_active(const_sg_host_t host) + { + ensure_plugin_inited(); + return host->extension()->is_active(); + } + + /** @ingroup plugin_battery + * @brief Return the power of the battery in W. + * @note A negative value indicates that the battery act as a load and charge. + * A positive value indicates that the battery act as a generator and discharge. + */ + double sg_battery_get_power(const_sg_host_t host) + { + ensure_plugin_inited(); + return host->extension()->get_power(); + } + + /** @ingroup plugin_battery + * @brief Return the state of charge of the battery. + */ + double sg_battery_get_state_of_charge(const_sg_host_t host) + { + ensure_plugin_inited(); + return host->extension()->get_state_of_charge(); + } + + /** @ingroup plugin_battery + * @brief Return the minimal state of charge of the battery. + */ + double sg_battery_get_state_of_charge_min(const_sg_host_t host) + { + ensure_plugin_inited(); + return host->extension()->get_state_of_charge_min(); + } + + /** @ingroup plugin_battery + * @brief Return the maximal state of charge of the battery. + */ + double sg_battery_get_state_of_charge_max(const_sg_host_t host) + { + ensure_plugin_inited(); + return host->extension()->get_state_of_charge_max(); + } + + /** @ingroup plugin_battery + * @brief Return the state of health of the battery. + */ + double sg_battery_get_state_of_health(const_sg_host_t host) + { + ensure_plugin_inited(); + return host->extension()->get_state_of_health(); + } + + /** @ingroup plugin_battery + * @brief Return the capacity of the battery in Wh. + * @note capacity is reduced by the state of health of the battery. + */ + double sg_battery_get_capacity(const_sg_host_t host) + { + ensure_plugin_inited(); + return host->extension()->get_capacity(); + } + + /** @ingroup plugin_battery + * @brief Return the cumulative cost of the battery. + */ + double sg_battery_get_cumulative_cost(const_sg_host_t host) + { + ensure_plugin_inited(); + return host->extension()->get_cumulative_cost(); + } + + /** @ingroup plugin_battery + * @brief Return the date of the next event, i.e., when the battery will be empty or full. + * @note If power is null then return -1. + */ + double sg_battery_get_next_event_date(const_sg_host_t host) + { + ensure_plugin_inited(); + return host->extension()->get_next_event_date(); + }