Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Various sonar cleanups
[simgrid.git] / src / plugins / battery.cpp
index 15c715a..0cbfdbc 100644 (file)
@@ -6,10 +6,7 @@
 #include <simgrid/plugins/battery.hpp>
 #include <simgrid/plugins/energy.h>
 #include <simgrid/s4u/Engine.hpp>
 #include <simgrid/plugins/battery.hpp>
 #include <simgrid/plugins/energy.h>
 #include <simgrid/s4u/Engine.hpp>
-#include <simgrid/s4u/Host.hpp>
 #include <simgrid/simix.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 "src/kernel/resource/CpuImpl.hpp"
 #include "src/simgrid/module.hpp"
@@ -24,8 +21,13 @@ This is the battery plugin, enabling management of batteries.
 Batteries
 .........
 
 Batteries
 .........
 
-A battery has an initial State of Charge :math:`SoC`, a charge efficiency :math:`\eta_{charge}`, a discharge efficiency
-:math:`\eta_{discharge}`, an initial capacity :math:`C_{initial}` and a number of cycle :math:`N`.
+A battery has an initial State of Charge :math:`SoC`, a nominal charge power, a nominal discharge power, a charge
+efficiency :math:`\eta_{charge}`, a discharge efficiency :math:`\eta_{discharge}`, an initial capacity
+:math:`C_{initial}` and a number of cycle :math:`N`.
+
+The nominal charge(discharge) power is the maximum power the Battery can consume(provide), before application of the
+charge(discharge) efficiency factor. For instance, if a load provides(consumes) 100W to(from) the Battery with a nominal
+charge(discharge) power of 50W and a charge(discharge) efficiency of 0.9, the Battery will only gain(provide) 45W.
 
 We distinguish the energy provided :math:`E_{provided}` / consumed :math:`E_{consumed}` from the energy lost
 :math:`E_{lost}` / gained :math:`E_{gained}`. The energy provided / consumed shows the external point of view, and the
 
 We distinguish the energy provided :math:`E_{provided}` / consumed :math:`E_{consumed}` from the energy lost
 :math:`E_{lost}` / gained :math:`E_{gained}`. The energy provided / consumed shows the external point of view, and the
@@ -40,6 +42,9 @@ energy lost / gained shows the internal point of view:
 For instance, if you apply a load of 100W to a battery for 10s with a discharge efficiency of 0.8, the energy provided
 will be equal to 10kJ, and the energy lost will be equal to 12.5kJ.
 
 For instance, if you apply a load of 100W to a battery for 10s with a discharge efficiency of 0.8, the energy provided
 will be equal to 10kJ, and the energy lost will be equal to 12.5kJ.
 
+All the energies are positive, but loads connected to a Battery may be positive or negative, as explained in the next
+section.
+
 Use the battery reduces its State of Health :math:`SoH` and its capacity :math:`C` linearly in consequence:
 
 .. math::
 Use the battery reduces its State of Health :math:`SoH` and its capacity :math:`C` linearly in consequence:
 
 .. math::
@@ -63,19 +68,25 @@ continuous use of the battery alternating between charge and discharge:
 The natural depletion of batteries over time is not taken into account.
 
 Loads & Hosts
 The natural depletion of batteries over time is not taken into account.
 
 Loads & Hosts
-..............
+.............
 
 You can add named loads to a battery. Those loads may be positive and consume energy from the battery, or negative and
 
 You can add named loads to a battery. Those loads may be positive and consume energy from the battery, or negative and
-add energy to the battery. You can also connect hosts to a battery. Theses hosts will consume their energy from the
+provide energy to the battery. You can also connect hosts to a battery. Theses hosts will consume their energy from the
 battery until the battery is empty or until the connection between the hosts and the battery is set inactive.
 
 battery until the battery is empty or until the connection between the hosts and the battery is set inactive.
 
-Events
-......
+Handlers
+........
 
 
-You can create events that will happen at specific SoC of the battery and trigger a callback.
-Theses events may be recurrent, for instance you may want to always set all loads to zero and deactivate all hosts
+You can schedule handlers that will happen at specific SoC of the battery and trigger a callback.
+Theses handlers may be recurrent, for instance you may want to always set all loads to zero and deactivate all hosts
 connections when the battery reaches 20% SoC.
 
 connections when the battery reaches 20% SoC.
 
