#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 <xbt/asserts.h>
-#include <xbt/log.h>
#include "src/kernel/resource/CpuImpl.hpp"
#include "src/simgrid/module.hpp"
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
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.
-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.
+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");
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_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;
}
-/* 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 */
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
- 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_);
// 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_);
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
- 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;
- 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
- 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;
- 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_;
- // 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;
}
- // 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
*/
- 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 +
- 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;
, 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 non-negative (provided: %f)",
+ 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(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].
- * @param nominal_charge_power_w The maximum power delivered by the Battery in W (<= 0).
- * @param nominal_discharge_power_w The maximum power absorbed by the Battery in W (>= 0).
+ * @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).
*/
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
*/
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
- * @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
- * @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
- * @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