Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
add battery-chiller-solar example.
authorAdrien Gougeon <adrien.gougeon@ens-rennes.fr>
Thu, 28 Sep 2023 08:26:02 +0000 (10:26 +0200)
committerAdrien Gougeon <adrien.gougeon@ens-rennes.fr>
Thu, 28 Sep 2023 08:26:02 +0000 (10:26 +0200)
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-degradation/s4u-battery-degradation.cpp
include/simgrid/plugins/battery.hpp
include/simgrid/plugins/solar_panel.hpp
src/plugins/battery.cpp
src/plugins/solar_panel.cpp

index d33f19f..5e93c83 100644 (file)
@@ -166,6 +166,8 @@ 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-degradation/plot_battery_degradation.py
 include examples/cpp/battery-degradation/s4u-battery-degradation.cpp
 include examples/cpp/battery-degradation/s4u-battery-degradation.tesh
index 2ddf038..abda109 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-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..454b259
--- /dev/null
@@ -0,0 +1,128 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example combine the battery plugin, the chiller plugin and the solar
+   panel plugin. It illustrates how to use them together to evaluate the amount
+   of brown energy (from the electrical grid) and green energy (from the solar
+   panel) consumed by several machines.
+
+   In this scenario we have two host placed in a room.
+   The room is maintained at 24°C by a chiller, powered by the electrical grid
+   and consumes brown energy.
+   The two hosts are powered by a battery when available, and the electrical
+   grid otherwise. The battery is charged by a solar panel.
+
+   We simulate two days from 00h00 to 00h00.
+   The solar panel generates power from 8h to 20h with a peak at 14h.
+   During the simulation, when the charge of the battery goes:
+    - below 75% the solar panel is connected to the battery
+    - above 80% the solar panel is disconnected from the battery
+    - below 20% the hosts are disconnected from the battery
+    - above 25% the hosts are connected to the battery
+
+   The two hosts are always idle, except from 12h to 16h on the first day.
+*/
+
+#include "simgrid/plugins/battery.hpp"
+#include "simgrid/plugins/chiller.hpp"
+#include "simgrid/plugins/energy.h"
+#include "simgrid/plugins/solar_panel.hpp"
+#include "simgrid/s4u.hpp"
+#include <math.h>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(battery_chiller_solar, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+namespace sp  = simgrid::plugins;
+
+static void irradiance_manager(sp::SolarPanelPtr solar_panel)
+{
+  int time         = 0;
+  int time_step    = 10;
+  double amplitude = 1000 / 2.0;
+  double period    = 24 * 60 * 60;
+  double shift     = 16 * 60 * 60;
+  double irradiance;
+  while (true) {
+    irradiance = amplitude * sin(2 * M_PI * (time + shift) / period);
+    irradiance = irradiance < 0 ? 0 : irradiance;
+    solar_panel->set_solar_irradiance(irradiance);
+    sg4::this_actor::sleep_for(time_step);
+    time += time_step;
+  }
+}
+
+static void host_job_manager(double start, double duration)
+{
+  sg4::this_actor::sleep_until(start);
+  sg4::this_actor::get_host()->execute(duration * sg4::this_actor::get_host()->get_speed());
+}
+
+static void end_manager(sp::BatteryPtr b)
+{
+  sg4::this_actor::sleep_until(86400 * 2);
+  for (auto& handler : b->get_handlers())
+    b->delete_handler(handler);
+}
+
+static void logger(sp::BatteryPtr battery, sp::SolarPanelPtr solar_panel, sp::ChillerPtr chiller, sg4::Host* host1,
+                   sg4::Host* host2)
+{
+  while (true) {
+    XBT_INFO("SoC: %f Solar_Power: %f E_chiller: %f E_hosts_brown: %f E_hosts_green: %f",
+             battery->get_state_of_charge(), solar_panel->get_power(), chiller->get_energy_consumed(),
+             sg_host_get_consumed_energy(host1) + sg_host_get_consumed_energy(host2) - battery->get_energy_provided(),
+             battery->get_energy_provided());
+    simgrid::s4u::this_actor::sleep_for(100);
+  }
+}
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+  sg_host_energy_plugin_init();
+
+  auto myhost1 = e.host_by_name("MyHost1");
+  auto myhost2 = e.host_by_name("MyHost2");
+
+  auto battery     = sp::Battery::init("Battery", 0.2, -1e3, 1e3, 0.9, 0.9, 2000, 1000);
+  auto chiller     = sp::Chiller::init("Chiller", 50, 1006, 0.2, 0.9, 24, 24, 1e3);
+  auto solar_panel = sp::SolarPanel::init("Solar Panel", 1.1, 0.9, 0, 0, 1e3);
+  chiller->add_host(myhost1);
+  chiller->add_host(myhost2);
+  solar_panel->on_this_power_change_cb(
+      [battery](sp::SolarPanel* s) { battery->set_load("Solar Panel", s->get_power() * -1); });
+  battery->schedule_handler(0.8, sp::Battery::CHARGE, sp::Battery::Handler::PERSISTANT,
+                            [battery]() { battery->set_load("Solar Panel", false); });
+  battery->schedule_handler(0.75, sp::Battery::DISCHARGE, sp::Battery::Handler::PERSISTANT,
+                            [battery]() { battery->set_load("Solar Panel", true); });
+  battery->schedule_handler(0.2, sp::Battery::DISCHARGE, sp::Battery::Handler::PERSISTANT,
+                            [battery, &myhost1, &myhost2]() {
+                              battery->connect_host(myhost1, false);
+                              battery->connect_host(myhost2, false);
+                            });
+  battery->schedule_handler(0.25, sp::Battery::CHARGE, sp::Battery::Handler::PERSISTANT,
+                            [battery, &myhost1, &myhost2]() {
+                              battery->connect_host(myhost1);
+                              battery->connect_host(myhost2);
+                            });
+
+  sg4::Actor::create("irradiance_manager", myhost1, irradiance_manager, solar_panel)->daemonize();
+  sg4::Actor::create("host_job_manager", myhost1, host_job_manager, 12 * 60 * 60, 4 * 60 * 60);
+  sg4::Actor::create("host_job_manager", myhost2, host_job_manager, 12 * 60 * 60, 4 * 60 * 60);
+  sg4::Actor::create("end_manager", myhost1, end_manager, battery);
+  // sg4::Actor::create("logger", myhost1, logger, battery, solar_panel, chiller, myhost1, myhost2)->daemonize();
+
+  e.run();
+  XBT_INFO("State of charge of the battery: %0.1f%%", battery->get_state_of_charge() * 100);
+  XBT_INFO(
+      "Energy consumed by the hosts (green / brown): %.2fMJ "
+      "/ %.2fMJ",
+      battery->get_energy_provided() / 1e6,
+      (sg_host_get_consumed_energy(myhost1) + sg_host_get_consumed_energy(myhost2) - battery->get_energy_provided()) /
+          1e6);
+  XBT_INFO("Energy consumed by the chiller (brown): %.2fMJ", chiller->get_energy_consumed() / 1e6);
+  return 0;
+}
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
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 7f0c361..64c9753 100644 (file)
@@ -94,8 +94,8 @@ private:
   double initial_capacity_wh_;
   double energy_budget_j_;
 
-  std::map<const s4u::Host*, bool> host_loads_     = {};
-  std::map<const std::string, double> named_loads_ = {};
+  std::map<const s4u::Host*, bool> host_loads_                      = {};
+  std::map<const std::string, std::pair<bool, double>> named_loads_ = {};
   std::vector<std::shared_ptr<Handler>> handlers_;
 
   double capacity_wh_;
@@ -128,6 +128,7 @@ public:
                          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 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..bf18ae1 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"
@@ -154,11 +151,13 @@ 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_);
@@ -210,11 +209,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 +225,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
@@ -263,7 +265,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);
@@ -309,7 +311,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 +338,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 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;
 }