add battery-chiller-solar example.
See merge request simgrid/simgrid!174
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-connector/s4u-battery-connector.cpp
+include examples/cpp/battery-connector/s4u-battery-connector.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-connector 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);
+}
+
+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);
+
+ 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
--- /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 shows how to use the battery as a connector.
+ A solar panel is connected to the connector and power a host.
+*/
+
+#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>
+#include <simgrid/s4u/Actor.hpp>
+#include <xbt/log.h>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(battery_chiller_solar, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+namespace sp = simgrid::plugins;
+
+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 connector = sp::Battery::init();
+ auto solar_panel = sp::SolarPanel::init("Solar Panel", 1, 1, 200, 0, 1e3);
+
+ connector->set_load("Solar Panel", solar_panel->get_power() * -1);
+ connector->connect_host(myhost1);
+
+ solar_panel->on_this_power_change_cb([connector](sp::SolarPanel *s) {
+ connector->set_load("Solar Panel", s->get_power() * -1);
+ });
+
+ sg4::Actor::create("manager", myhost1, [&myhost1, & solar_panel, &connector]{
+ XBT_INFO("Solar Panel power = %.2fW, MyHost1 power = %.2fW. The Solar Panel provides more than needed.", solar_panel->get_power(), sg_host_get_current_consumption(myhost1));
+ simgrid::s4u::this_actor::sleep_for(100);
+ XBT_INFO("Energy consumption MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", sg_host_get_consumed_energy(myhost1) / 1e3, connector->get_energy_provided() / 1e3);
+
+ solar_panel->set_solar_irradiance(100);
+ XBT_INFO("Solar Panel power = %.2fW, MyHost1 power = %.2fW. The Solar Panel provides exactly what is needed.", solar_panel->get_power(), sg_host_get_current_consumption(myhost1));
+ double last_measure_host_energy = sg_host_get_consumed_energy(myhost1);
+ double last_measure_connector_energy = connector->get_energy_provided();
+
+ simgrid::s4u::this_actor::sleep_for(100);
+ XBT_INFO("Energy consumption MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", (sg_host_get_consumed_energy(myhost1) - last_measure_host_energy) / 1e3, (connector->get_energy_provided() - last_measure_connector_energy) / 1e3);
+
+ XBT_INFO("MyHost1 executes something for 100s. The Solar Panel does not provide enough energy.");
+ last_measure_host_energy = sg_host_get_consumed_energy(myhost1);
+ last_measure_connector_energy = connector->get_energy_provided();
+ myhost1->execute(100 * myhost1->get_speed());
+ XBT_INFO("Energy MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", (sg_host_get_consumed_energy(myhost1) - last_measure_host_energy) / 1e3, (connector->get_energy_provided() - last_measure_connector_energy) / 1e3);
+ });
+
+ e.run();
+ return 0;
+}
--- /dev/null
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-battery-connector ${platfdir}/energy_platform.xml
+> [MyHost1:manager:(1) 0.000000] [battery_chiller_solar/INFO] Solar Panel power = 200.00W, MyHost1 power = 100.00W. The Solar Panel provides more than needed.
+> [MyHost1:manager:(1) 100.000000] [battery_chiller_solar/INFO] Energy consumption MyHost1: 10.00kJ, Energy from the Solar Panel 10.00kJ
+> [MyHost1:manager:(1) 100.000000] [battery_chiller_solar/INFO] Solar Panel power = 100.00W, MyHost1 power = 100.00W. The Solar Panel provides exactly what is needed.
+> [MyHost1:manager:(1) 200.000000] [battery_chiller_solar/INFO] Energy consumption MyHost1: 10.00kJ, Energy from the Solar Panel 10.00kJ
+> [MyHost1:manager:(1) 200.000000] [battery_chiller_solar/INFO] MyHost1 executes something for 100s. The Solar Panel does not provide enough energy.
+> [MyHost1:manager:(1) 300.000000] [battery_chiller_solar/INFO] Energy MyHost1: 12.00kJ, Energy from the Solar Panel 10.00kJ
+> [300.000000] [host_energy/INFO] Total energy consumption: 92000.000000 Joules (used hosts: 32000.000000 Joules; unused/idle hosts: 60000.000000)
+> [300.000000] [host_energy/INFO] Energy consumption of host MyHost1: 32000.000000 Joules
+> [300.000000] [host_energy/INFO] Energy consumption of host MyHost2: 30000.000000 Joules
+> [300.000000] [host_energy/INFO] Energy consumption of host MyHost3: 30000.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);
});
}
XBT_INFO("Initial state: ");
XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
c->get_energy_consumed());
-
XBT_INFO("The machines slowly heat up the room.");
- simgrid::s4u::this_actor::sleep_until(400);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
- simgrid::s4u::this_actor::sleep_until(800);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
simgrid::s4u::this_actor::sleep_until(1000);
XBT_INFO("The Chiller now compensates the heat generated by the machines.");
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
simgrid::s4u::this_actor::sleep_until(1200);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
-
XBT_INFO("Let's compute something.");
sg4::this_actor::exec_async(1e10);
- simgrid::s4u::this_actor::sleep_until(1250);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
-
simgrid::s4u::this_actor::sleep_until(1300);
XBT_INFO("Computation done.");
-
simgrid::s4u::this_actor::sleep_until(1400);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
-
XBT_INFO("Now let's stress the chiller by decreasing the goal temperature to 23°C.");
c->set_goal_temp(23);
- simgrid::s4u::this_actor::sleep_until(1600);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
- simgrid::s4u::this_actor::sleep_until(1800);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
+
+ simgrid::s4u::this_actor::sleep_until(1900);
simgrid::s4u::this_actor::sleep_until(2000);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
- simgrid::s4u::this_actor::sleep_until(2200);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
+ simgrid::s4u::this_actor::sleep_until(2100);
}
int main(int argc, char* argv[])
chiller->add_host(e.host_by_name("MyHost2"));
chiller->add_host(e.host_by_name("MyHost3"));
sg4::Actor::create("sender", e.host_by_name("MyHost1"), manager, chiller);
+ chiller->on_power_change_cb([](simgrid::plugins::Chiller* c) {
+ XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
+ c->get_energy_consumed());
+ });
e.run();
return 0;
> [MyHost1:sender:(1) 0.000000] [chiller_simple/INFO] Initial state:
> [MyHost1:sender:(1) 0.000000] [chiller_simple/INFO] Chiller: Power: 0.000000W T_in: 23.000000°C Energy consumed: 0.000000J
> [MyHost1:sender:(1) 0.000000] [chiller_simple/INFO] The machines slowly heat up the room.
-> [MyHost1:sender:(1) 400.000000] [chiller_simple/INFO] Chiller: Power: 0.000000W T_in: 23.486875°C Energy consumed: 0.000000J
-> [MyHost1:sender:(1) 800.000000] [chiller_simple/INFO] Chiller: Power: 0.000000W T_in: 23.973749°C Energy consumed: 0.000000J
+> [1000.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 71373.333333J
> [MyHost1:sender:(1) 1000.000000] [chiller_simple/INFO] The Chiller now compensates the heat generated by the machines.
-> [MyHost1:sender:(1) 1000.000000] [chiller_simple/INFO] Chiller: Power: 356.866667W T_in: 24.000000°C Energy consumed: 71373.333333J
-> [MyHost1:sender:(1) 1200.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 151373.333333J
+> [1200.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 151373.333333J
> [MyHost1:sender:(1) 1200.000000] [chiller_simple/INFO] Let's compute something.
-> [MyHost1:sender:(1) 1250.000000] [chiller_simple/INFO] Chiller: Power: 426.666667W T_in: 24.000000°C Energy consumed: 172706.666667J
+> [1300.000000] [chiller_simple/INFO] Chiller: Power: 426.666667W T_in: 24.000000°C Energy consumed: 194040.000000J
> [MyHost1:sender:(1) 1300.000000] [chiller_simple/INFO] Computation done.
-> [MyHost1:sender:(1) 1400.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 234040.000000J
+> [1400.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 234040.000000J
> [MyHost1:sender:(1) 1400.000000] [chiller_simple/INFO] Now let's stress the chiller by decreasing the goal temperature to 23°C.
-> [MyHost1:sender:(1) 1600.000000] [chiller_simple/INFO] Chiller: Power: 1000.000000W T_in: 23.634844°C Energy consumed: 434040.000000J
-> [MyHost1:sender:(1) 1800.000000] [chiller_simple/INFO] Chiller: Power: 1000.000000W T_in: 23.269688°C Energy consumed: 634040.000000J
-> [MyHost1:sender:(1) 2000.000000] [chiller_simple/INFO] Chiller: Power: 843.133333W T_in: 23.000000°C Energy consumed: 802666.666667J
-> [MyHost1:sender:(1) 2200.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 23.000000°C Energy consumed: 882666.666667J
-> [2200.000000] [host_energy/INFO] Total energy consumption: 662000.000000 Joules (used hosts: 222000.000000 Joules; unused/idle hosts: 440000.000000)
-> [2200.000000] [host_energy/INFO] Energy consumption of host MyHost1: 222000.000000 Joules
-> [2200.000000] [host_energy/INFO] Energy consumption of host MyHost2: 220000.000000 Joules
-> [2200.000000] [host_energy/INFO] Energy consumption of host MyHost3: 220000.000000 Joules
+> [1900.000000] [chiller_simple/INFO] Chiller: Power: 1000.000000W T_in: 23.087110°C Energy consumed: 734040.000000J
+> [2000.000000] [chiller_simple/INFO] Chiller: Power: 686.266667W T_in: 23.000000°C Energy consumed: 802666.666667J
+> [2100.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 23.000000°C Energy consumed: 842666.666667J
+> [2100.000000] [host_energy/INFO] Total energy consumption: 632000.000000 Joules (used hosts: 212000.000000 Joules; unused/idle hosts: 420000.000000)
+> [2100.000000] [host_energy/INFO] Energy consumption of host MyHost1: 212000.000000 Joules
+> [2100.000000] [host_energy/INFO] Energy consumption of host MyHost2: 210000.000000 Joules
+> [2100.000000] [host_energy/INFO] Energy consumption of host MyHost3: 210000.000000 Joules
\ No newline at end of file
#ifndef SIMGRID_PLUGINS_BATTERY_HPP_
#define SIMGRID_PLUGINS_BATTERY_HPP_
+#include <cmath>
#include <memory>
#include <simgrid/kernel/resource/Model.hpp>
#include <simgrid/s4u/Activity.hpp>
static std::shared_ptr<BatteryModel> battery_model_;
std::string name_;
- double nominal_charge_power_w_;
- double nominal_discharge_power_w_;
- double charge_efficiency_;
- double discharge_efficiency_;
- double initial_capacity_wh_;
- double energy_budget_j_;
-
- std::map<const s4u::Host*, bool> host_loads_ = {};
- std::map<const std::string, double> named_loads_ = {};
+ double nominal_charge_power_w_ = -INFINITY;
+ double nominal_discharge_power_w_ = INFINITY;
+ double charge_efficiency_ = 1;
+ double discharge_efficiency_ = 1;
+ double initial_capacity_wh_ = 0;
+ double energy_budget_j_ = 0;
+
+ 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 energy_stored_j_;
+ double capacity_wh_ = 0;
+ double energy_stored_j_ = 0;
double energy_provided_j_ = 0;
double energy_consumed_j_ = 0;
double last_updated_ = 0;
+ explicit Battery();
explicit 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);
#endif
public:
+ static BatteryPtr init();
static BatteryPtr 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);
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();
friend void intrusive_ptr_add_ref(Chiller* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); }
#endif
+ inline static xbt::signal<void(Chiller*)> on_power_change;
+ xbt::signal<void(Chiller*)> on_this_power_change;
+
public:
static ChillerPtr init(const std::string& name, double air_mass_kg, double specific_heat_j_per_kg_per_c, double alpha,
double cooling_efficiency, double initial_temp_c, double goal_temp_c, double max_power_w);
double get_temp_out() { return temp_out_c_; }
double get_power() { return power_w_; }
double get_energy_consumed() { return energy_consumed_j_; }
+ double get_next_event();
+
+ /** Add a callback fired after this chiller power changed. */
+ void on_this_power_change_cb(const std::function<void(Chiller*)>& func) { on_this_power_change.connect(func); };
+ /** Add a callback fired after a chiller power changed.
+ * Triggered after the on_this_power_change function.**/
+ static void on_power_change_cb(const std::function<void(Chiller*)>& cb) { on_power_change.connect(cb); }
};
} // namespace simgrid::plugins
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"
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_handler();
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_);
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
return time_delta;
}
+Battery::Battery() {}
+
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)
, 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
double ChillerModel::next_occurring_event(double now)
{
- return -1;
+ static bool init = false;
+ if (!init) {
+ init = true;
+ return 0;
+ }
+ double next_event = -1;
+ double tmp;
+ for (auto chiller : chillers_) {
+ tmp = chiller->get_next_event();
+ if (tmp != -1 and (next_event == -1 or tmp < next_event))
+ next_event = tmp;
+ }
+ return next_event;
}
/* Chiller */
temp_out_c_ = temp_in_c_ + heat_generated_j / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
double delta_temp_c = temp_out_c_ - goal_temp_c_;
- if (not active_ or delta_temp_c < 0) {
+ if (not active_ or delta_temp_c <= 0) {
temp_in_c_ = temp_out_c_;
power_w_ = 0;
last_updated_ = now;
}
double cooling_demand_w = delta_temp_c * air_mass_kg_ * specific_heat_j_per_kg_per_c_ / time_delta_s;
- if (cooling_demand_w / cooling_efficiency_ <= max_power_w_) {
- power_w_ = cooling_demand_w / cooling_efficiency_;
- temp_in_c_ = temp_out_c_ -
- (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
- } else {
- power_w_ = max_power_w_;
- temp_in_c_ = temp_out_c_ -
- (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
- }
+ double previous_power_w = power_w_;
+ power_w_ = std::min(max_power_w_, cooling_demand_w / cooling_efficiency_);
+ temp_in_c_ =
+ temp_out_c_ - (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
energy_consumed_j_ += power_w_ * time_delta_s;
+ if (previous_power_w != power_w_) {
+ on_this_power_change(this);
+ on_power_change(this);
+ }
last_updated_ = now;
});
}
return this;
}
+/** @ingroup plugin_chiller
+ * @return Time of the next event, i.e.,
+ when the chiller will reach the goal temp if possible, -1 otherwise.
+ */
+double Chiller::get_next_event()
+{
+ if (not is_active() or goal_temp_c_ <= temp_out_c_)
+ return -1;
+ else {
+ double heat_power_w = 0;
+ for (auto const& host : hosts_)
+ heat_power_w += sg_host_get_current_consumption(host);
+ heat_power_w = heat_power_w * (1 + alpha_);
+ return air_mass_kg_ * (goal_temp_c_ - temp_out_c_) * specific_heat_j_per_kg_per_c_ / heat_power_w;
+ }
+}
} // namespace simgrid::plugins
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;
}