+Connector
+.........
+
+A Battery can act as a connector to connect Solar Panels direcly to loads. Such Battery is created without any
+parameter, cannot store energy and has a transfer efficiency of 100%.
+
   @endrst
  */
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(Battery, kernel, "Logging specific to the battery plugin");
   @endrst
  */
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(Battery, kernel, "Logging specific to the battery plugin");
@@ -99,25 +110,30 @@ void BatteryModel::update_actions_state(double now, double delta)
 
 double BatteryModel::next_occurring_event(double now)
 {
 
 double BatteryModel::next_occurring_event(double now)
 {
+  static bool init = false;
+  if (!init) {
+    init = true;
+    return 0;
+  }
   double time_delta = -1;
   for (auto battery : batteries_) {
   double time_delta = -1;
   for (auto battery : batteries_) {
-    double time_delta_battery = battery->next_occurring_event();
+    double time_delta_battery = battery->next_occurring_handler();
     time_delta                = time_delta == -1 or time_delta_battery < time_delta ? time_delta_battery : time_delta;
   }
   return time_delta;
 }
 
     time_delta                = time_delta == -1 or time_delta_battery < time_delta ? time_delta_battery : time_delta;
   }
   return time_delta;
 }
 
-/* Event */
+/* Handler */
 
 
-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)
+Battery::Handler::Handler(double state_of_charge, Flow flow, Persistancy p, std::function<void()> callback)
+    : state_of_charge_(state_of_charge), flow_(flow), callback_(callback), persistancy_(p)
 {
 }
 
 {
 }
 
-std::shared_ptr<Battery::Event> Battery::Event::init(double state_of_charge, Flow flow, std::function<void()> callback,
-                                                     bool repeat)
+std::shared_ptr<Battery::Handler> Battery::Handler::init(double state_of_charge, Flow flow, Persistancy p,
+                                                         std::function<void()> callback)
 {
 {
-  return std::make_shared<Battery::Event>(state_of_charge, flow, callback, repeat);
+  return std::make_shared<Battery::Handler>(state_of_charge, flow, p, callback);
 }
 
 /* Battery */
 }
 
 /* Battery */
@@ -146,12 +162,18 @@ void Battery::update()
     double consumed_power_w = 0;
     for (auto const& [host, active] : host_loads_)
       provided_power_w += active ? sg_host_get_current_consumption(host) : 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;
+    for (auto const& [name, pair] : named_loads_) {
+      if (not pair.first)
+        continue;
+      if (pair.second > 0)
+        provided_power_w += pair.second;
       else
       else
-        consumed_power_w += -load;
+        consumed_power_w += -pair.second;
     }
     }
+
+    provided_power_w = std::min(provided_power_w, nominal_discharge_power_w_ * discharge_efficiency_);
+    consumed_power_w = std::min(consumed_power_w, -nominal_charge_power_w_);
+
     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;
 
     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;
 
@@ -171,6 +193,14 @@ void Battery::update()
     // Updating battery
     energy_provided_j_ += energy_lost_delta_j * discharge_efficiency_;
     energy_consumed_j_ += energy_gained_delta_j / charge_efficiency_;
     // Updating battery
     energy_provided_j_ += energy_lost_delta_j * discharge_efficiency_;
     energy_consumed_j_ += energy_gained_delta_j / charge_efficiency_;
+
+    // This battery is a simple connector, we only update energy provided and consumed
+    if (energy_budget_j_ == 0) {
+      energy_consumed_j_ = energy_provided_j_;
+      last_updated_      = now;
+      return;
+    }
+
     capacity_wh_ =
         initial_capacity_wh_ *
         (1 - (energy_provided_j_ / discharge_efficiency_ + energy_consumed_j_ * charge_efficiency_) / energy_budget_j_);
     capacity_wh_ =
         initial_capacity_wh_ *
         (1 - (energy_provided_j_ / discharge_efficiency_ + energy_consumed_j_ * charge_efficiency_) / energy_budget_j_);
