Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of framagit.org:simgrid/simgrid
[simgrid.git] / src / plugins / photovoltaic.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/photovoltaic.hpp>
7 #include <simgrid/s4u/Actor.hpp>
8 #include <simgrid/s4u/Engine.hpp>
9 #include <simgrid/s4u/Host.hpp>
10 #include <simgrid/s4u/VirtualMachine.hpp>
11 #include <simgrid/simix.hpp>
12
13 #include "src/kernel/resource/CpuImpl.hpp"
14 #include "src/simgrid/module.hpp"
15
16 #include <boost/algorithm/string/classification.hpp>
17 #include <boost/algorithm/string/split.hpp>
18
19 SIMGRID_REGISTER_PLUGIN(photovoltaic, "Photovoltaic management", &sg_photovoltaic_plugin_init)
20
21 /** @defgroup plugin_photovoltaic plugin_photovoltaic Plugin photovoltaic
22
23   @beginrst
24
25 This is the photovoltaic plugin, enabling management of photovoltaic panels on hosts.
26 To activate this plugin, first call :cpp:func:`sg_photovoltaic_plugin_init()`.
27
28 This plugin allows evaluation of photovoltaic panels power generation during simulation depending on size, solar
29 irradiance and conversion factor.
30
31 The power model is taken from the paper `"Reinforcement Learning Based Load Balancing for
32 Geographically Distributed Data Centres" <https://dro.dur.ac.uk/33395/1/33395.pdf?DDD280+kkgc95+vbdv77>`_ by Max Mackie et. al.
33
34 The cost model is taken from the chapter 4 of the thesis `Sizing and Operation of Multi-Energy Hydrogen-Based
35 Microgrids <https://tel.archives-ouvertes.fr/tel-02077668/document>`_ by Bei Li.
36
37 Photovoltaic Panel properties
38 ....................
39
40 Properties of panels are defined as properties of hosts in the platform XML file.
41
42 Here is an example of XML declaration where we consider a host as a photovoltaic panel:
43
44 .. code-block:: xml
45
46    <host id="pv_panel" speed="0f">
47       <prop id="photovoltaic_area" value="4" />
48       <prop id="photovoltaic_conversion_efficiency" value="0.2" />
49     </host>
50
51 The different properties are:
52
53 - ``photovoltaic_area``: Set the area of the panel in m² (default=0)
54 - ``photovoltaic_conversion_efficiency``: Set the conversion efficiency of the panel (default=0)
55 - ``photovoltaic_solar_irradiance``: Set the initial solar irradiance in W/m² (default=0)
56 - ``photovoltaic_min_power``: Set the minimum power of the panel in W (default=-1). Power generation below this value is automatically 0. Value is ignored if negative
57 - ``photovoltaic_max_power``: Set the maximal power of the panel in W (default=-1). Power generation above this value is automatically truncated. Value is ignored if negative
58 - ``photovoltaic_eval_cost``: Evaluate the cost of the panel during the simulation if set to 1 (defaulf=0)
59 - ``photovoltaic_lifespan``: Set the lifespan of the panel in years (default=0)
60 - ``photovoltaic_investment_cost``: Set the investment cost of the panel (default=0)
61 - ``photovoltaic_maintenance_cost``: Set the maintenance cost of the panel (default=0)
62
63   @endrst
64  */
65
66 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(photovoltaic, kernel, "Logging specific to the photovoltaic plugin");
67
68 namespace simgrid::plugin {
69 class Photovoltaic {
70 private:
71   simgrid::s4u::Host* host_ = nullptr;
72
73   double area_m2_                   = 0;
74   double conversion_efficiency_     = 0;
75   double solar_irradiance_w_per_m2_ = 0;
76   double min_power_w_               = -1;
77   double max_power_w_               = -1;
78
79   double power_w_      = 0;
80   double last_updated_ = 0;
81
82   bool eval_cost_                 = false;
83   double cumulative_cost_         = 0;
84   int lifespan_years_             = 0;
85   double investment_cost_per_w_   = 0;
86   double maintenance_cost_per_wh_ = 0;
87
88   void init_photovoltaic_params();
89   void init_cost_params();
90   void update();
91
92   Photovoltaic* set_area(double a);
93   Photovoltaic* set_conversion_efficiency(double e);
94   Photovoltaic* set_min_power(double p);
95   Photovoltaic* set_max_power(double p);
96   Photovoltaic* set_eval_cost(bool eval);
97   Photovoltaic* set_lifespan(int l);
98   Photovoltaic* set_investment_cost(double c);
99   Photovoltaic* set_maintenance_cost(double c);
100
101 public:
102   static simgrid::xbt::Extension<simgrid::s4u::Host, Photovoltaic> EXTENSION_ID;
103
104   explicit Photovoltaic(simgrid::s4u::Host* host);
105   ~Photovoltaic();
106
107   Photovoltaic* set_solar_irradiance(double s);
108
109   double get_power();
110 };
111
112 Photovoltaic* Photovoltaic::set_area(double a)
113 {
114   xbt_assert(a > 0, " : area should be > 0 (provided: %f)", a);
115   simgrid::kernel::actor::simcall_answered([this, a] { area_m2_ = a; });
116   return this;
117 }
118
119 Photovoltaic* Photovoltaic::set_conversion_efficiency(double e)
120 {
121   xbt_assert(e > 0 and e <= 1, " : conversion efficiency should be in [0,1] (provided: %f)", e);
122   simgrid::kernel::actor::simcall_answered([this, e] { conversion_efficiency_ = e; });
123   return this;
124 }
125
126 Photovoltaic* Photovoltaic::set_solar_irradiance(double s)
127 {
128   xbt_assert(s > 0, " : solar irradiance should be > 0 (provided: %f)", s);
129   simgrid::kernel::actor::simcall_answered([this, s] { solar_irradiance_w_per_m2_ = s; });
130   return this;
131 }
132
133 Photovoltaic* Photovoltaic::set_min_power(double p)
134 {
135   simgrid::kernel::actor::simcall_answered([this, p] { min_power_w_ = p; });
136   return this;
137 }
138
139 Photovoltaic* Photovoltaic::set_max_power(double p)
140 {
141   simgrid::kernel::actor::simcall_answered([this, p] { max_power_w_ = p; });
142   return this;
143 }
144
145 Photovoltaic* Photovoltaic::set_eval_cost(bool e)
146 {
147   simgrid::kernel::actor::simcall_answered([this, e] { eval_cost_ = e; });
148   return this;
149 }
150
151 Photovoltaic* Photovoltaic::set_lifespan(int l)
152 {
153   xbt_assert(l > 0, " : lifespan should be > 0 (provided: %d)", l);
154   simgrid::kernel::actor::simcall_answered([this, l] { lifespan_years_ = l; });
155   return this;
156 }
157
158 Photovoltaic* Photovoltaic::set_investment_cost(double c)
159 {
160   xbt_assert(c > 0, " : investment cost should be > 0 (provided: %f)", c);
161   simgrid::kernel::actor::simcall_answered([this, c] { investment_cost_per_w_ = c; });
162   return this;
163 }
164
165 Photovoltaic* Photovoltaic::set_maintenance_cost(double c)
166 {
167   xbt_assert(c > 0, " : maintenance cost hould be > 0 (provided: %f)", c);
168   simgrid::kernel::actor::simcall_answered([this, c] { maintenance_cost_per_wh_ = c; });
169   return this;
170 }
171
172 double Photovoltaic::get_power()
173 {
174   update();
175   return power_w_;
176 }
177
178 simgrid::xbt::Extension<simgrid::s4u::Host, Photovoltaic> Photovoltaic::EXTENSION_ID;
179
180 void Photovoltaic::init_photovoltaic_params()
181 {
182   const char* prop_chars;
183   prop_chars = host_->get_property("photovoltaic_area");
184   if (prop_chars)
185     set_area(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
186   prop_chars = host_->get_property("photovoltaic_conversion_efficiency");
187   if (prop_chars)
188     set_conversion_efficiency(
189         xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
190   prop_chars = host_->get_property("photovoltaic_solar_irradiance");
191   if (prop_chars)
192     set_solar_irradiance(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
193   prop_chars = host_->get_property("photovoltaic_min_power");
194   if (prop_chars)
195     set_min_power(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
196   prop_chars = host_->get_property("photovoltaic_max_power");
197   if (prop_chars)
198     set_max_power(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
199   prop_chars = host_->get_property("photovoltaic_eval_cost");
200   if (prop_chars)
201     set_eval_cost(xbt_str_parse_int(prop_chars, ("cannot parse int: " + std::string(prop_chars)).c_str()));
202   prop_chars = host_->get_property("photovoltaic_lifespan");
203   if (prop_chars)
204     set_lifespan(xbt_str_parse_int(prop_chars, ("cannot parse int: " + std::string(prop_chars)).c_str()));
205   prop_chars = host_->get_property("photovoltaic_investment_cost");
206   if (prop_chars)
207     set_investment_cost(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
208   prop_chars = host_->get_property("photovoltaic_maintenance_cost");
209   if (prop_chars)
210     set_maintenance_cost(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
211   simgrid::kernel::actor::simcall_answered([this] { last_updated_ = simgrid::s4u::Engine::get_clock(); });
212 }
213
214 void Photovoltaic::update()
215 {
216   simgrid::kernel::actor::simcall_answered([this] {
217     double now = simgrid::s4u::Engine::get_clock();
218     if (now <= last_updated_)
219       return;
220     double power_w = conversion_efficiency_ * area_m2_ * solar_irradiance_w_per_m2_;
221     if (min_power_w_ > 0 && power_w_ < min_power_w_)
222       power_w = 0;
223     if (max_power_w_ > 0 && power_w_ > max_power_w_)
224       power_w = max_power_w_;
225     power_w_ = power_w;
226     if (eval_cost_) {
227       xbt_assert(max_power_w_ > 0, " : max power must be > 0 (provided: %f)", max_power_w_);
228       cumulative_cost_ += max_power_w_ * (now - last_updated_) *
229                           (investment_cost_per_w_ / (lifespan_years_ * 8760 * 3600) + maintenance_cost_per_wh_ / 3600);
230     }
231     last_updated_ = now;
232   });
233 }
234
235 Photovoltaic::Photovoltaic(simgrid::s4u::Host* host) : host_(host)
236 {
237   init_photovoltaic_params();
238 }
239
240 Photovoltaic::~Photovoltaic() = default;
241 } // namespace simgrid::plugin
242
243 using simgrid::plugin::Photovoltaic;
244
245 /* **************************** events  callback *************************** */
246
247 static void on_creation(simgrid::s4u::Host& host)
248 {
249   if (dynamic_cast<simgrid::s4u::VirtualMachine*>(&host)) // Ignore virtual machines
250     return;
251   host.extension_set(new Photovoltaic(&host));
252 }
253
254 /* **************************** Public interface *************************** */
255
256 static void ensure_plugin_inited()
257 {
258   if (not Photovoltaic::EXTENSION_ID.valid())
259     throw simgrid::xbt::InitializationError(
260         "The Photovoltaic plugin is not active. Please call sg_photovoltaic_plugin_init() "
261         "before calling any function related to that plugin.");
262 }
263
264 /** @ingroup plugin_photovoltaic
265  *  @brief Enable photovoltaic plugin.
266  */
267 void sg_photovoltaic_plugin_init()
268 {
269   if (Photovoltaic::EXTENSION_ID.valid())
270     return;
271   Photovoltaic::EXTENSION_ID = simgrid::s4u::Host::extension_create<Photovoltaic>();
272   simgrid::s4u::Host::on_creation_cb(&on_creation);
273 }
274
275 /** @ingroup plugin_photovoltaic
276  *  @param s The solar irradiance to set in W/m².
277  */
278 void sg_photovoltaic_set_solar_irradiance(const_sg_host_t host, double s)
279 {
280   ensure_plugin_inited();
281   host->extension<Photovoltaic>()->set_solar_irradiance(s);
282 }
283
284 /** @ingroup plugin_photovoltaic
285  *  @return Power generation in W.
286  */
287 double sg_photovoltaic_get_power(const_sg_host_t host)
288 {
289   ensure_plugin_inited();
290   return host->extension<Photovoltaic>()->get_power();
291 }