From: Martin Quinson Date: Mon, 30 Oct 2023 02:36:31 +0000 (+0000) Subject: Merge branch 'example-battery-chiller-solar' into 'master' X-Git-Tag: v3.35~89^2~29 X-Git-Url: http://bilbo.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/5d565c9f388ee34b957b69a595e98bbfaf06fb10?hp=1105688a093bb0555040b34ebe3f88eaf5072f55 Merge branch 'example-battery-chiller-solar' into 'master' add battery-chiller-solar example. See merge request simgrid/simgrid!174 --- diff --git a/MANIFEST.in b/MANIFEST.in index 610932ba7d..2c3927c307 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -166,6 +166,10 @@ include examples/cpp/app-masterworkers/s4u-app-masterworkers.tesh 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 diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index b917540cf1..6f1af7f34e 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -157,7 +157,7 @@ foreach (example activityset-testany activityset-waitany activityset-waitall act 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 diff --git a/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp new file mode 100644 index 0000000000..c428b32948 --- /dev/null +++ b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp @@ -0,0 +1,115 @@ +/* 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 + +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; +} diff --git a/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh new file mode 100644 index 0000000000..f2cddf46e3 --- /dev/null +++ b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh @@ -0,0 +1,10 @@ +#!/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 diff --git a/examples/cpp/battery-connector/s4u-battery-connector.cpp b/examples/cpp/battery-connector/s4u-battery-connector.cpp new file mode 100644 index 0000000000..b4d9434580 --- /dev/null +++ b/examples/cpp/battery-connector/s4u-battery-connector.cpp @@ -0,0 +1,63 @@ +/* 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 +#include +#include + +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; +} diff --git a/examples/cpp/battery-connector/s4u-battery-connector.tesh b/examples/cpp/battery-connector/s4u-battery-connector.tesh new file mode 100644 index 0000000000..2dd264da3f --- /dev/null +++ b/examples/cpp/battery-connector/s4u-battery-connector.tesh @@ -0,0 +1,13 @@ +#!/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 diff --git a/examples/cpp/battery-degradation/s4u-battery-degradation.cpp b/examples/cpp/battery-degradation/s4u-battery-degradation.cpp index 9510404fa0..13b149ef46 100644 --- a/examples/cpp/battery-degradation/s4u-battery-degradation.cpp +++ b/examples/cpp/battery-degradation/s4u-battery-degradation.cpp @@ -14,13 +14,13 @@ static void manager() { 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 handler2; @@ -33,7 +33,7 @@ static void manager() battery->delete_handler(handler1); battery->delete_handler(handler2); } - battery->set_load("load", 100); + battery->set_load("load", 100.0); }); } diff --git a/examples/cpp/chiller-simple/s4u-chiller-simple.cpp b/examples/cpp/chiller-simple/s4u-chiller-simple.cpp index c5a45b3d16..079d7c5b39 100644 --- a/examples/cpp/chiller-simple/s4u-chiller-simple.cpp +++ b/examples/cpp/chiller-simple/s4u-chiller-simple.cpp @@ -16,49 +16,21 @@ static void manager(simgrid::plugins::ChillerPtr c) 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[]) @@ -72,6 +44,10 @@ 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; diff --git a/examples/cpp/chiller-simple/s4u-chiller-simple.tesh b/examples/cpp/chiller-simple/s4u-chiller-simple.tesh index c1d4c27f46..cdad59de11 100644 --- a/examples/cpp/chiller-simple/s4u-chiller-simple.tesh +++ b/examples/cpp/chiller-simple/s4u-chiller-simple.tesh @@ -4,21 +4,18 @@ $ ${bindir:=.}/s4u-chiller-simple ${platfdir}/energy_platform.xml > [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 diff --git a/include/simgrid/plugins/battery.hpp b/include/simgrid/plugins/battery.hpp index 7f0c3618ef..058428beb4 100644 --- a/include/simgrid/plugins/battery.hpp +++ b/include/simgrid/plugins/battery.hpp @@ -6,6 +6,7 @@ #ifndef SIMGRID_PLUGINS_BATTERY_HPP_ #define SIMGRID_PLUGINS_BATTERY_HPP_ +#include #include #include #include @@ -87,23 +88,24 @@ private: static std::shared_ptr 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 host_loads_ = {}; - std::map 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 host_loads_ = {}; + std::map> named_loads_ = {}; std::vector> 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); @@ -124,10 +126,12 @@ private: #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(); diff --git a/include/simgrid/plugins/chiller.hpp b/include/simgrid/plugins/chiller.hpp index b60e03dc82..f0297fabd9 100644 --- a/include/simgrid/plugins/chiller.hpp +++ b/include/simgrid/plugins/chiller.hpp @@ -68,6 +68,9 @@ private: friend void intrusive_ptr_add_ref(Chiller* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); } #endif + inline static xbt::signal on_power_change; + xbt::signal 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); @@ -96,6 +99,13 @@ public: 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& 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& cb) { on_power_change.connect(cb); } }; } // namespace simgrid::plugins diff --git a/include/simgrid/plugins/solar_panel.hpp b/include/simgrid/plugins/solar_panel.hpp index b9097b416f..5fa424bd36 100644 --- a/include/simgrid/plugins/solar_panel.hpp +++ b/include/simgrid/plugins/solar_panel.hpp @@ -16,37 +16,18 @@ using SolarPanelPtr = boost::intrusive_ptr; 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 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 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}; @@ -61,6 +42,9 @@ private: friend void intrusive_ptr_add_ref(SolarPanel* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); } #endif + inline static xbt::signal on_power_change; + xbt::signal 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); @@ -72,14 +56,20 @@ public: 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& 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& cb) { on_power_change.connect(cb); } }; } // namespace simgrid::plugins #endif diff --git a/src/plugins/battery.cpp b/src/plugins/battery.cpp index 412b69ed0f..9639bf67e5 100644 --- a/src/plugins/battery.cpp +++ b/src/plugins/battery.cpp @@ -6,10 +6,7 @@ #include #include #include -#include #include -#include -#include #include "src/kernel/resource/CpuImpl.hpp" #include "src/simgrid/module.hpp" @@ -84,6 +81,12 @@ You can schedule handlers that will happen at specific SoC of the battery and tr 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"); @@ -107,6 +110,11 @@ void BatteryModel::update_actions_state(double now, double delta) 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(); @@ -154,12 +162,15 @@ 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; - 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_); @@ -182,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_; + + // 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_); @@ -210,11 +229,13 @@ double 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_); @@ -224,10 +245,11 @@ double Battery::next_occurring_handler() 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 @@ -250,6 +272,8 @@ double Battery::next_occurring_handler() 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) @@ -263,7 +287,7 @@ Battery::Battery(const std::string& name, double state_of_charge, double nominal , 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); @@ -277,11 +301,29 @@ Battery::Battery(const std::string& name, double state_of_charge, double nominal 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). @@ -309,7 +351,21 @@ BatteryPtr Battery::init(const std::string& name, double state_of_charge, double */ 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 @@ -322,7 +378,7 @@ void Battery::set_load(const std::string& name, double power_w) */ 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 diff --git a/src/plugins/chiller.cpp b/src/plugins/chiller.cpp index 501f155865..b0c814e5db 100644 --- a/src/plugins/chiller.cpp +++ b/src/plugins/chiller.cpp @@ -75,7 +75,19 @@ void ChillerModel::update_actions_state(double now, double delta) 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 */ @@ -105,7 +117,7 @@ void Chiller::update() 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; @@ -113,17 +125,16 @@ void Chiller::update() } 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; }); } @@ -284,4 +295,20 @@ ChillerPtr Chiller::remove_host(s4u::Host* host) 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 diff --git a/src/plugins/solar_panel.cpp b/src/plugins/solar_panel.cpp index 8e44734b82..abf999513d 100644 --- a/src/plugins/solar_panel.cpp +++ b/src/plugins/solar_panel.cpp @@ -43,50 +43,22 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(SolarPanel, kernel, "Logging specific to the sol 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 SolarPanel::solar_panel_model_; - -void SolarPanel::init_plugin() -{ - auto model = std::make_shared(); - 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); + } }); } @@ -122,14 +94,9 @@ SolarPanel::SolarPanel(std::string name, double area_m2, double conversion_effic 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; } @@ -151,6 +118,7 @@ SolarPanelPtr SolarPanel::set_area(double area_m2) { 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; } @@ -162,6 +130,7 @@ SolarPanelPtr SolarPanel::set_conversion_efficiency(double e) { 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; } @@ -175,6 +144,7 @@ SolarPanelPtr SolarPanel::set_solar_irradiance(double solar_irradiance_w_per_m2) 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; } @@ -188,6 +158,7 @@ SolarPanelPtr SolarPanel::set_min_power(double power_w) 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; } @@ -201,6 +172,7 @@ SolarPanelPtr SolarPanel::set_max_power(double power_w) 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; }