include examples/cpp/app-token-ring/s4u-app-token-ring.tesh
include examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp
include examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh
+include examples/cpp/battery-connector/s4u-battery-connector.cpp
+include examples/cpp/battery-connector/s4u-battery-connector.tesh
include examples/cpp/battery-degradation/plot_battery_degradation.py
include examples/cpp/battery-degradation/s4u-battery-degradation.cpp
include examples/cpp/battery-degradation/s4u-battery-degradation.tesh
actor-create actor-daemon actor-exiting actor-join actor-kill
actor-lifetime actor-migrate actor-suspend actor-yield actor-stacksize
app-bittorrent app-chainsend app-token-ring
- battery-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
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);
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);
--- /dev/null
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example shows how to use the battery as a connector.
+ A solar panel is connected to the connector and power a host.
+*/
+
+#include "simgrid/plugins/battery.hpp"
+#include "simgrid/plugins/chiller.hpp"
+#include "simgrid/plugins/energy.h"
+#include "simgrid/plugins/solar_panel.hpp"
+#include "simgrid/s4u.hpp"
+#include <math.h>
+#include <simgrid/s4u/Actor.hpp>
+#include <xbt/log.h>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(battery_chiller_solar, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+namespace sp = simgrid::plugins;
+
+int main(int argc, char* argv[])
+{
+ sg4::Engine e(&argc, argv);
+ e.load_platform(argv[1]);
+ sg_host_energy_plugin_init();
+
+ auto myhost1 = e.host_by_name("MyHost1");
+
+ auto connector = sp::Battery::init();
+ auto solar_panel = sp::SolarPanel::init("Solar Panel", 1, 1, 200, 0, 1e3);
+
+ connector->set_load("Solar Panel", solar_panel->get_power() * -1);
+ connector->connect_host(myhost1);
+
+ solar_panel->on_this_power_change_cb([connector](sp::SolarPanel *s) {
+ connector->set_load("Solar Panel", s->get_power() * -1);
+ });
+
+ sg4::Actor::create("manager", myhost1, [&myhost1, & solar_panel, &connector]{
+ XBT_INFO("Solar Panel power = %.2fW, MyHost1 power = %.2fW. The Solar Panel provides more than needed.", solar_panel->get_power(), sg_host_get_current_consumption(myhost1));
+ simgrid::s4u::this_actor::sleep_for(100);
+ XBT_INFO("Energy consumption MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", sg_host_get_consumed_energy(myhost1) / 1e3, connector->get_energy_provided() / 1e3);
+
+ solar_panel->set_solar_irradiance(100);
+ XBT_INFO("Solar Panel power = %.2fW, MyHost1 power = %.2fW. The Solar Panel provides exactly what is needed.", solar_panel->get_power(), sg_host_get_current_consumption(myhost1));
+ double last_measure_host_energy = sg_host_get_consumed_energy(myhost1);
+ double last_measure_connector_energy = connector->get_energy_provided();
+
+ simgrid::s4u::this_actor::sleep_for(100);
+ XBT_INFO("Energy consumption MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", (sg_host_get_consumed_energy(myhost1) - last_measure_host_energy) / 1e3, (connector->get_energy_provided() - last_measure_connector_energy) / 1e3);
+
+ XBT_INFO("MyHost1 executes something for 100s. The Solar Panel does not provide enough energy.");
+ last_measure_host_energy = sg_host_get_consumed_energy(myhost1);
+ last_measure_connector_energy = connector->get_energy_provided();
+ myhost1->execute(100 * myhost1->get_speed());
+ XBT_INFO("Energy MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", (sg_host_get_consumed_energy(myhost1) - last_measure_host_energy) / 1e3, (connector->get_energy_provided() - last_measure_connector_energy) / 1e3);
+ });
+
+ e.run();
+ return 0;
+}
--- /dev/null
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-battery-connector ${platfdir}/energy_platform.xml
+> [MyHost1:manager:(1) 0.000000] [battery_chiller_solar/INFO] Solar Panel power = 200.00W, MyHost1 power = 100.00W. The Solar Panel provides more than needed.
+> [MyHost1:manager:(1) 100.000000] [battery_chiller_solar/INFO] Energy consumption MyHost1: 10.00kJ, Energy from the Solar Panel 10.00kJ
+> [MyHost1:manager:(1) 100.000000] [battery_chiller_solar/INFO] Solar Panel power = 100.00W, MyHost1 power = 100.00W. The Solar Panel provides exactly what is needed.
+> [MyHost1:manager:(1) 200.000000] [battery_chiller_solar/INFO] Energy consumption MyHost1: 10.00kJ, Energy from the Solar Panel 10.00kJ
+> [MyHost1:manager:(1) 200.000000] [battery_chiller_solar/INFO] MyHost1 executes something for 100s. The Solar Panel does not provide enough energy.
+> [MyHost1:manager:(1) 300.000000] [battery_chiller_solar/INFO] Energy MyHost1: 12.00kJ, Energy from the Solar Panel 10.00kJ
+> [300.000000] [host_energy/INFO] Total energy consumption: 92000.000000 Joules (used hosts: 32000.000000 Joules; unused/idle hosts: 60000.000000)
+> [300.000000] [host_energy/INFO] Energy consumption of host MyHost1: 32000.000000 Joules
+> [300.000000] [host_energy/INFO] Energy consumption of host MyHost2: 30000.000000 Joules
+> [300.000000] [host_energy/INFO] Energy consumption of host MyHost3: 30000.000000 Joules
\ No newline at end of file
XBT_INFO("Initial state: ");
XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
c->get_energy_consumed());
-
XBT_INFO("The machines slowly heat up the room.");
- simgrid::s4u::this_actor::sleep_until(400);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
- simgrid::s4u::this_actor::sleep_until(800);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
simgrid::s4u::this_actor::sleep_until(1000);
XBT_INFO("The Chiller now compensates the heat generated by the machines.");
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
simgrid::s4u::this_actor::sleep_until(1200);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
-
XBT_INFO("Let's compute something.");
sg4::this_actor::exec_async(1e10);
- simgrid::s4u::this_actor::sleep_until(1250);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
-
simgrid::s4u::this_actor::sleep_until(1300);
XBT_INFO("Computation done.");
-
simgrid::s4u::this_actor::sleep_until(1400);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
-
XBT_INFO("Now let's stress the chiller by decreasing the goal temperature to 23°C.");
c->set_goal_temp(23);
- simgrid::s4u::this_actor::sleep_until(1600);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
- simgrid::s4u::this_actor::sleep_until(1800);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
+
+ simgrid::s4u::this_actor::sleep_until(1900);
simgrid::s4u::this_actor::sleep_until(2000);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
- simgrid::s4u::this_actor::sleep_until(2200);
- XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
- c->get_energy_consumed());
+ simgrid::s4u::this_actor::sleep_until(2100);
}
int main(int argc, char* argv[])
chiller->add_host(e.host_by_name("MyHost2"));
chiller->add_host(e.host_by_name("MyHost3"));
sg4::Actor::create("sender", e.host_by_name("MyHost1"), manager, chiller);
+ chiller->on_power_change_cb([](simgrid::plugins::Chiller* c) {
+ XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
+ c->get_energy_consumed());
+ });
e.run();
return 0;
> [MyHost1:sender:(1) 0.000000] [chiller_simple/INFO] Initial state:
> [MyHost1:sender:(1) 0.000000] [chiller_simple/INFO] Chiller: Power: 0.000000W T_in: 23.000000°C Energy consumed: 0.000000J
> [MyHost1:sender:(1) 0.000000] [chiller_simple/INFO] The machines slowly heat up the room.
-> [MyHost1:sender:(1) 400.000000] [chiller_simple/INFO] Chiller: Power: 0.000000W T_in: 23.486875°C Energy consumed: 0.000000J
-> [MyHost1:sender:(1) 800.000000] [chiller_simple/INFO] Chiller: Power: 0.000000W T_in: 23.973749°C Energy consumed: 0.000000J
+> [1000.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 71373.333333J
> [MyHost1:sender:(1) 1000.000000] [chiller_simple/INFO] The Chiller now compensates the heat generated by the machines.
-> [MyHost1:sender:(1) 1000.000000] [chiller_simple/INFO] Chiller: Power: 356.866667W T_in: 24.000000°C Energy consumed: 71373.333333J
-> [MyHost1:sender:(1) 1200.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 151373.333333J
+> [1200.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 151373.333333J
> [MyHost1:sender:(1) 1200.000000] [chiller_simple/INFO] Let's compute something.
-> [MyHost1:sender:(1) 1250.000000] [chiller_simple/INFO] Chiller: Power: 426.666667W T_in: 24.000000°C Energy consumed: 172706.666667J
+> [1300.000000] [chiller_simple/INFO] Chiller: Power: 426.666667W T_in: 24.000000°C Energy consumed: 194040.000000J
> [MyHost1:sender:(1) 1300.000000] [chiller_simple/INFO] Computation done.
-> [MyHost1:sender:(1) 1400.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 234040.000000J
+> [1400.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 234040.000000J
> [MyHost1:sender:(1) 1400.000000] [chiller_simple/INFO] Now let's stress the chiller by decreasing the goal temperature to 23°C.
-> [MyHost1:sender:(1) 1600.000000] [chiller_simple/INFO] Chiller: Power: 1000.000000W T_in: 23.634844°C Energy consumed: 434040.000000J
-> [MyHost1:sender:(1) 1800.000000] [chiller_simple/INFO] Chiller: Power: 1000.000000W T_in: 23.269688°C Energy consumed: 634040.000000J
-> [MyHost1:sender:(1) 2000.000000] [chiller_simple/INFO] Chiller: Power: 843.133333W T_in: 23.000000°C Energy consumed: 802666.666667J
-> [MyHost1:sender:(1) 2200.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 23.000000°C Energy consumed: 882666.666667J
-> [2200.000000] [host_energy/INFO] Total energy consumption: 662000.000000 Joules (used hosts: 222000.000000 Joules; unused/idle hosts: 440000.000000)
-> [2200.000000] [host_energy/INFO] Energy consumption of host MyHost1: 222000.000000 Joules
-> [2200.000000] [host_energy/INFO] Energy consumption of host MyHost2: 220000.000000 Joules
-> [2200.000000] [host_energy/INFO] Energy consumption of host MyHost3: 220000.000000 Joules
+> [1900.000000] [chiller_simple/INFO] Chiller: Power: 1000.000000W T_in: 23.087110°C Energy consumed: 734040.000000J
+> [2000.000000] [chiller_simple/INFO] Chiller: Power: 686.266667W T_in: 23.000000°C Energy consumed: 802666.666667J
+> [2100.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 23.000000°C Energy consumed: 842666.666667J
+> [2100.000000] [host_energy/INFO] Total energy consumption: 632000.000000 Joules (used hosts: 212000.000000 Joules; unused/idle hosts: 420000.000000)
+> [2100.000000] [host_energy/INFO] Energy consumption of host MyHost1: 212000.000000 Joules
+> [2100.000000] [host_energy/INFO] Energy consumption of host MyHost2: 210000.000000 Joules
+> [2100.000000] [host_energy/INFO] Energy consumption of host MyHost3: 210000.000000 Joules
\ No newline at end of file
#ifndef SIMGRID_PLUGINS_BATTERY_HPP_
#define SIMGRID_PLUGINS_BATTERY_HPP_
+#include <cmath>
#include <memory>
#include <simgrid/kernel/resource/Model.hpp>
#include <simgrid/s4u/Activity.hpp>
static std::shared_ptr<BatteryModel> battery_model_;
std::string name_;
- double nominal_charge_power_w_;
- double nominal_discharge_power_w_;
- double charge_efficiency_;
- double discharge_efficiency_;
- double initial_capacity_wh_;
- double energy_budget_j_;
+ double nominal_charge_power_w_ = -INFINITY;
+ double nominal_discharge_power_w_ = INFINITY;
+ double charge_efficiency_ = 1;
+ double discharge_efficiency_ = 1;
+ double initial_capacity_wh_ = 0;
+ double energy_budget_j_ = 0;
std::map<const s4u::Host*, bool> host_loads_ = {};
std::map<const std::string, std::pair<bool, double>> named_loads_ = {};
std::vector<std::shared_ptr<Handler>> handlers_;
- double capacity_wh_;
- double energy_stored_j_;
+ double capacity_wh_ = 0;
+ double energy_stored_j_ = 0;
double energy_provided_j_ = 0;
double energy_consumed_j_ = 0;
double last_updated_ = 0;
+ explicit Battery();
explicit Battery(const std::string& name, double state_of_charge, double nominal_charge_power_w,
double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency,
double initial_capacity_wh, int cycles);
#endif
public:
+ static BatteryPtr init();
static BatteryPtr init(const std::string& name, double state_of_charge, double nominal_charge_power_w,
double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency,
double initial_capacity_wh, int cycles);
friend void intrusive_ptr_add_ref(Chiller* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); }
#endif
+ inline static xbt::signal<void(Chiller*)> on_power_change;
+ xbt::signal<void(Chiller*)> on_this_power_change;
+
public:
static ChillerPtr init(const std::string& name, double air_mass_kg, double specific_heat_j_per_kg_per_c, double alpha,
double cooling_efficiency, double initial_temp_c, double goal_temp_c, double max_power_w);
double get_temp_out() { return temp_out_c_; }
double get_power() { return power_w_; }
double get_energy_consumed() { return energy_consumed_j_; }
+ double get_next_event();
+
+ /** Add a callback fired after this chiller power changed. */
+ void on_this_power_change_cb(const std::function<void(Chiller*)>& func) { on_this_power_change.connect(func); };
+ /** Add a callback fired after a chiller power changed.
+ * Triggered after the on_this_power_change function.**/
+ static void on_power_change_cb(const std::function<void(Chiller*)>& cb) { on_power_change.connect(cb); }
};
} // namespace simgrid::plugins
Theses handlers may be recurrent, for instance you may want to always set all loads to zero and deactivate all hosts
connections when the battery reaches 20% SoC.
+Connector
+.........
+
+A Battery can act as a connector to connect Solar Panels direcly to loads. Such Battery is created without any
+parameter, cannot store energy and has a transfer efficiency of 100%.
+
@endrst
*/
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(Battery, kernel, "Logging specific to the battery plugin");
double BatteryModel::next_occurring_event(double now)
{
+ static bool init = false;
+ if (!init) {
+ init = true;
+ return 0;
+ }
double time_delta = -1;
for (auto battery : batteries_) {
double time_delta_battery = battery->next_occurring_handler();
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_);
// 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_);
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)
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).
double ChillerModel::next_occurring_event(double now)
{
- return -1;
+ static bool init = false;
+ if (!init) {
+ init = true;
+ return 0;
+ }
+ double next_event = -1;
+ double tmp;
+ for (auto chiller : chillers_) {
+ tmp = chiller->get_next_event();
+ if (tmp != -1 and (next_event == -1 or tmp < next_event))
+ next_event = tmp;
+ }
+ return next_event;
}
/* Chiller */
temp_out_c_ = temp_in_c_ + heat_generated_j / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
double delta_temp_c = temp_out_c_ - goal_temp_c_;
- if (not active_ or delta_temp_c < 0) {
+ if (not active_ or delta_temp_c <= 0) {
temp_in_c_ = temp_out_c_;
power_w_ = 0;
last_updated_ = now;
}
double cooling_demand_w = delta_temp_c * air_mass_kg_ * specific_heat_j_per_kg_per_c_ / time_delta_s;
- if (cooling_demand_w / cooling_efficiency_ <= max_power_w_) {
- power_w_ = cooling_demand_w / cooling_efficiency_;
- temp_in_c_ = temp_out_c_ -
- (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
- } else {
- power_w_ = max_power_w_;
- temp_in_c_ = temp_out_c_ -
- (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
- }
+ double previous_power_w = power_w_;
+ power_w_ = std::min(max_power_w_, cooling_demand_w / cooling_efficiency_);
+ temp_in_c_ =
+ temp_out_c_ - (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
energy_consumed_j_ += power_w_ * time_delta_s;
+ if (previous_power_w != power_w_) {
+ on_this_power_change(this);
+ on_power_change(this);
+ }
last_updated_ = now;
});
}
return this;
}
+/** @ingroup plugin_chiller
+ * @return Time of the next event, i.e.,
+ when the chiller will reach the goal temp if possible, -1 otherwise.
+ */
+double Chiller::get_next_event()
+{
+ if (not is_active() or goal_temp_c_ <= temp_out_c_)
+ return -1;
+ else {
+ double heat_power_w = 0;
+ for (auto const& host : hosts_)
+ heat_power_w += sg_host_get_current_consumption(host);
+ heat_power_w = heat_power_w * (1 + alpha_);
+ return air_mass_kg_ * (goal_temp_c_ - temp_out_c_) * specific_heat_j_per_kg_per_c_ / heat_power_w;
+ }
+}
} // namespace simgrid::plugins