Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'example-battery-chiller-solar' into 'master'
authorMartin Quinson <martin.quinson@ens-rennes.fr>
Mon, 30 Oct 2023 02:36:31 +0000 (02:36 +0000)
committerMartin Quinson <martin.quinson@ens-rennes.fr>
Mon, 30 Oct 2023 02:36:31 +0000 (02:36 +0000)
add battery-chiller-solar example.

See merge request simgrid/simgrid!174

15 files changed:
MANIFEST.in
examples/cpp/CMakeLists.txt
examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp [new file with mode: 0644]
examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh [new file with mode: 0644]
examples/cpp/battery-connector/s4u-battery-connector.cpp [new file with mode: 0644]
examples/cpp/battery-connector/s4u-battery-connector.tesh [new file with mode: 0644]
examples/cpp/battery-degradation/s4u-battery-degradation.cpp
examples/cpp/chiller-simple/s4u-chiller-simple.cpp
examples/cpp/chiller-simple/s4u-chiller-simple.tesh
include/simgrid/plugins/battery.hpp
include/simgrid/plugins/chiller.hpp
include/simgrid/plugins/solar_panel.hpp
src/plugins/battery.cpp
src/plugins/chiller.cpp
src/plugins/solar_panel.cpp

index 610932b..2c3927c 100644 (file)
@@ -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
index b917540..6f1af7f 100644 (file)
@@ -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 (file)
index 0000000..c428b32
--- /dev/null
@@ -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 <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;
+}
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 (file)
index 0000000..f2cddf4
--- /dev/null
@@ -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 (file)
index 0000000..b4d9434
--- /dev/null
@@ -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 <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;
+}
diff --git a/examples/cpp/battery-connector/s4u-battery-connector.tesh b/examples/cpp/battery-connector/s4u-battery-connector.tesh
new file mode 100644 (file)
index 0000000..2dd264d
--- /dev/null
@@ -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
index 9510404..13b149e 100644 (file)
@@ -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<simgrid::plugins::Battery::Handler> 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);
       });
 }
 
index c5a45b3..079d7c5 100644 (file)
@@ -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;
index c1d4c27..cdad59d 100644 (file)
@@ -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
index 7f0c361..058428b 100644 (file)
@@ -6,6 +6,7 @@
 #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>
@@ -87,23 +88,24 @@ private:
   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);
@@ -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();
index b60e03d..f0297fa 100644 (file)
@@ -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<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);
@@ -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<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
index b9097b4..5fa424b 100644 (file)
@@ -16,37 +16,18 @@ using SolarPanelPtr = boost::intrusive_ptr<SolarPanel>;
 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};
@@ -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<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);
@@ -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<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
index 412b69e..9639bf6 100644 (file)
@@ -6,10 +6,7 @@
 #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"
@@ -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
index 501f155..b0c814e 100644 (file)
@@ -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
index 8e44734..abf9995 100644 (file)
@@ -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<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);
+    }
   });
 }
 
@@ -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;
 }