@@ -178,66 +208,74 @@ void Battery::update()
     energy_stored_j_ = std::min(energy_stored_j_, 3600 * capacity_wh_);
     last_updated_    = now;
 
     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;
+    auto handlers_2 = handlers_;
+    for (auto handler : handlers_2) {
+      if (abs(handler->time_delta_ - time_delta_s) < 0.000000001) {
+        handler->callback_();
+        if (handler->persistancy_ == Handler::Persistancy::PERSISTANT)
+          handler->time_delta_ = -1;
         else
         else
-          to_delete.push_back(event);
+          delete_handler(handler);
       }
     }
       }
     }
-    for (auto event : to_delete)
-      delete_event(event);
   });
 }
 
   });
 }
 
-double Battery::next_occurring_event()
+double Battery::next_occurring_handler()
 {
   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;
 {
   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;
+  for (auto const& [name, pair] : named_loads_) {
+    if (not pair.first)
+      continue;
+    if (pair.second > 0)
+      provided_power_w += pair.second;
     else
     else
-      consumed_power_w += -load;
+      consumed_power_w += -pair.second;
   }
 
   }
 
+  provided_power_w = std::min(provided_power_w, nominal_discharge_power_w_ * discharge_efficiency_);
+  consumed_power_w = std::min(consumed_power_w, -nominal_charge_power_w_);
+
   double time_delta = -1;
   double time_delta = -1;
-  for (auto& event : events_) {
+  for (auto& handler : handlers_) {
     double lost_power_w   = provided_power_w / discharge_efficiency_;
     double gained_power_w = consumed_power_w * charge_efficiency_;
     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)) {
+    if ((lost_power_w == gained_power_w) or (handler->state_of_charge_ == get_state_of_charge()) or
+        (lost_power_w > gained_power_w and
+         (handler->flow_ == Flow::CHARGE or handler->state_of_charge_ > get_state_of_charge())) or
+        (lost_power_w < gained_power_w and
+         (handler->flow_ == Flow::DISCHARGE or handler->state_of_charge_ < get_state_of_charge()))) {
       continue;
     }
       continue;
     }
-    // Evaluate time until event happen
+    // Evaluate time until handler 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
        */
     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_ *
+      handler->time_delta_ =
+          (3600 * handler->state_of_charge_ * initial_capacity_wh_ *
                (1 - (energy_provided_j_ / discharge_efficiency_ + energy_consumed_j_ * charge_efficiency_) /
                         energy_budget_j_) -
            energy_stored_j_) /
           (gained_power_w - lost_power_w +
                (1 - (energy_provided_j_ / discharge_efficiency_ + energy_consumed_j_ * charge_efficiency_) /
                         energy_budget_j_) -
            energy_stored_j_) /
           (gained_power_w - lost_power_w +
-           3600 * event->state_of_charge_ * initial_capacity_wh_ * (gained_power_w + lost_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_;
+           3600 * handler->state_of_charge_ * initial_capacity_wh_ * (gained_power_w + lost_power_w) /
+               energy_budget_j_);
+      if ((time_delta == -1 or handler->time_delta_ < time_delta) and abs(handler->time_delta_) > 0.000000001)
+        time_delta = handler->time_delta_;
     }
   }
   return time_delta;
 }
 
     }
   }
   return time_delta;
 }
 
-Battery::Battery(const std::string& name, double state_of_charge, double charge_efficiency, double discharge_efficiency,
+Battery::Battery(const std::string& name, double state_of_charge, double nominal_charge_power_w,
+                 double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency,
                  double initial_capacity_wh, int cycles)
     : name_(name)
                  double initial_capacity_wh, int cycles)
     : name_(name)
+    , nominal_charge_power_w_(nominal_charge_power_w)
+    , nominal_discharge_power_w_(nominal_discharge_power_w)
     , charge_efficiency_(charge_efficiency)
     , discharge_efficiency_(discharge_efficiency)
     , initial_capacity_wh_(initial_capacity_wh)
     , charge_efficiency_(charge_efficiency)
     , discharge_efficiency_(discharge_efficiency)
     , initial_capacity_wh_(initial_capacity_wh)
