* under the terms of the license (GNU LGPL) which comes with this package. */
#include <simgrid/Exception.hpp>
#include <simgrid/plugins/battery.hpp>
-#include <simgrid/s4u/Actor.hpp>
+#include <simgrid/plugins/energy.h>
#include <simgrid/s4u/Engine.hpp>
#include <simgrid/s4u/Host.hpp>
-#include <simgrid/s4u/VirtualMachine.hpp>
#include <simgrid/simix.hpp>
+#include <xbt/asserts.h>
+#include <xbt/log.h>
#include "src/kernel/resource/CpuImpl.hpp"
#include "src/simgrid/module.hpp"
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/split.hpp>
-
-SIMGRID_REGISTER_PLUGIN(battery, "Battery management", &sg_battery_plugin_init)
-
+SIMGRID_REGISTER_PLUGIN(battery, "Battery management", nullptr)
/** @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
-
- <host id="Host" speed="100.0Mf" core="1">
- <prop id="battery_active" value="1" />
- <prop id="battery_capacity" value="10" />
- <prop id="battery_cycles" value="200" />
- <prop id="battery_state_of_charge" value="0.8" />
- </host>
-
-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_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)
+This is the battery plugin
@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<simgrid::s4u::Host, Battery> 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() const;
- double get_state_of_charge_max() const;
- double get_state_of_health();
- double get_capacity();
- double get_cumulative_cost();
- double get_next_event_date();
-};
-
-simgrid::xbt::Extension<simgrid::s4u::Host, Battery> 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; });
-}
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(Battery, kernel, "Logging specific to the battery plugin");
-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; });
-}
+namespace simgrid::plugins {
-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;
-}
+/* BatteryModel */
-bool Battery::is_active() const
-{
- return active_;
-}
+BatteryModel::BatteryModel() : Model("BatteryModel") {}
-double Battery::get_power()
+void BatteryModel::add_battery(BatteryPtr b)
{
- update();
- return power_w_;
+ batteries_.push_back(b);
}
-double Battery::get_state_of_charge()
+void BatteryModel::update_actions_state(double now, double delta)
{
- update();
- return state_of_charge_;
+ for (auto battery : batteries_)
+ battery->update();
}
-double Battery::get_state_of_charge_min() const
+double BatteryModel::next_occurring_event(double now)
{
- return state_of_charge_min_;
+ double time_delta = -1;
+ for (auto battery : batteries_) {
+ double time_delta_battery = battery->next_occurring_event();
+ time_delta = time_delta == -1 or time_delta_battery < time_delta ? time_delta_battery : time_delta;
+ }
+ return time_delta;
}
-double Battery::get_state_of_charge_max() const
-{
- return state_of_charge_max_;
-}
+/* Event */
-double Battery::get_state_of_health()
+Battery::Event::Event(double state_of_charge, Flow flow, std::function<void()> callback, bool repeat)
+ : state_of_charge_(state_of_charge), flow_(flow), callback_(callback), repeat_(repeat)
{
- update();
- return 1 - (energy_exchanged_j_ / energy_budget_j_);
}
-double Battery::get_capacity()
+std::shared_ptr<Battery::Event> Battery::Event::init(double state_of_charge, Flow flow, std::function<void()> callback,
+ bool repeat)
{
- update();
- return capacity_wh_;
+ return std::make_shared<Battery::Event>(state_of_charge, flow, callback, repeat);
}
-double Battery::get_cumulative_cost()
-{
- update();
- return cumulative_cost_;
-}
+/* Battery */
-double Battery::get_next_event_date()
-{
- update();
- return next_event_;
-}
+std::shared_ptr<BatteryModel> Battery::battery_model_;
-void Battery::init_battery_params()
+void Battery::init_plugin()
{
- 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(); });
+ auto model = std::make_shared<BatteryModel>();
+ simgrid::s4u::Engine::get_instance()->add_model(model);
+ Battery::battery_model_ = model;
}
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 || not is_active())
+ kernel::actor::simcall_answered([this] {
+ double now = s4u::Engine::get_clock();
+ double time_delta_s = now - last_updated_;
+
+ // Nothing to update
+ if (time_delta_s <= 0)
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;
+
+ // Calculate energy provided / consumed during this step
+ double provided_power_w = 0;
+ double consumed_power_w = 0;
+ for (auto const& [host, active] : host_loads_)
+ provided_power_w += active ? sg_host_get_current_consumption(host) : 0;
+ for (auto const& [name, load] : named_loads_) {
+ if (load > 0)
+ provided_power_w += load;
+ else
+ consumed_power_w += -load;
}
- if (event) {
- power_w_ = 0;
- next_event_ = -1;
+ double energy_lost_delta_j = provided_power_w / discharge_efficiency_ * time_delta_s;
+ double energy_gained_delta_j = consumed_power_w * charge_efficiency_ * time_delta_s;
+
+ // Check that the provided/consumed energy is valid
+ energy_lost_delta_j = std::min(energy_lost_delta_j, energy_stored_j_ + energy_gained_delta_j);
+ /* Charging deteriorate the capacity, but the capacity is used to evaluate the maximum charge so
+ we need to evaluate the theorethical new capacity in the worst case when we fully charge the battery */
+ double new_tmp_capacity_wh =
+ (initial_capacity_wh_ *
+ (1 - (energy_provided_j_ + energy_lost_delta_j * discharge_efficiency_ + energy_consumed_j_ -
+ (energy_stored_j_ + energy_lost_delta_j) / charge_efficiency_) /
+ energy_budget_j_)) /
+ (1 + 3600 * initial_capacity_wh_ / (charge_efficiency_ * energy_budget_j_));
+ energy_gained_delta_j =
+ std::min(energy_gained_delta_j, (3600 * new_tmp_capacity_wh) - energy_stored_j_ + energy_lost_delta_j);
+
+ // Updating battery
+ energy_provided_j_ += energy_lost_delta_j * discharge_efficiency_;
+ energy_consumed_j_ += energy_gained_delta_j / charge_efficiency_;
+ capacity_wh_ = initial_capacity_wh_ * (1 - (energy_provided_j_ + energy_consumed_j_) / energy_budget_j_);
+ energy_stored_j_ += energy_gained_delta_j - energy_lost_delta_j;
+ energy_stored_j_ = std::min(energy_stored_j_, 3600 * capacity_wh_);
+ last_updated_ = now;
+
+ std::vector<std::shared_ptr<Event>> to_delete = {};
+ for (auto event : events_) {
+ if (abs(event->time_delta_ - time_delta_s) < 0.000000001) {
+ event->callback_();
+ if (event->repeat_)
+ event->time_delta_ = -1;
+ else
+ to_delete.push_back(event);
+ }
}
- last_updated_ = now;
+ for (auto event : to_delete)
+ delete_event(event);
});
}
-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<simgrid::s4u::VirtualMachine*>(&host)) // Ignore virtual machines
- return;
- host.extension_set(new Battery(&host));
-}
-
-/* **************************** Public interface *************************** */
-
-static void ensure_plugin_inited()
+double Battery::next_occurring_event()
{
- 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.");
-}
+ double provided_power_w = 0;
+ double consumed_power_w = 0;
+ for (auto const& [host, active] : host_loads_)
+ provided_power_w += active ? sg_host_get_current_consumption(host) : 0;
+ for (auto const& [name, load] : named_loads_) {
+ if (load > 0)
+ provided_power_w += load;
+ else
+ consumed_power_w += -load;
+ }
-/** @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<Battery>();
- simgrid::s4u::Host::on_creation_cb(&on_creation);
+ double time_delta = -1;
+ for (auto& event : events_) {
+ double lost_power_w = provided_power_w / discharge_efficiency_;
+ double gained_power_w = consumed_power_w * charge_efficiency_;
+ // Event cannot happen
+ if ((lost_power_w == gained_power_w) or (event->state_of_charge_ == energy_stored_j_ / (3600 * capacity_wh_)) or
+ (lost_power_w > gained_power_w and event->flow_ == Flow::CHARGE) or
+ (lost_power_w < gained_power_w and event->flow_ == Flow::DISCHARGE)) {
+ continue;
+ }
+ // Evaluate time until event happen
+ else {
+ /* The time to reach a state of charge depends on the capacity, but charging and discharging deteriorate the
+ * capacity, so we need to evaluate the time considering a capacity that also depends on time
+ */
+ event->time_delta_ = (3600 * event->state_of_charge_ * initial_capacity_wh_ *
+ (1 - (energy_provided_j_ + energy_consumed_j_) / energy_budget_j_) -
+ energy_stored_j_) /
+ (gained_power_w - lost_power_w +
+ 3600 * event->state_of_charge_ * initial_capacity_wh_ *
+ (consumed_power_w + provided_power_w) / energy_budget_j_);
+ if ((time_delta == -1 or event->time_delta_ < time_delta) and abs(event->time_delta_) > 0.000000001)
+ time_delta = event->time_delta_;
+ }
+ }
+ return time_delta;
+}
+
+Battery::Battery(const std::string& name, double state_of_charge, double charge_efficiency, double discharge_efficiency,
+ double initial_capacity_wh, int cycles, double depth_of_discharge)
+ : name_(name)
+ , energy_stored_j_(state_of_charge * 3600 * initial_capacity_wh)
+ , charge_efficiency_(charge_efficiency)
+ , discharge_efficiency_(discharge_efficiency)
+ , initial_capacity_wh_(initial_capacity_wh)
+ , capacity_wh_(initial_capacity_wh)
+ , cycles_(cycles)
+ , depth_of_discharge_(depth_of_discharge)
+ , energy_budget_j_(initial_capacity_wh * depth_of_discharge * 3600 * cycles * 2)
+{
+ xbt_assert(state_of_charge >= 0 and state_of_charge <= 1, " : state of charge should be in [0, 1] (provided: %f)",
+ state_of_charge);
+ xbt_assert(charge_efficiency > 0 and charge_efficiency <= 1, " : charge efficiency should be in [0,1] (provided: %f)",
+ charge_efficiency);
+ xbt_assert(discharge_efficiency > 0 and discharge_efficiency <= 1,
+ " : discharge efficiency should be in [0,1] (provided: %f)", discharge_efficiency);
+ xbt_assert(initial_capacity_wh > 0, " : initial capacity should be > 0 (provided: %f)", initial_capacity_wh);
+ xbt_assert(cycles > 0, " : cycles should be > 0 (provided: %d)", cycles);
+ xbt_assert(depth_of_discharge > 0 and depth_of_discharge <= 1,
+ " : depth of discharge should be in ]0, 1] (provided: %f)", depth_of_discharge);
+}
+
+BatteryPtr Battery::init(const std::string& name, double state_of_charge, double charge_efficiency,
+ double discharge_efficiency, double initial_capacity_wh, int cycles, double depth_of_discharge)
+{
+ static bool plugin_inited = false;
+ if (not plugin_inited) {
+ init_plugin();
+ plugin_inited = true;
+ }
+ auto battery = BatteryPtr(new Battery(name, state_of_charge, charge_efficiency, discharge_efficiency,
+ initial_capacity_wh, cycles, depth_of_discharge));
+ battery_model_->add_battery(battery);
+ return battery;
}
-/** @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)
+void Battery::set_load(const std::string& name, double power_w)
{
- ensure_plugin_inited();
- host->extension<Battery>()->set_state(state);
+ named_loads_[name] = power_w;
}
-/** @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)
+void Battery::connect_host(s4u::Host* h, bool active)
{
- ensure_plugin_inited();
- host->extension<Battery>()->set_power(power);
+ host_loads_[h] = active;
}
-/** @ingroup plugin_battery
- * @brief Return true if the battery is active.
- */
-bool sg_battery_is_active(const_sg_host_t host)
+double Battery::get_state_of_charge()
{
- ensure_plugin_inited();
- return host->extension<Battery>()->is_active();
+ return energy_stored_j_ / (3600 * capacity_wh_);
}
-/** @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)
+double Battery::get_state_of_health()
{
- ensure_plugin_inited();
- return host->extension<Battery>()->get_power();
+ return 1 - ((energy_provided_j_ + energy_consumed_j_) / energy_budget_j_);
}
-/** @ingroup plugin_battery
- * @brief Return the state of charge of the battery.
- */
-double sg_battery_get_state_of_charge(const_sg_host_t host)
+double Battery::get_capacity()
{
- ensure_plugin_inited();
- return host->extension<Battery>()->get_state_of_charge();
+ return capacity_wh_;
}
-/** @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)
+double Battery::get_energy_provided()
{
- ensure_plugin_inited();
- return host->extension<Battery>()->get_state_of_charge_min();
+ return energy_provided_j_;
}
-/** @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)
+double Battery::get_energy_consumed()
{
- ensure_plugin_inited();
- return host->extension<Battery>()->get_state_of_charge_max();
+ return energy_consumed_j_;
}
-/** @ingroup plugin_battery
- * @brief Return the state of health of the battery.
- */
-double sg_battery_get_state_of_health(const_sg_host_t host)
+double Battery::get_energy_stored(std::string unit)
{
- ensure_plugin_inited();
- return host->extension<Battery>()->get_state_of_health();
+ if (unit == "J")
+ return energy_stored_j_;
+ else if (unit == "Wh")
+ return energy_stored_j_ / 3600;
+ else
+ xbt_die("Invalid unit. Valid units are J (default) or Wh.");
}
-/** @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)
+std::shared_ptr<Battery::Event> Battery::create_event(double state_of_charge, Flow flow, std::function<void()> callback,
+ bool repeat)
{
- ensure_plugin_inited();
- return host->extension<Battery>()->get_capacity();
+ auto event = Event::init(state_of_charge, flow, callback, repeat);
+ events_.push_back(event);
+ return event;
}
-/** @ingroup plugin_battery
- * @brief Return the cumulative cost of the battery.
- */
-double sg_battery_get_cumulative_cost(const_sg_host_t host)
+std::vector<std::shared_ptr<Battery::Event>> Battery::get_events()
{
- ensure_plugin_inited();
- return host->extension<Battery>()->get_cumulative_cost();
+ return events_;
}
-/** @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)
+void Battery::delete_event(std::shared_ptr<Event> event)
{
- ensure_plugin_inited();
- return host->extension<Battery>()->get_next_event_date();
+ events_.erase(
+ std::remove_if(events_.begin(), events_.end(), [&event](std::shared_ptr<Event> e) { return event == e; }),
+ events_.end());
}
+} // namespace simgrid::plugins
\ No newline at end of file