1 /* Copyright (c) 2023. The SimGrid Team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
5 #include <simgrid/Exception.hpp>
6 #include <simgrid/plugins/chiller.hpp>
7 #include <simgrid/plugins/energy.h>
8 #include <simgrid/simix.hpp>
9 #include <xbt/asserts.h>
12 #include "src/kernel/resource/CpuImpl.hpp"
13 #include "src/simgrid/module.hpp"
15 SIMGRID_REGISTER_PLUGIN(chiller, "Chiller management", nullptr)
17 /** @defgroup plugin_chiller Plugin Chiller
21 This is the chiller plugin, enabling management of chillers.
26 A chiller is placed inside a room with several machines. The role of the chiller is to keep the temperature of the room
27 below a threshold. This plugin and its equations are based on the paper "Co-simulation of FMUs and Distributed
28 Applications with SimGrid" by Camus et al. (https://hal.science/hal-01762540).
30 The heat generated inside the room :math:`Q_{room}` depends on the heat from the machines :math:`Q_{machines}` and
31 from the heat of the other devices, such as lighing, accounted using a factor :math:`\alpha` such as:
35 Q_{room} = (1 + \alpha) \times Q_{machines}
37 This energy heats the input temperature :math:`T_{in}` and gives an output temperature :math:`T_{out}` based on the the
38 mass of air inside the room :math:`m_{air}` and its specific heat :math:`C_{p}`:
42 T_{out} = T_{in} + {Q_{room} \over m_{air} \times C_{p}}
44 If the output temperature is above the goal temperature :math:`T_{goal}` the chiller compensates the excessive heat
45 using electrical energy :math:`Q_{cooling}` depending on its cooling efficiency :math:`\eta_{cooling}` :
49 Q_{cooling} = (T_{out} - T_{goal}) \times m_{air} \times C_{p} / \eta_{cooling}
51 The chiller has a power threshold that cannot be exceeded. If the power needed is above this threshold, or if the
52 chiller is not active, the temperature of the room increases.
57 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(Chiller, kernel, "Logging specific to the solar panel plugin");
59 namespace simgrid::plugins {
63 ChillerModel::ChillerModel() : Model("ChillerModel") {}
65 void ChillerModel::add_chiller(ChillerPtr c)
67 chillers_.push_back(c);
70 void ChillerModel::update_actions_state(double now, double delta)
72 for (auto chiller : chillers_)
76 double ChillerModel::next_occurring_event(double now)
83 std::shared_ptr<ChillerModel> Chiller::chiller_model_;
85 void Chiller::init_plugin()
87 auto model = std::make_shared<ChillerModel>();
88 simgrid::s4u::Engine::get_instance()->add_model(model);
89 Chiller::chiller_model_ = model;
92 void Chiller::update()
94 simgrid::kernel::actor::simcall_answered([this] {
95 double now = s4u::Engine::get_clock();
96 double time_delta_s = now - last_updated_;
98 if (time_delta_s <= 0)
101 double hosts_power_w = 0;
102 for (auto const& host : hosts_)
103 hosts_power_w += sg_host_get_current_consumption(host);
104 double heat_generated_j = hosts_power_w * (1 + alpha_) * time_delta_s;
105 temp_out_c_ = temp_in_c_ + heat_generated_j / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
106 double delta_temp_c = temp_out_c_ - goal_temp_c_;
108 if (not active_ or delta_temp_c < 0) {
109 temp_in_c_ = temp_out_c_;
115 double cooling_demand_w = delta_temp_c * air_mass_kg_ * specific_heat_j_per_kg_per_c_ / time_delta_s;
116 if (cooling_demand_w / cooling_efficiency_ <= max_power_w_) {
117 power_w_ = cooling_demand_w / cooling_efficiency_;
118 temp_in_c_ = temp_out_c_ -
119 (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
121 power_w_ = max_power_w_;
122 temp_in_c_ = temp_out_c_ -
123 (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
126 energy_consumed_j_ += power_w_ * time_delta_s;
131 Chiller::Chiller(const std::string& name, double air_mass_kg, double specific_heat_j_per_kg_per_c, double alpha,
132 double cooling_efficiency, double initial_temp_c, double goal_temp_c, double max_power_w)
134 , air_mass_kg_(air_mass_kg)
135 , specific_heat_j_per_kg_per_c_(specific_heat_j_per_kg_per_c)
137 , cooling_efficiency_(cooling_efficiency)
138 , temp_in_c_(initial_temp_c)
139 , temp_out_c_(initial_temp_c)
140 , goal_temp_c_(goal_temp_c)
141 , max_power_w_(max_power_w)
143 xbt_assert(air_mass_kg > 0, ": air mass must be > 0 (provided: %f)", air_mass_kg);
144 xbt_assert(specific_heat_j_per_kg_per_c > 0, ": specific heat must be > 0 (provided: %f)",
145 specific_heat_j_per_kg_per_c);
146 xbt_assert(alpha >= 0, ": alpha must be >= 0 (provided: %f)", alpha);
147 xbt_assert(cooling_efficiency >= 0 and cooling_efficiency <= 1,
148 ": cooling efficiency must be in [0,1] (provided: %f)", cooling_efficiency);
149 xbt_assert(max_power_w >= 0, ": maximal power must be >=0 (provided: %f)", max_power_w);
152 /** @ingroup plugin_chiller
153 * @param name The name of the Chiller.
154 * @param air_mass_kg The air mass of the room managed by the Chiller in kg (> 0).
155 * @param specific_heat_j_per_kg_per_c The specific heat of air in J per kg per °C (> 0).
156 * @param alpha The ratio of the other devices in the total heat dissipation (e.g. lighting, Power Distribution Unit)
158 * @param cooling_efficiency The cooling efficiency of the Chiller [0, 1].
159 * @param initial_temp_c The initial temperature of the room managed by the Chiller.
160 * @param goal_temp_c The goal temperature of the room. The Chiller is idle below this temperature.
161 * @param max_power_w The maximal power delivered by the Chiller in W (> 0). If this power is reached the room
162 * temperature will raise above the goal temperature.
163 * @return A ChillerPtr pointing to the new Chiller.
165 ChillerPtr Chiller::init(const std::string& name, double air_mass_kg, double specific_heat_j_per_kg_per_c, double alpha,
166 double cooling_efficiency, double initial_temp_c, double goal_temp_c, double max_power_w)
168 static bool plugin_inited = false;
169 if (not plugin_inited) {
171 plugin_inited = true;
173 auto chiller = ChillerPtr(new Chiller(name, air_mass_kg, specific_heat_j_per_kg_per_c, alpha, cooling_efficiency,
174 initial_temp_c, goal_temp_c, max_power_w));
175 chiller_model_->add_chiller(chiller);
179 /** @ingroup plugin_chiller
180 * @param name The new name of the Chiller.
181 * @return A ChillerPtr pointing to the modified Chiller.
183 ChillerPtr Chiller::set_name(std::string name)
185 simgrid::kernel::actor::simcall_answered([this, name] { name_ = name; });
189 /** @ingroup plugin_chiller
190 * @param air_mass_kg The new air mass of the Chiller in kg.
191 * @return A ChillerPtr pointing to the modified Chiller.
193 ChillerPtr Chiller::set_air_mass(double air_mass_kg)
195 xbt_assert(air_mass_kg > 0, ": air mass must be > 0 (provided: %f)", air_mass_kg);
196 simgrid::kernel::actor::simcall_answered([this, air_mass_kg] { air_mass_kg_ = air_mass_kg; });
200 /** @ingroup plugin_chiller
201 * @param specific_heat_j_per_kg_per_c The specific heat of the Chiller in J per kg per °C.
202 * @return A ChillerPtr pointing to the modified Chiller.
204 ChillerPtr Chiller::set_specific_heat(double specific_heat_j_per_kg_per_c)
206 xbt_assert(specific_heat_j_per_kg_per_c > 0, ": specific heat must be > 0 (provided: %f)",
207 specific_heat_j_per_kg_per_c);
208 simgrid::kernel::actor::simcall_answered(
209 [this, specific_heat_j_per_kg_per_c] { specific_heat_j_per_kg_per_c_ = specific_heat_j_per_kg_per_c; });
213 /** @ingroup plugin_chiller
214 * @param alpha The new alpha of the Chiller.
215 * @return A ChillerPtr pointing to the modified Chiller.
217 ChillerPtr Chiller::set_alpha(double alpha)
219 xbt_assert(alpha >= 0, ": alpha must be >= 0 (provided: %f)", alpha);
220 simgrid::kernel::actor::simcall_answered([this, alpha] { alpha_ = alpha; });
224 /** @ingroup plugin_chiller
225 * @param cooling_efficiency The new coolingefficiency of the Chiller.
226 * @return A ChillerPtr pointing to the modified Chiller.
228 ChillerPtr Chiller::set_cooling_efficiency(double cooling_efficiency)
230 xbt_assert(cooling_efficiency >= 0 and cooling_efficiency <= 1,
231 ": cooling efficiency must be in [0,1] (provided: %f)", cooling_efficiency);
232 simgrid::kernel::actor::simcall_answered([this, cooling_efficiency] { cooling_efficiency_ = cooling_efficiency; });
236 /** @ingroup plugin_chiller
237 * @param goal_temp_c The new goal temperature of the Chiller in °C.
238 * @return A ChillerPtr pointing to the modified Chiller.
240 ChillerPtr Chiller::set_goal_temp(double goal_temp_c)
242 simgrid::kernel::actor::simcall_answered([this, goal_temp_c] { goal_temp_c_ = goal_temp_c; });
246 /** @ingroup plugin_chiller
247 * @param max_power_w The new maximal power of the Chiller in W.
248 * @return A ChillerPtr pointing to the modified Chiller.
250 ChillerPtr Chiller::set_max_power(double max_power_w)
252 xbt_assert(max_power_w >= 0, ": maximal power must be >=0 (provided: %f)", max_power_w);
253 simgrid::kernel::actor::simcall_answered([this, max_power_w] { max_power_w_ = max_power_w; });
257 /** @ingroup plugin_chiller
258 * @param active The new active status of the Chiller.
259 * @return A ChillerPtr pointing to the modified Chiller.
261 ChillerPtr Chiller::set_active(bool active)
263 simgrid::kernel::actor::simcall_answered([this, active] { active_ = active; });
267 /** @ingroup plugin_chiller
268 * @param host The host to add to the room managed by the Chiller.
269 * @return A ChillerPtr pointing to the modified Chiller.
271 ChillerPtr Chiller::add_host(s4u::Host* host)
273 simgrid::kernel::actor::simcall_answered([this, host] { hosts_.insert(host); });
277 /** @ingroup plugin_chiller
278 * @param host The host to remove from the room managed by the Chiller.
279 * @return A ChillerPtr pointing to the modified Chiller.
281 ChillerPtr Chiller::remove_host(s4u::Host* host)
283 simgrid::kernel::actor::simcall_answered([this, host] { hosts_.erase(host); });
287 } // namespace simgrid::plugins