Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Respect coding style for boolean operators.
[simgrid.git] / src / plugins / battery.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/battery.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(battery, "Battery management", &sg_battery_plugin_init)
20
21 /** @defgroup plugin_battery plugin_battery Plugin Battery
22
23   @beginrst
24
25 This is the battery plugin, enabling management of batteries on hosts.
26 To activate this plugin, first call :cpp:func:`sg_battery_plugin_init()`.
27
28 We consider a constant energy exchange model.
29
30 Properties of batteries such as State of Charge and State of Health are lazily updated, ie., when reading values and
31 when the power is modified.
32
33 State of Charge (SoC)
34 .....................
35
36 If the power of a battery is set to a negative value then the battery will act as a load and fill over time until it
37 reaches its maximal SoC. Conversely, if the power of a battery is set to a positive value then the battery will act as a
38 generator and deplete over time until it reaches its minimal SoC. When reaching either its maximal or minimal SoC it
39 will set its power to 0.
40
41 The natural depletion of batteries over time is not taken into account.
42
43 State of Health (SoH)
44 .....................
45
46 A battery starts with an energy budget :math:`E` such as:
47
48 .. math::
49
50   E = C \times U \times D \times N \times 2
51
52 Where :math:`C` is the initial capacity, :math:`U` is the ratio of usable capacity, :math:`D` is the depth of discharge
53 and :math:`N` is the number of cycles of the battery.
54
55 The SoH represents the consumption of this energy budget during the lifetime of the battery.
56 Use the battery reduces its SoH and its capacity in consequence.
57 When the SoH reaches 0, the battery becomes unusable.
58
59 .. warning::
60
61   Due to the decrease of the battery capacity with the SoH, a large usable capacity leads to very tiny battery capacity
62   when reaching low SoH. This may results in charge and discharge cycles too short to be evaluated by the simulator. To
63   avoid this situation you should not try to reach a SoH of 0 with a usable capacity set to 1.
64
65 Plotting the output of the example "battery-degradation" highlights the linear decrease of the SoH due to a continuous
66 use of the battery and the decreasing cycle duration as its capacity reduces:
67
68 .. image:: /img/battery_degradation.svg
69    :align: center
70
71 Batteries properties
72 ....................
73
74 Properties of the batteries are defined as properties of hosts in the platform XML file.
75
76 Here is an example of XML declaration:
77
78 .. code-block:: xml
79
80    <host id="Host" speed="100.0Mf" core="1">
81        <prop id="battery_active" value="1" />
82        <prop id="battery_capacity" value="10" />
83        <prop id="battery_cycles" value="200" />
84        <prop id="battery_state_of_charge" value="0.8" />
85    </host>
86
87 The different properties are:
88
89 - ``battery_active``: Set the battery as active if set to 1 (default=0)
90 - ``battery_power``: Set the initial power of the battery in W (default=0). A negative value indicates that the battery act as a load and charge. A positive value indicates that the battery act as a generator and discharge
91 - ``battery_state_of_charge``: Set the initial state of charge of the battery (default=0)
92 - ``battery_state_of_charge_min``: Set the minimal state of charge of the battery (default=0.2)
93 - ``battery_state_of_charge_max``: Set the maximal state of charge of the battery (default=0.8)
94 - ``battery_capacity``: Set the initial capacity of the battery in Wh (default=0)
95 - ``battery_usable_capacity``: Set the ratio of usable capacity of the battery (default=0.8)
96 - ``battery_depth_of_discharge``: Set the depth of discharge of the battery (default=0.9)
97 - ``battery_charge_efficiency``: Set the charge efficiency of the battery (default=1)
98 - ``battery_discharge_efficiency``: Set the charge efficiency of the battery (default=1)
99 - ``battery_cycles``: Set the number of cycle of the battery (default=1)
100 - ``battery_depth_of_discharge``: Set the number of cycle of the battery (default=1)
101 - ``battery_eval_cost``: Evaluate the cost of the battery during the simulation if set to 1 (defaulf=0)
102 - ``battery_investment_cost``: Set the investment cost of the battery (default=0)
103 - ``battery_static_maintenance_cost``: Set the static maintenance cost of the battery (default=0)
104 - ``battery_variable_maintenance_cost``: Set the variable maintenance cost of the battery (default=0)
105
106   @endrst
107  */
108 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(battery, kernel, "Logging specific to the battery plugin");
109
110 namespace simgrid::plugin {
111 class Battery {
112 private:
113   simgrid::s4u::Host* host_ = nullptr;
114
115   double state_of_charge_min_  = 0.2;
116   double state_of_charge_max_  = 0.8;
117   double charge_efficiency_    = 1;
118   double discharge_efficiency_ = 1;
119   double initial_capacity_wh_  = 0;
120   double cycles_ = 1; // total complete cycles (charge + discharge) the battery can do before complete depletion.
121   double depth_of_discharge_ = 0.9;
122   double usable_capacity_    = 0.8;
123   double energy_budget_j_    = 0;
124
125   bool active_               = false;
126   double power_w_            = 0; // NEGATIVE when charging (consumes power) POSITIVE when discharging (generates power)
127   double state_of_charge_    = 0;
128   double capacity_wh_        = 0;
129   double next_event_         = -1;
130   double energy_exchanged_j_ = 0;
131   double last_updated_       = 0;
132
133   // Calculation of costs from Bei Li thesis (link :https://tel.archives-ouvertes.fr/tel-02077668/document) (chapter 4)
134   bool eval_cost_                                = false;
135   double cumulative_cost_                        = 0;
136   double investment_cost_per_wh_                 = 0;
137   double static_maintenance_cost_per_wh_times_h_ = 0;
138   double variable_maintenance_cost_per_wh_       = 0;
139
140   void init_battery_params();
141   void init_cost_params();
142   void update();
143
144   void set_state_of_charge(double soc);
145   void set_state_of_charge_min(double soc);
146   void set_state_of_charge_max(double soc);
147   void set_capacity(double c);
148   void set_initial_capacity(double c);
149   void set_cycles(int c);
150   void set_depth_of_discharge(double d);
151   void set_usable_capacity(double c);
152   void set_charge_efficiency(double e);
153   void set_discharge_efficiency(double e);
154   void set_eval_cost(bool eval);
155   void set_investment_cost(double c);
156   void set_static_maintenance_cost(double c);
157   void set_variable_maintenance_cost(double c);
158
159   bool is_charging();
160
161 public:
162   static simgrid::xbt::Extension<simgrid::s4u::Host, Battery> EXTENSION_ID;
163
164   explicit Battery(simgrid::s4u::Host* host);
165   ~Battery();
166
167   void set_state(bool state);
168   void set_power(const double power);
169
170   bool is_active() const;
171   double get_power();
172   double get_state_of_charge();
173   double get_state_of_charge_min() const;
174   double get_state_of_charge_max() const;
175   double get_state_of_health();
176   double get_capacity();
177   double get_cumulative_cost();
178   double get_next_event_date();
179 };
180
181 simgrid::xbt::Extension<simgrid::s4u::Host, Battery> Battery::EXTENSION_ID;
182
183 void Battery::set_power(const double p)
184 {
185   update();
186   xbt_assert(p == 0 or (p > 0 and state_of_charge_ > state_of_charge_min_) or
187                  (p < 0 and state_of_charge_ < state_of_charge_max_),
188              "Incoherent power and state of charge. A battery cannot charge(discharge) past its maximal(minimal) state "
189              "of charge.");
190   xbt_assert(p == 0 or energy_exchanged_j_ < energy_budget_j_, "Cannot set power of a fully used battery.");
191   simgrid::kernel::actor::simcall_answered([this, p] {
192     power_w_ = p;
193     if (power_w_ == 0) {
194       next_event_ = -1;
195       return;
196     }
197     double soc_shutdown;
198     double soh_shutdown;
199     if (power_w_ > 0) {
200       soc_shutdown = capacity_wh_ * 3600 * (state_of_charge_ - state_of_charge_min_) / (power_w_ * charge_efficiency_);
201       soh_shutdown = (energy_budget_j_ - energy_exchanged_j_) / (power_w_ * charge_efficiency_);
202     } else { // power_w_ < 0
203       soc_shutdown =
204           capacity_wh_ * 3600 * (state_of_charge_max_ - state_of_charge_) / (abs(power_w_) / discharge_efficiency_);
205       soh_shutdown = (energy_budget_j_ - energy_exchanged_j_) / (abs(power_w_) / discharge_efficiency_);
206     }
207     if (soh_shutdown <= 0)
208       next_event_ = simgrid::s4u::Engine::get_clock() + soc_shutdown;
209     else
210       next_event_ = simgrid::s4u::Engine::get_clock() + std::min(soc_shutdown, soh_shutdown);
211   });
212 }
213
214 void Battery::set_state(bool state)
215 {
216   update();
217   simgrid::kernel::actor::simcall_answered([this, state] { active_ = state; });
218 }
219
220 void Battery::set_state_of_charge(double soc)
221 {
222   xbt_assert(soc > 0 and soc <= 1, " : state of charge should be in ]0,1] (provided: %f)", soc);
223   simgrid::kernel::actor::simcall_answered([this, soc] { state_of_charge_ = soc; });
224 }
225
226 void Battery::set_state_of_charge_min(double soc)
227 {
228   xbt_assert(soc > 0 and soc <= 1 and soc < state_of_charge_max_,
229              " : state of charge min should be in ]0,1] and below state of charge max (provided: %f)", soc);
230   simgrid::kernel::actor::simcall_answered([this, soc] { state_of_charge_min_ = soc; });
231 }
232
233 void Battery::set_state_of_charge_max(double soc)
234 {
235   xbt_assert(soc > 0 and soc <= 1 and soc > state_of_charge_min_,
236              " : state of charge max should be in ]0,1] and above state of charge min (provided: %f)", soc);
237   simgrid::kernel::actor::simcall_answered([this, soc] { state_of_charge_max_ = soc; });
238 }
239
240 void Battery::set_initial_capacity(double c)
241 {
242   xbt_assert(c > 0, " : capacity should be > 0 (provided: %f)", c);
243   simgrid::kernel::actor::simcall_answered([this, c] { initial_capacity_wh_ = c; });
244 }
245
246 void Battery::set_capacity(double c)
247 {
248   xbt_assert(c > 0, " : capacity should be > 0 (provided: %f)", c);
249   simgrid::kernel::actor::simcall_answered([this, c] { capacity_wh_ = c; });
250 }
251
252 void Battery::set_cycles(int c)
253 {
254   xbt_assert(c > 0, " : cycles should be > 0 (provided: %d)", c);
255   simgrid::kernel::actor::simcall_answered([this, c] { cycles_ = c; });
256 }
257
258 void Battery::set_depth_of_discharge(double d)
259 {
260   xbt_assert(d > 0 and d <= 1, " : depth of discharge should be in ]0, 1] (provided: %f)", d);
261   simgrid::kernel::actor::simcall_answered([this, d] { depth_of_discharge_ = d; });
262 }
263
264 void Battery::set_usable_capacity(double c)
265 {
266   xbt_assert(c > 0 and c <= 1, " : usable capacity should be in ]0, 1] (provided: %f)", c);
267   simgrid::kernel::actor::simcall_answered([this, c] { usable_capacity_ = c; });
268 }
269
270 void Battery::set_charge_efficiency(double e)
271 {
272   xbt_assert(e > 0 and e <= 1, " : charge efficiency should be in [0,1] (provided: %f)", e);
273   simgrid::kernel::actor::simcall_answered([this, e] { charge_efficiency_ = e; });
274 }
275
276 void Battery::set_discharge_efficiency(double e)
277 {
278   xbt_assert(e > 0 and e <= 1, " : discharge efficiency should be in [0,1] (provided: %f)", e);
279   simgrid::kernel::actor::simcall_answered([this, e] { discharge_efficiency_ = e; });
280 }
281
282 void Battery::set_eval_cost(bool eval)
283 {
284   simgrid::kernel::actor::simcall_answered([this, eval] { eval_cost_ = eval; });
285 }
286
287 void Battery::set_investment_cost(double c)
288 {
289   xbt_assert(c >= 0, " : investment cost should be >= 0 (provided: %f)", c);
290   simgrid::kernel::actor::simcall_answered([this, c] { investment_cost_per_wh_ = c; });
291 }
292
293 void Battery::set_static_maintenance_cost(double c)
294 {
295   xbt_assert(c >= 0, " : static maintenance cost should be >= 0 (provided: %f)", c);
296   simgrid::kernel::actor::simcall_answered([this, c] { static_maintenance_cost_per_wh_times_h_ = c; });
297 }
298
299 void Battery::set_variable_maintenance_cost(double c)
300 {
301   xbt_assert(c >= 0, " : variable maintenance cost should be >= 0 (provided: %f)", c);
302   simgrid::kernel::actor::simcall_answered([this, c] { variable_maintenance_cost_per_wh_ = c; });
303 }
304
305 bool Battery::is_charging()
306 {
307   update();
308   return power_w_ < 0;
309 }
310
311 bool Battery::is_active() const
312 {
313   return active_;
314 }
315
316 double Battery::get_power()
317 {
318   update();
319   return power_w_;
320 }
321
322 double Battery::get_state_of_charge()
323 {
324   update();
325   return state_of_charge_;
326 }
327
328 double Battery::get_state_of_charge_min() const
329 {
330   return state_of_charge_min_;
331 }
332
333 double Battery::get_state_of_charge_max() const
334 {
335   return state_of_charge_max_;
336 }
337
338 double Battery::get_state_of_health()
339 {
340   update();
341   return 1 - (energy_exchanged_j_ / energy_budget_j_);
342 }
343
344 double Battery::get_capacity()
345 {
346   update();
347   return capacity_wh_;
348 }
349
350 double Battery::get_cumulative_cost()
351 {
352   update();
353   return cumulative_cost_;
354 }
355
356 double Battery::get_next_event_date()
357 {
358   update();
359   return next_event_;
360 }
361
362 void Battery::init_battery_params()
363 {
364   const char* prop_chars;
365   prop_chars = host_->get_property("battery_capacity");
366   if (prop_chars) {
367     set_capacity(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
368     set_initial_capacity(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
369   }
370   prop_chars = host_->get_property("battery_usable_capacity");
371   if (prop_chars)
372     set_usable_capacity(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
373   prop_chars = host_->get_property("battery_depth_of_discharge");
374   if (prop_chars)
375     set_depth_of_discharge(
376         xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
377   prop_chars = host_->get_property("battery_cycles");
378   if (prop_chars)
379     set_cycles(xbt_str_parse_int(prop_chars, ("cannot parse int: " + std::string(prop_chars)).c_str()));
380   simgrid::kernel::actor::simcall_answered([this] {
381     energy_budget_j_ = (initial_capacity_wh_ * usable_capacity_ * depth_of_discharge_ * 3600 * cycles_ * 2);
382   });
383   prop_chars = host_->get_property("battery_active");
384   if (prop_chars)
385     set_state(xbt_str_parse_int(prop_chars, ("cannot parse int: " + std::string(prop_chars)).c_str()));
386   prop_chars = host_->get_property("battery_state_of_charge_min");
387   if (prop_chars)
388     set_state_of_charge_min(
389         xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
390   prop_chars = host_->get_property("battery_state_of_charge_max");
391   if (prop_chars)
392     set_state_of_charge_max(
393         xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
394   prop_chars = host_->get_property("battery_charge_efficiency");
395   if (prop_chars)
396     set_charge_efficiency(
397         xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
398   prop_chars = host_->get_property("battery_discharge_efficiency");
399   if (prop_chars)
400     set_discharge_efficiency(
401         xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
402   prop_chars = host_->get_property("battery_state_of_charge");
403   if (prop_chars)
404     set_state_of_charge(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
405   prop_chars = host_->get_property("battery_eval_cost");
406   if (prop_chars)
407     set_eval_cost(xbt_str_parse_int(prop_chars, ("cannot parse int: " + std::string(prop_chars)).c_str()));
408   prop_chars = host_->get_property("battery_investment_cost");
409   if (prop_chars)
410     set_investment_cost(xbt_str_parse_int(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
411   prop_chars = host_->get_property("battery_static_maintenance_cost");
412   if (prop_chars)
413     set_static_maintenance_cost(
414         xbt_str_parse_int(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
415   prop_chars = host_->get_property("battery_variable_maintenance_cost");
416   if (prop_chars)
417     set_variable_maintenance_cost(
418         xbt_str_parse_int(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
419   prop_chars = host_->get_property("battery_power");
420   if (prop_chars)
421     set_power(xbt_str_parse_double(prop_chars, ("cannot parse double: " + std::string(prop_chars)).c_str()));
422   simgrid::kernel::actor::simcall_answered([this] { last_updated_ = simgrid::s4u::Engine::get_clock(); });
423 }
424
425 void Battery::update()
426 {
427   simgrid::kernel::actor::simcall_answered([this] {
428     double now             = simgrid::s4u::Engine::get_clock();
429     double time_delta_real = now - last_updated_;
430     if (time_delta_real <= 0 || not is_active())
431       return;
432     double time_delta_until_event = next_event_ - last_updated_;
433     bool event                    = next_event_ != -1 and time_delta_until_event <= time_delta_real;
434     double power_real_w           = power_w_ < 0 ? power_w_ * charge_efficiency_ : power_w_ / discharge_efficiency_;
435     state_of_charge_ -= power_real_w * (event ? time_delta_until_event : time_delta_real) / (3600 * capacity_wh_);
436     energy_exchanged_j_ += (event ? time_delta_until_event : time_delta_real) * abs(power_real_w);
437     capacity_wh_ = initial_capacity_wh_ * usable_capacity_ * (1 - (energy_exchanged_j_ / energy_budget_j_)) +
438                    initial_capacity_wh_ * (1 - usable_capacity_);
439     capacity_wh_ = std::max(capacity_wh_, 0.0);
440     if (eval_cost_) {
441       double usage_cost_per_wh =
442           (investment_cost_per_wh_ / (depth_of_discharge_ * cycles_ * 2) + variable_maintenance_cost_per_wh_);
443       double usage_cost =
444           usage_cost_per_wh * abs(power_real_w) * (event ? time_delta_until_event : time_delta_real) / 3600;
445       double static_maintenance_cost =
446           static_maintenance_cost_per_wh_times_h_ * initial_capacity_wh_ * time_delta_real / 3600;
447       cumulative_cost_ += usage_cost + static_maintenance_cost;
448     }
449     if (event) {
450       power_w_    = 0;
451       next_event_ = -1;
452     }
453     last_updated_ = now;
454   });
455 }
456
457 Battery::Battery(simgrid::s4u::Host* host) : host_(host)
458 {
459   init_battery_params();
460 }
461
462 Battery::~Battery() = default;
463 } // namespace simgrid::plugin
464
465 using simgrid::plugin::Battery;
466
467 /* **************************** events  callback *************************** */
468
469 static void on_creation(simgrid::s4u::Host& host)
470 {
471   if (dynamic_cast<simgrid::s4u::VirtualMachine*>(&host)) // Ignore virtual machines
472     return;
473   host.extension_set(new Battery(&host));
474 }
475
476 /* **************************** Public interface *************************** */
477
478 static void ensure_plugin_inited()
479 {
480   if (not Battery::EXTENSION_ID.valid())
481     throw simgrid::xbt::InitializationError("The Battery plugin is not active. Please call sg_battery_plugin_init() "
482                                             "before calling any function related to that plugin.");
483 }
484
485 /** @ingroup plugin_battery
486  *  @brief Enable battery plugin.
487  */
488 void sg_battery_plugin_init()
489 {
490   if (Battery::EXTENSION_ID.valid())
491     return;
492   Battery::EXTENSION_ID = simgrid::s4u::Host::extension_create<Battery>();
493   simgrid::s4u::Host::on_creation_cb(&on_creation);
494 }
495
496 /** @ingroup plugin_battery
497  *  @param state The state to set.
498  *  @brief Set the state of the battery.
499  * A battery set to inactive (false) will neither update its state of charge nor its state of health.
500  */
501 void sg_battery_set_state(const_sg_host_t host, bool state)
502 {
503   ensure_plugin_inited();
504   host->extension<Battery>()->set_state(state);
505 }
506
507 /** @ingroup plugin_battery
508  *  @param power The power to set in W.
509  *  @brief Set the power of the battery.
510  *  @note A negative value makes the battery act as a load and charge.
511  * A positive value makes the battery act as a generator and discharge.
512  */
513 void sg_battery_set_power(const_sg_host_t host, double power)
514 {
515   ensure_plugin_inited();
516   host->extension<Battery>()->set_power(power);
517 }
518
519 /** @ingroup plugin_battery
520  *  @brief Return true if the battery is active.
521  */
522 bool sg_battery_is_active(const_sg_host_t host)
523 {
524   ensure_plugin_inited();
525   return host->extension<Battery>()->is_active();
526 }
527
528 /** @ingroup plugin_battery
529  *  @brief Return the power of the battery in W.
530  *  @note A negative value indicates that the battery act as a load and charge.
531  * A positive value indicates that the battery act as a generator and discharge.
532  */
533 double sg_battery_get_power(const_sg_host_t host)
534 {
535   ensure_plugin_inited();
536   return host->extension<Battery>()->get_power();
537 }
538
539 /** @ingroup plugin_battery
540  *  @brief Return the state of charge of the battery.
541  */
542 double sg_battery_get_state_of_charge(const_sg_host_t host)
543 {
544   ensure_plugin_inited();
545   return host->extension<Battery>()->get_state_of_charge();
546 }
547
548 /** @ingroup plugin_battery
549  *  @brief Return the minimal state of charge of the battery.
550  */
551 double sg_battery_get_state_of_charge_min(const_sg_host_t host)
552 {
553   ensure_plugin_inited();
554   return host->extension<Battery>()->get_state_of_charge_min();
555 }
556
557 /** @ingroup plugin_battery
558  *  @brief Return the maximal state of charge of the battery.
559  */
560 double sg_battery_get_state_of_charge_max(const_sg_host_t host)
561 {
562   ensure_plugin_inited();
563   return host->extension<Battery>()->get_state_of_charge_max();
564 }
565
566 /** @ingroup plugin_battery
567  *  @brief Return the state of health of the battery.
568  */
569 double sg_battery_get_state_of_health(const_sg_host_t host)
570 {
571   ensure_plugin_inited();
572   return host->extension<Battery>()->get_state_of_health();
573 }
574
575 /** @ingroup plugin_battery
576  *  @brief Return the capacity of the battery in Wh.
577  *  @note capacity is reduced by the state of health of the battery.
578  */
579 double sg_battery_get_capacity(const_sg_host_t host)
580 {
581   ensure_plugin_inited();
582   return host->extension<Battery>()->get_capacity();
583 }
584
585 /** @ingroup plugin_battery
586  *  @brief Return the cumulative cost of the battery.
587  */
588 double sg_battery_get_cumulative_cost(const_sg_host_t host)
589 {
590   ensure_plugin_inited();
591   return host->extension<Battery>()->get_cumulative_cost();
592 }
593
594 /** @ingroup plugin_battery
595  *  @brief Return the date of the next event, i.e., when the battery will be empty or full.
596  *  @note If power is null then return -1.
597  */
598 double sg_battery_get_next_event_date(const_sg_host_t host)
599 {
600   ensure_plugin_inited();
601   return host->extension<Battery>()->get_next_event_date();
602 }