@@ -245,6 +283,10 @@ Battery::Battery(const std::string& name, double state_of_charge, double charge_
     , capacity_wh_(initial_capacity_wh)
     , energy_stored_j_(state_of_charge * 3600 * initial_capacity_wh)
 {
     , capacity_wh_(initial_capacity_wh)
     , energy_stored_j_(state_of_charge * 3600 * initial_capacity_wh)
 {
+  xbt_assert(nominal_charge_power_w <= 0, " : nominal charge power must be <= 0 (provided: %f)",
+             nominal_charge_power_w);
+  xbt_assert(nominal_discharge_power_w >= 0, " : nominal discharge power must be non-negative (provided: %f)",
+             nominal_discharge_power_w);
   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)",
   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)",
@@ -255,25 +297,46 @@ Battery::Battery(const std::string& name, double state_of_charge, double charge_
   xbt_assert(cycles > 0, " : cycles should be > 0 (provided: %d)", cycles);
 }
 
   xbt_assert(cycles > 0, " : cycles should be > 0 (provided: %d)", cycles);
 }
 
+/** @ingroup plugin_battery
+ *  @brief Init a Battery with this constructor makes it only usable as a connector.
+ *         A connector has no capacity and only delivers as much power as it receives
+           with a transfer efficiency of 100%.
+ *  @return A BatteryPtr pointing to the new Battery.
+ */
+BatteryPtr Battery::init()
+{
+  static bool plugin_inited = false;
+  if (not plugin_inited) {
+    init_plugin();
+    plugin_inited = true;
+  }
+  auto battery = BatteryPtr(new Battery());
+  battery_model_->add_battery(battery);
+  return battery;
+}
+
 /** @ingroup plugin_battery
  *  @param name The name of the Battery.
  *  @param state_of_charge The initial state of charge of the Battery [0,1].
 /** @ingroup plugin_battery
  *  @param name The name of the Battery.
  *  @param state_of_charge The initial state of charge of the Battery [0,1].
+ *  @param nominal_charge_power_w The maximum power absorbed by the Battery in W (<= 0).
+ *  @param nominal_discharge_power_w The maximum power delivered by the Battery in W (>= 0).
  *  @param charge_efficiency The charge efficiency of the Battery [0,1].
  *  @param discharge_efficiency The discharge efficiency of the Battery [0,1].
  *  @param initial_capacity_wh The initial capacity of the Battery in Wh (>0).
  *  @param cycles The number of charge-discharge cycles until complete depletion of the Battery capacity.
  *  @return A BatteryPtr pointing to the new Battery.
  */
  *  @param charge_efficiency The charge efficiency of the Battery [0,1].
  *  @param discharge_efficiency The discharge efficiency of the Battery [0,1].
  *  @param initial_capacity_wh The initial capacity of the Battery in Wh (>0).
  *  @param cycles The number of charge-discharge cycles until complete depletion of the Battery capacity.
  *  @return A BatteryPtr pointing to the new Battery.
  */
-BatteryPtr Battery::init(const std::string& name, double state_of_charge, double charge_efficiency,
-                         double discharge_efficiency, double initial_capacity_wh, int cycles)
+BatteryPtr Battery::init(const std::string& name, double state_of_charge, double nominal_charge_power_w,
+                         double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency,
+                         double initial_capacity_wh, int cycles)
 {
   static bool plugin_inited = false;
   if (not plugin_inited) {
     init_plugin();
     plugin_inited = true;
   }
 {
   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));
+  auto battery = BatteryPtr(new Battery(name, state_of_charge, nominal_charge_power_w, nominal_discharge_power_w,
+                                        charge_efficiency, discharge_efficiency, initial_capacity_wh, cycles));
   battery_model_->add_battery(battery);
   return battery;
 }
   battery_model_->add_battery(battery);
   return battery;
 }
