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...
[simgrid.git] / src / plugins / chiller.cpp
1 /* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
2
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>
10 #include <xbt/log.h>
11
12 #include "src/kernel/resource/CpuImpl.hpp"
13 #include "src/simgrid/module.hpp"
14
15 SIMGRID_REGISTER_PLUGIN(chiller, "Chiller management", nullptr)
16
17 /** @defgroup plugin_chiller Plugin Chiller
18
19   @beginrst
20
21 This is the chiller plugin, enabling management of chillers.
22
23 Chiller
24 .......
25
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).
29
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:
32
33 .. math::
34
35   Q_{room} = (1 + \alpha) \times Q_{machines}
36
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}`:
39
40 .. math::
41
42   T_{out} = T_{in} + {Q_{room} \over m_{air} \times C_{p}}
43
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}` :
46
47 .. math::
48
49   Q_{cooling} = (T_{out} - T_{goal}) \times m_{air} \times C_{p} / \eta_{cooling}
50
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.
53
54   @endrst
55  */
56
57 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(Chiller, kernel, "Logging specific to the solar panel plugin");
58
59 namespace simgrid::plugins {
60
61 /* ChillerModel */
62
63 ChillerModel::ChillerModel() : Model("ChillerModel") {}
64
65 void ChillerModel::add_chiller(ChillerPtr c)
66 {
67   chillers_.push_back(c);
68 }
69
70 void ChillerModel::update_actions_state(double now, double delta)
71 {
72   for (auto chiller : chillers_)
73     chiller->update();
74 }
75
76 double ChillerModel::next_occurring_event(double now)
77 {
78   static bool init = false;
79   if (!init) {
80     init = true;
81     return 0;
82   }
83   double next_event = -1;
84   double tmp;
85   for (auto chiller : chillers_) {
86     tmp = chiller->get_next_event();
87     if (tmp != -1 and (next_event == -1 or tmp < next_event))
88       next_event = tmp;
89   }
90   return next_event;
91 }
92
93 /* Chiller */
94
95 std::shared_ptr<ChillerModel> Chiller::chiller_model_;
96
97 void Chiller::init_plugin()
98 {
99   auto model = std::make_shared<ChillerModel>();
100   simgrid::s4u::Engine::get_instance()->add_model(model);
101   Chiller::chiller_model_ = model;
102 }
103
104 void Chiller::update()
105 {
106   simgrid::kernel::actor::simcall_answered([this] {
107     double now          = s4u::Engine::get_clock();
108     double time_delta_s = now - last_updated_;
109
110     if (time_delta_s <= 0)
111       return;
112
113     double hosts_power_w = 0;
114     for (auto const& host : hosts_)
115       hosts_power_w += sg_host_get_current_consumption(host);
116     double heat_generated_j = hosts_power_w * (1 + alpha_) * time_delta_s;
117     temp_out_c_             = temp_in_c_ + heat_generated_j / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
118     double delta_temp_c     = temp_out_c_ - goal_temp_c_;
119
120     if (not active_ or delta_temp_c <= 0) {
121       temp_in_c_    = temp_out_c_;
122       power_w_      = 0;
123       last_updated_ = now;
124       return;
125     }
126
127     double cooling_demand_w = delta_temp_c * air_mass_kg_ * specific_heat_j_per_kg_per_c_ / time_delta_s;
128     double previous_power_w = power_w_;
129     power_w_                = std::min(max_power_w_, cooling_demand_w / cooling_efficiency_);
130     temp_in_c_ =
131         temp_out_c_ - (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
132
133     energy_consumed_j_ += power_w_ * time_delta_s;
134     if (previous_power_w != power_w_) {
135       on_this_power_change(this);
136       on_power_change(this);
137     }
138     last_updated_ = now;
139   });
140 }
141
142 Chiller::Chiller(const std::string& name, double air_mass_kg, double specific_heat_j_per_kg_per_c, double alpha,
143                  double cooling_efficiency, double initial_temp_c, double goal_temp_c, double max_power_w)
144     : name_(name)
145     , air_mass_kg_(air_mass_kg)
146     , specific_heat_j_per_kg_per_c_(specific_heat_j_per_kg_per_c)
147     , alpha_(alpha)
148     , cooling_efficiency_(cooling_efficiency)
149     , temp_in_c_(initial_temp_c)
150     , temp_out_c_(initial_temp_c)
151     , goal_temp_c_(goal_temp_c)
152     , max_power_w_(max_power_w)
153 {
154   xbt_assert(air_mass_kg > 0, ": air mass must be > 0 (provided: %f)", air_mass_kg);
155   xbt_assert(specific_heat_j_per_kg_per_c > 0, ": specific heat must be > 0 (provided: %f)",
156              specific_heat_j_per_kg_per_c);
157   xbt_assert(alpha >= 0, ": alpha must be >= 0 (provided: %f)", alpha);
158   xbt_assert(cooling_efficiency >= 0 and cooling_efficiency <= 1,
159              ": cooling efficiency must be in [0,1] (provided: %f)", cooling_efficiency);
160   xbt_assert(max_power_w >= 0, ": maximal power must be >=0 (provided: %f)", max_power_w);
161 }
162
163 /** @ingroup plugin_chiller
164  *  @param name The name of the Chiller.
165  *  @param air_mass_kg The air mass of the room managed by the Chiller in kg (> 0).
166  *  @param specific_heat_j_per_kg_per_c The specific heat of air in J per kg per °C (> 0).
167  *  @param alpha The ratio of the other devices in the total heat dissipation (e.g. lighting, Power Distribution Unit)
168  * (>= 0).
169  *  @param cooling_efficiency The cooling efficiency of the Chiller [0, 1].
170  *  @param initial_temp_c The initial temperature of the room managed by the Chiller.
171  *  @param goal_temp_c The goal temperature of the room. The Chiller is idle below this temperature.
172  *  @param max_power_w The maximal power delivered by the Chiller in W (> 0). If this power is reached the room
173  * temperature will raise above the goal temperature.
174  *  @return A ChillerPtr pointing to the new Chiller.
175  */
176 ChillerPtr Chiller::init(const std::string& name, double air_mass_kg, double specific_heat_j_per_kg_per_c, double alpha,
177                          double cooling_efficiency, double initial_temp_c, double goal_temp_c, double max_power_w)
178 {
179   static bool plugin_inited = false;
180   if (not plugin_inited) {
181     init_plugin();
182     plugin_inited = true;
183   }
184   auto chiller = ChillerPtr(new Chiller(name, air_mass_kg, specific_heat_j_per_kg_per_c, alpha, cooling_efficiency,
185                                         initial_temp_c, goal_temp_c, max_power_w));
186   chiller_model_->add_chiller(chiller);
187   return chiller;
188 }
189
190 /** @ingroup plugin_chiller
191  *  @param name The new name of the Chiller.
192  *  @return A ChillerPtr pointing to the modified Chiller.
193  */
194 ChillerPtr Chiller::set_name(std::string name)
195 {
196   simgrid::kernel::actor::simcall_answered([this, name] { name_ = name; });
197   return this;
198 }
199
200 /** @ingroup plugin_chiller
201  *  @param air_mass_kg The new air mass of the Chiller in kg.
202  *  @return A ChillerPtr pointing to the modified Chiller.
203  */
204 ChillerPtr Chiller::set_air_mass(double air_mass_kg)
205 {
206   xbt_assert(air_mass_kg > 0, ": air mass must be > 0 (provided: %f)", air_mass_kg);
207   simgrid::kernel::actor::simcall_answered([this, air_mass_kg] { air_mass_kg_ = air_mass_kg; });
208   return this;
209 }
210
211 /** @ingroup plugin_chiller
212  *  @param specific_heat_j_per_kg_per_c The specific heat of the Chiller in J per kg per °C.
213  *  @return A ChillerPtr pointing to the modified Chiller.
214  */
215 ChillerPtr Chiller::set_specific_heat(double specific_heat_j_per_kg_per_c)
216 {
217   xbt_assert(specific_heat_j_per_kg_per_c > 0, ": specific heat must be > 0 (provided: %f)",
218              specific_heat_j_per_kg_per_c);
219   simgrid::kernel::actor::simcall_answered(
220       [this, specific_heat_j_per_kg_per_c] { specific_heat_j_per_kg_per_c_ = specific_heat_j_per_kg_per_c; });
221   return this;
222 }
223
224 /** @ingroup plugin_chiller
225  *  @param alpha The new alpha of the Chiller.
226  *  @return A ChillerPtr pointing to the modified Chiller.
227  */
228 ChillerPtr Chiller::set_alpha(double alpha)
229 {
230   xbt_assert(alpha >= 0, ": alpha must be >= 0 (provided: %f)", alpha);
231   simgrid::kernel::actor::simcall_answered([this, alpha] { alpha_ = alpha; });
232   return this;
233 }
234
235 /** @ingroup plugin_chiller
236  *  @param cooling_efficiency The new coolingefficiency of the Chiller.
237  *  @return A ChillerPtr pointing to the modified Chiller.
238  */
239 ChillerPtr Chiller::set_cooling_efficiency(double cooling_efficiency)
240 {
241   xbt_assert(cooling_efficiency >= 0 and cooling_efficiency <= 1,
242              ": cooling efficiency must be in [0,1] (provided: %f)", cooling_efficiency);
243   simgrid::kernel::actor::simcall_answered([this, cooling_efficiency] { cooling_efficiency_ = cooling_efficiency; });
244   return this;
245 }
246
247 /** @ingroup plugin_chiller
248  *  @param goal_temp_c The new goal temperature of the Chiller in °C.
249  *  @return A ChillerPtr pointing to the modified Chiller.
250  */
251 ChillerPtr Chiller::set_goal_temp(double goal_temp_c)
252 {
253   simgrid::kernel::actor::simcall_answered([this, goal_temp_c] { goal_temp_c_ = goal_temp_c; });
254   return this;
255 }
256
257 /** @ingroup plugin_chiller
258  *  @param max_power_w The new maximal power of the Chiller in W.
259  *  @return A ChillerPtr pointing to the modified Chiller.
260  */
261 ChillerPtr Chiller::set_max_power(double max_power_w)
262 {
263   xbt_assert(max_power_w >= 0, ": maximal power must be >=0 (provided: %f)", max_power_w);
264   simgrid::kernel::actor::simcall_answered([this, max_power_w] { max_power_w_ = max_power_w; });
265   return this;
266 }
267
268 /** @ingroup plugin_chiller
269  *  @param active The new active status of the Chiller.
270  *  @return A ChillerPtr pointing to the modified Chiller.
271  */
272 ChillerPtr Chiller::set_active(bool active)
273 {
274   simgrid::kernel::actor::simcall_answered([this, active] { active_ = active; });
275   return this;
276 }
277
278 /** @ingroup plugin_chiller
279  *  @param host The host to add to the room managed by the Chiller.
280  *  @return A ChillerPtr pointing to the modified Chiller.
281  */
282 ChillerPtr Chiller::add_host(s4u::Host* host)
283 {
284   simgrid::kernel::actor::simcall_answered([this, host] { hosts_.insert(host); });
285   return this;
286 }
287
288 /** @ingroup plugin_chiller
289  *  @param host The host to remove from the room managed by the Chiller.
290  *  @return A ChillerPtr pointing to the modified Chiller.
291  */
292 ChillerPtr Chiller::remove_host(s4u::Host* host)
293 {
294   simgrid::kernel::actor::simcall_answered([this, host] { hosts_.erase(host); });
295   return this;
296 }
297
298 /** @ingroup plugin_chiller
299  *  @return Time of the next event, i.e.,
300  when the chiller will reach the goal temp if possible, -1 otherwise.
301  */
302 double Chiller::get_next_event()
303 {
304   if (not is_active() or goal_temp_c_ <= temp_out_c_)
305     return -1;
306   else {
307     double heat_power_w = 0;
308     for (auto const& host : hosts_)
309       heat_power_w += sg_host_get_current_consumption(host);
310     heat_power_w = heat_power_w * (1 + alpha_);
311     return air_mass_kg_ * (goal_temp_c_ - temp_out_c_) * specific_heat_j_per_kg_per_c_ / heat_power_w;
312   }
313 }
314 } // namespace simgrid::plugins