include examples/cpp/app-masterworkers/s4u-app-masterworkers_d.xml
include examples/cpp/app-token-ring/s4u-app-token-ring.cpp
include examples/cpp/app-token-ring/s4u-app-token-ring.tesh
+include examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp
+include examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh
include examples/cpp/battery-degradation/plot_battery_degradation.py
include examples/cpp/battery-degradation/s4u-battery-degradation.cpp
include examples/cpp/battery-degradation/s4u-battery-degradation.tesh
actor-create actor-daemon actor-exiting actor-join actor-kill
actor-lifetime actor-migrate actor-suspend actor-yield actor-stacksize
app-bittorrent app-chainsend app-token-ring
- battery-degradation battery-simple battery-energy
+ battery-chiller-solar battery-degradation battery-simple battery-energy
chiller-simple
comm-pingpong comm-ready comm-suspend comm-wait comm-waituntil
comm-dependent comm-host2host comm-failure comm-throttling
--- /dev/null
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example combine the battery plugin, the chiller plugin and the solar
+ panel plugin. It illustrates how to use them together to evaluate the amount
+ of brown energy (from the electrical grid) and green energy (from the solar
+ panel) consumed by several machines.
+
+ In this scenario we have two host placed in a room.
+ The room is maintained at 24°C by a chiller, powered by the electrical grid
+ and consumes brown energy.
+ The two hosts are powered by a battery when available, and the electrical
+ grid otherwise. The battery is charged by a solar panel.
+
+ We simulate two days from 00h00 to 00h00.
+ The solar panel generates power from 8h to 20h with a peak at 14h.
+ During the simulation, when the charge of the battery goes:
+ - below 75% the solar panel is connected to the battery
+ - above 80% the solar panel is disconnected from the battery
+ - below 20% the hosts are disconnected from the battery
+ - above 25% the hosts are connected to the battery
+
+ The two hosts are always idle, except from 12h to 16h on the first day.
+*/
+
+#include "simgrid/plugins/battery.hpp"
+#include "simgrid/plugins/chiller.hpp"
+#include "simgrid/plugins/energy.h"
+#include "simgrid/plugins/solar_panel.hpp"
+#include "simgrid/s4u.hpp"
+#include <math.h>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(battery_chiller_solar, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+namespace sp = simgrid::plugins;
+
+static void irradiance_manager(sp::SolarPanelPtr solar_panel)
+{
+ int time = 0;
+ int time_step = 10;
+ double amplitude = 1000 / 2.0;
+ double period = 24 * 60 * 60;
+ double shift = 16 * 60 * 60;
+ double irradiance;
+ while (true) {
+ irradiance = amplitude * sin(2 * M_PI * (time + shift) / period);
+ irradiance = irradiance < 0 ? 0 : irradiance;
+ solar_panel->set_solar_irradiance(irradiance);
+ sg4::this_actor::sleep_for(time_step);
+ time += time_step;
+ }
+}
+
+static void host_job_manager(double start, double duration)
+{
+ sg4::this_actor::sleep_until(start);
+ sg4::this_actor::get_host()->execute(duration * sg4::this_actor::get_host()->get_speed());
+}
+
+static void end_manager(sp::BatteryPtr b)
+{
+ sg4::this_actor::sleep_until(86400 * 2);
+ for (auto& handler : b->get_handlers())
+ b->delete_handler(handler);
+}
+
+static void logger(sp::BatteryPtr battery, sp::SolarPanelPtr solar_panel, sp::ChillerPtr chiller, sg4::Host* host1,
+ sg4::Host* host2)
+{
+ while (true) {
+ XBT_INFO("SoC: %f Solar_Power: %f E_chiller: %f E_hosts_brown: %f E_hosts_green: %f",
+ battery->get_state_of_charge(), solar_panel->get_power(), chiller->get_energy_consumed(),
+ sg_host_get_consumed_energy(host1) + sg_host_get_consumed_energy(host2) - battery->get_energy_provided(),
+ battery->get_energy_provided());
+ simgrid::s4u::this_actor::sleep_for(100);
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ sg4::Engine e(&argc, argv);
+ e.load_platform(argv[1]);
+ sg_host_energy_plugin_init();
+
+ auto myhost1 = e.host_by_name("MyHost1");
+ auto myhost2 = e.host_by_name("MyHost2");
+
+ auto battery = sp::Battery::init("Battery", 0.2, -1e3, 1e3, 0.9, 0.9, 2000, 1000);
+ auto chiller = sp::Chiller::init("Chiller", 50, 1006, 0.2, 0.9, 24, 24, 1e3);
+ auto solar_panel = sp::SolarPanel::init("Solar Panel", 1.1, 0.9, 0, 0, 1e3);
+ chiller->add_host(myhost1);
+ chiller->add_host(myhost2);
+ solar_panel->on_this_power_change_cb(
+ [battery](sp::SolarPanel* s) { battery->set_load("Solar Panel", s->get_power() * -1); });
+ battery->schedule_handler(0.8, sp::Battery::CHARGE, sp::Battery::Handler::PERSISTANT,
+ [battery]() { battery->set_load("Solar Panel", false); });
+ battery->schedule_handler(0.75, sp::Battery::DISCHARGE, sp::Battery::Handler::PERSISTANT,
+ [battery]() { battery->set_load("Solar Panel", true); });
+ battery->schedule_handler(0.2, sp::Battery::DISCHARGE, sp::Battery::Handler::PERSISTANT,
+ [battery, &myhost1, &myhost2]() {
+ battery->connect_host(myhost1, false);
+ battery->connect_host(myhost2, false);
+ });
+ battery->schedule_handler(0.25, sp::Battery::CHARGE, sp::Battery::Handler::PERSISTANT,
+ [battery, &myhost1, &myhost2]() {
+ battery->connect_host(myhost1);
+ battery->connect_host(myhost2);
+ });
+
+ sg4::Actor::create("irradiance_manager", myhost1, irradiance_manager, solar_panel)->daemonize();
+ sg4::Actor::create("host_job_manager", myhost1, host_job_manager, 12 * 60 * 60, 4 * 60 * 60);
+ sg4::Actor::create("host_job_manager", myhost2, host_job_manager, 12 * 60 * 60, 4 * 60 * 60);
+ sg4::Actor::create("end_manager", myhost1, end_manager, battery);
+ // sg4::Actor::create("logger", myhost1, logger, battery, solar_panel, chiller, myhost1, myhost2)->daemonize();
+
+ e.run();
+ XBT_INFO("State of charge of the battery: %0.1f%%", battery->get_state_of_charge() * 100);
+ XBT_INFO(
+ "Energy consumed by the hosts (green / brown): %.2fMJ "
+ "/ %.2fMJ",
+ battery->get_energy_provided() / 1e6,
+ (sg_host_get_consumed_energy(myhost1) + sg_host_get_consumed_energy(myhost2) - battery->get_energy_provided()) /
+ 1e6);
+ XBT_INFO("Energy consumed by the chiller (brown): %.2fMJ", chiller->get_energy_consumed() / 1e6);
+ return 0;
+}
--- /dev/null
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-battery-chiller-solar ${platfdir}/energy_platform.xml
+> [172800.000000] [host_energy/INFO] Total energy consumption: 53568000.000000 Joules (used hosts: 36288000.000000 Joules; unused/idle hosts: 17280000.000000)
+> [172800.000000] [battery_chiller_solar/INFO] State of charge of the battery: 20.4%
+> [172800.000000] [battery_chiller_solar/INFO] Energy consumed by the hosts (green / brown): 21.60MJ / 14.69MJ
+> [172800.000000] [battery_chiller_solar/INFO] Energy consumed by the chiller (brown): 48.38MJ
+> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost1: 17568000.000000 Joules
+> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost2: 18720000.000000 Joules
+> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost3: 17280000.000000 Joules
\ No newline at end of file
{
auto battery = simgrid::plugins::Battery::init("Battery", 0.8, -200, 200, 0.9, 0.9, 10, 100);
- battery->set_load("load", 100);
+ battery->set_load("load", 100.0);
auto handler1 = battery->schedule_handler(
0.2, simgrid::plugins::Battery::DISCHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, [battery]() {
XBT_INFO("%f,%f,SoC", simgrid::s4u::Engine::get_clock(), battery->get_state_of_charge());
XBT_INFO("%f,%f,SoH", simgrid::s4u::Engine::get_clock(), battery->get_state_of_health());
- battery->set_load("load", -100);
+ battery->set_load("load", -100.0);
});
std::shared_ptr<simgrid::plugins::Battery::Handler> handler2;
battery->delete_handler(handler1);
battery->delete_handler(handler2);
}
- battery->set_load("load", 100);
+ battery->set_load("load", 100.0);
});
}
double initial_capacity_wh_;
double energy_budget_j_;
- std::map<const s4u::Host*, bool> host_loads_ = {};
- std::map<const std::string, double> named_loads_ = {};
+ std::map<const s4u::Host*, bool> host_loads_ = {};
+ std::map<const std::string, std::pair<bool, double>> named_loads_ = {};
std::vector<std::shared_ptr<Handler>> handlers_;
double capacity_wh_;
double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency,
double initial_capacity_wh, int cycles);
void set_load(const std::string& name, double power_w);
+ void set_load(const std::string& name, bool active);
void connect_host(s4u::Host* host, bool active = true);
double get_state_of_charge();
double get_state_of_health();
XBT_PUBLIC void intrusive_ptr_release(SolarPanel* o);
XBT_PUBLIC void intrusive_ptr_add_ref(SolarPanel* o);
-class SolarPanelModel : public kernel::resource::Model {
- std::vector<SolarPanelPtr> solar_panels_;
-
-public:
- explicit SolarPanelModel();
-
- void add_solar_panel(SolarPanelPtr b);
- void update_actions_state(double now, double delta) override;
- double next_occurring_event(double now) override;
-};
-
class SolarPanel {
- friend SolarPanelModel;
-
-private:
- static std::shared_ptr<SolarPanelModel> solar_panel_model_;
-
std::string name_;
double area_m2_;
double conversion_efficiency_;
double solar_irradiance_w_per_m2_;
double min_power_w_;
double max_power_w_;
-
- double power_w_ = 0;
- double last_updated_ = 0;
+ double power_w_ = -1;
explicit SolarPanel(std::string name, double area_m2, double conversion_efficiency, double solar_irradiance_w_per_m2,
double min_power_w, double max_power_w);
- static void init_plugin();
void update();
std::atomic_int_fast32_t refcount_{0};
friend void intrusive_ptr_add_ref(SolarPanel* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); }
#endif
+ inline static xbt::signal<void(SolarPanel*)> on_power_change;
+ xbt::signal<void(SolarPanel*)> on_this_power_change;
+
public:
static SolarPanelPtr init(const std::string& name, double area_m2, double conversion_efficiency,
double solar_irradiance_w_per_m2, double min_power_w, double max_power_w);
SolarPanelPtr set_min_power(double power_w);
SolarPanelPtr set_max_power(double power_w);
- std::string get_name() { return name_; }
- const char* get_cname() { return name_.c_str(); }
- double get_area() { return area_m2_; }
- double get_conversion_efficiency() { return conversion_efficiency_; }
- double get_solar_irradiance() { return solar_irradiance_w_per_m2_; }
- double get_min_power() { return min_power_w_; }
- double get_max_power() { return max_power_w_; }
- double get_power() { return power_w_; }
+ std::string get_name() const { return name_; }
+ const char* get_cname() const { return name_.c_str(); }
+ double get_area() const { return area_m2_; }
+ double get_conversion_efficiency() const { return conversion_efficiency_; }
+ double get_solar_irradiance() const { return solar_irradiance_w_per_m2_; }
+ double get_min_power() const { return min_power_w_; }
+ double get_max_power() const { return max_power_w_; }
+ double get_power() const { return power_w_; }
+
+ /** Add a callback fired after this solar panel power changed. */
+ void on_this_power_change_cb(const std::function<void(SolarPanel*)>& func) { on_this_power_change.connect(func); };
+ /** Add a callback fired after a solar panel power changed.
+ * Triggered after the on_this_power_change function.**/
+ static void on_power_change_cb(const std::function<void(SolarPanel*)>& cb) { on_power_change.connect(cb); }
};
} // namespace simgrid::plugins
#endif
#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"
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 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_);
for (auto& handler : handlers_) {
double lost_power_w = provided_power_w / discharge_efficiency_;
double gained_power_w = consumed_power_w * charge_efficiency_;
- // Handler cannot happen
- if ((lost_power_w == gained_power_w) or (handler->state_of_charge_ == energy_stored_j_ / (3600 * capacity_wh_)) or
- (lost_power_w > gained_power_w and handler->flow_ == Flow::CHARGE) or
- (lost_power_w < gained_power_w and handler->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 handler happen
, 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);
*/
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
namespace simgrid::plugins {
-/* SolarPanelModel */
-
-SolarPanelModel::SolarPanelModel() : Model("SolarPanelModel") {}
-
-void SolarPanelModel::add_solar_panel(SolarPanelPtr b)
-{
- solar_panels_.push_back(b);
-}
-
-void SolarPanelModel::update_actions_state(double now, double delta)
-{
- for (auto solar_panel : solar_panels_)
- solar_panel->update();
-}
-
-double SolarPanelModel::next_occurring_event(double now)
-{
- return -1;
-}
-
/* SolarPanel */
-std::shared_ptr<SolarPanelModel> SolarPanel::solar_panel_model_;
-
-void SolarPanel::init_plugin()
-{
- auto model = std::make_shared<SolarPanelModel>();
- simgrid::s4u::Engine::get_instance()->add_model(model);
- SolarPanel::solar_panel_model_ = model;
-}
-
void SolarPanel::update()
{
simgrid::kernel::actor::simcall_answered([this] {
- double now = simgrid::s4u::Engine::get_clock();
- if (now <= last_updated_)
- return;
double power_w = conversion_efficiency_ * area_m2_ * solar_irradiance_w_per_m2_;
- if (power_w_ < min_power_w_)
+ if (power_w < min_power_w_)
power_w = 0;
- if (power_w_ > max_power_w_)
+ if (power_w > max_power_w_)
power_w = max_power_w_;
- power_w_ = power_w;
- last_updated_ = now;
+ auto previous_power_w = power_w_;
+ power_w_ = power_w;
+ if (previous_power_w != power_w_) {
+ on_this_power_change(this);
+ on_power_change(this);
+ }
});
}
SolarPanelPtr SolarPanel::init(const std::string& name, double area_m2, double conversion_efficiency,
double solar_irradiance_w_per_m2, double min_power_w, double max_power_w)
{
- static bool plugin_inited = false;
- if (not plugin_inited) {
- init_plugin();
- plugin_inited = true;
- }
auto solar_panel = SolarPanelPtr(
new SolarPanel(name, area_m2, conversion_efficiency, solar_irradiance_w_per_m2, min_power_w, max_power_w));
- solar_panel_model_->add_solar_panel(solar_panel);
+ solar_panel->update();
return solar_panel;
}
{
xbt_assert(area_m2 >= 0, " : area must be > 0 (provided: %f)", area_m2);
kernel::actor::simcall_answered([this, area_m2] { area_m2_ = area_m2; });
+ update();
return this;
}
{
xbt_assert(e >= 0 and e <= 1, " : conversion efficiency must be in [0,1] (provided: %f)", e);
kernel::actor::simcall_answered([this, e] { conversion_efficiency_ = e; });
+ update();
return this;
}
solar_irradiance_w_per_m2);
kernel::actor::simcall_answered(
[this, solar_irradiance_w_per_m2] { solar_irradiance_w_per_m2_ = solar_irradiance_w_per_m2; });
+ update();
return this;
}
xbt_assert(max_power_w_ > power_w, " : maximal power must be above minimal power (provided: %f, max: %f)", power_w,
max_power_w_);
kernel::actor::simcall_answered([this, power_w] { min_power_w_ = power_w; });
+ update();
return this;
}
xbt_assert(min_power_w_ < power_w, " : maximal power must be above minimal power (provided: %f, min: %f)", power_w,
min_power_w_);
kernel::actor::simcall_answered([this, power_w] { max_power_w_ = power_w; });
+ update();
return this;
}