@@ -284,7 +347,21 @@ BatteryPtr Battery::init(const std::string& name, double state_of_charge, double
  */
 void Battery::set_load(const std::string& name, double power_w)
 {
  */
 void Battery::set_load(const std::string& name, double power_w)
 {
-  named_loads_[name] = power_w;
+  kernel::actor::simcall_answered([this, &name, &power_w] {
+    if (named_loads_.find(name) == named_loads_.end())
+      named_loads_[name] = std::make_pair(true, power_w);
+    else
+      named_loads_[name].second = power_w;
+  });
+}
+
+/** @ingroup plugin_battery
+ *  @param name The name of the load
+ *  @param active Status of the load. If false then the load is ignored by the Battery.
+ */
+void Battery::set_load(const std::string& name, bool active)
+{
+  kernel::actor::simcall_answered([this, &name, &active] { named_loads_[name].first = active; });
 }
 
 /** @ingroup plugin_battery
 }
 
 /** @ingroup plugin_battery
@@ -297,7 +374,7 @@ void Battery::set_load(const std::string& name, double power_w)
  */
 void Battery::connect_host(s4u::Host* host, bool active)
 {
  */
 void Battery::connect_host(s4u::Host* host, bool active)
 {
-  host_loads_[host] = active;
+  kernel::actor::simcall_answered([this, &host, &active] { host_loads_[host] = active; });
 }
 
 /** @ingroup plugin_battery
 }
 
 /** @ingroup plugin_battery
@@ -360,36 +437,36 @@ double Battery::get_energy_stored(std::string unit)
 }
 
 /** @ingroup plugin_battery
 }
 
 /** @ingroup plugin_battery
- *  @brief Create a new Event.
- *  @param state_of_charge The state of charge at which the Event will happen.
- *  @param flow The flow in which the Event will happen, either when the Battery is charging or discharging.
- *  @param callback The callable to trigger when the Event happen.
- *  @param repeat If the Event is a recurrent Event or a single Event.
- *  @return A shared pointer of the new Event.
+ *  @brief Schedule a new Handler.
+ *  @param state_of_charge The state of charge at which the Handler will happen.
+ *  @param flow The flow in which the Handler will happen, either when the Battery is charging or discharging.
+ *  @param callback The callable to trigger when the Handler happen.
+ *  @param p If the Handler is recurrent or unique.
+ *  @return A shared pointer of the new Handler.
  */
  */
-std::shared_ptr<Battery::Event> Battery::create_event(double state_of_charge, Flow flow, std::function<void()> callback,
-                                                      bool repeat)
+std::shared_ptr<Battery::Handler> Battery::schedule_handler(double state_of_charge, Flow flow, Handler::Persistancy p,
+                                                            std::function<void()> callback)
 {
 {
-  auto event = Event::init(state_of_charge, flow, callback, repeat);
-  events_.push_back(event);
-  return event;
+  auto handler = Handler::init(state_of_charge, flow, p, callback);
+  handlers_.push_back(handler);
+  return handler;
 }
 
 /** @ingroup plugin_battery
 }
 
 /** @ingroup plugin_battery
- *  @return A vector containing the Events associated to the Battery.
+ *  @return A vector containing the Handlers associated to the Battery.
  */
  */
-std::vector<std::shared_ptr<Battery::Event>> Battery::get_events()
+std::vector<std::shared_ptr<Battery::Handler>> Battery::get_handlers()
 {
 {
-  return events_;
+  return handlers_;
 }
 
 /** @ingroup plugin_battery
 }
 
 /** @ingroup plugin_battery
- *  @brief Remove an Event from the Battery.
+ *  @brief Remove an Handler from the Battery.
  */
  */
-void Battery::delete_event(std::shared_ptr<Event> event)
+void Battery::delete_handler(std::shared_ptr<Handler> handler)
 {
 {
-  events_.erase(
-      std::remove_if(events_.begin(), events_.end(), [&event](std::shared_ptr<Event> e) { return event == e; }),
-      events_.end());
+  handlers_.erase(std::remove_if(handlers_.begin(), handlers_.end(),
+                                 [&handler](std::shared_ptr<Handler> e) { return handler == e; }),
+                  handlers_.end());
 }
 } // namespace simgrid::plugins
\ No newline at end of file
 }
 } // namespace simgrid::plugins
\ No newline at end of file