Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
add possibility for a battery to be a simple connector and an example. add power...
authorAdrien Gougeon <adrien.gougeon@ens-rennes.fr>
Mon, 9 Oct 2023 15:51:47 +0000 (17:51 +0200)
committerAdrien Gougeon <adrien.gougeon@ens-rennes.fr>
Mon, 9 Oct 2023 15:51:47 +0000 (17:51 +0200)
MANIFEST.in
examples/cpp/CMakeLists.txt
examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp
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/chiller-simple/s4u-chiller-simple.cpp
examples/cpp/chiller-simple/s4u-chiller-simple.tesh
include/simgrid/plugins/battery.hpp
include/simgrid/plugins/chiller.hpp
src/plugins/battery.cpp
src/plugins/chiller.cpp

index 5e93c83..422f0e4 100644 (file)
@@ -168,6 +168,8 @@ 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 abda109..a0fc73f 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-chiller-solar 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
index 454b259..c428b32 100644 (file)
@@ -66,18 +66,6 @@ static void end_manager(sp::BatteryPtr b)
     b->delete_handler(handler);
 }
 
-static void logger(sp::BatteryPtr battery, sp::SolarPanelPtr solar_panel, sp::ChillerPtr chiller, sg4::Host* host1,
-                   sg4::Host* host2)
-{
-  while (true) {
-    XBT_INFO("SoC: %f Solar_Power: %f E_chiller: %f E_hosts_brown: %f E_hosts_green: %f",
-             battery->get_state_of_charge(), solar_panel->get_power(), chiller->get_energy_consumed(),
-             sg_host_get_consumed_energy(host1) + sg_host_get_consumed_energy(host2) - battery->get_energy_provided(),
-             battery->get_energy_provided());
-    simgrid::s4u::this_actor::sleep_for(100);
-  }
-}
-
 int main(int argc, char* argv[])
 {
   sg4::Engine e(&argc, argv);
@@ -113,7 +101,6 @@ int main(int argc, char* argv[])
   sg4::Actor::create("host_job_manager", myhost1, host_job_manager, 12 * 60 * 60, 4 * 60 * 60);
   sg4::Actor::create("host_job_manager", myhost2, host_job_manager, 12 * 60 * 60, 4 * 60 * 60);
   sg4::Actor::create("end_manager", myhost1, end_manager, battery);
-  // sg4::Actor::create("logger", myhost1, logger, battery, solar_panel, chiller, myhost1, myhost2)->daemonize();
 
   e.run();
   XBT_INFO("State of charge of the battery: %0.1f%%", battery->get_state_of_charge() * 100);
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 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 64c9753..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_;
+  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,6 +126,7 @@ 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);
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 bf18ae1..9639bf6 100644 (file)
@@ -81,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");
@@ -104,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();
@@ -159,6 +170,7 @@ void Battery::update()
       else
         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_);
 
@@ -181,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_);
@@ -252,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)
@@ -279,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).
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