From: Adrien Gougeon Date: Thu, 28 Sep 2023 08:26:02 +0000 (+0200) Subject: add battery-chiller-solar example. X-Git-Tag: v3.35~89^2~29^2~1 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/b1786c6251bb5352905bb1d0babb8267307a4b07 add battery-chiller-solar example. --- diff --git a/MANIFEST.in b/MANIFEST.in index d33f19fba6..5e93c83d5e 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -166,6 +166,8 @@ include examples/cpp/app-masterworkers/s4u-app-masterworkers.tesh include examples/cpp/app-masterworkers/s4u-app-masterworkers_d.xml include examples/cpp/app-token-ring/s4u-app-token-ring.cpp 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-degradation/plot_battery_degradation.py include examples/cpp/battery-degradation/s4u-battery-degradation.cpp include examples/cpp/battery-degradation/s4u-battery-degradation.tesh diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 2ddf038320..abda1093ca 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -157,7 +157,7 @@ foreach (example activityset-testany activityset-waitany activityset-waitall act 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-degradation battery-simple battery-energy + battery-chiller-solar 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 diff --git a/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp new file mode 100644 index 0000000000..454b2590cd --- /dev/null +++ b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp @@ -0,0 +1,128 @@ +/* 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 combine the battery plugin, the chiller plugin and the solar + panel plugin. It illustrates how to use them together to evaluate the amount + of brown energy (from the electrical grid) and green energy (from the solar + panel) consumed by several machines. + + In this scenario we have two host placed in a room. + The room is maintained at 24°C by a chiller, powered by the electrical grid + and consumes brown energy. + The two hosts are powered by a battery when available, and the electrical + grid otherwise. The battery is charged by a solar panel. + + We simulate two days from 00h00 to 00h00. + The solar panel generates power from 8h to 20h with a peak at 14h. + During the simulation, when the charge of the battery goes: + - below 75% the solar panel is connected to the battery + - above 80% the solar panel is disconnected from the battery + - below 20% the hosts are disconnected from the battery + - above 25% the hosts are connected to the battery + + The two hosts are always idle, except from 12h to 16h on the first day. +*/ + +#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 + +XBT_LOG_NEW_DEFAULT_CATEGORY(battery_chiller_solar, "Messages specific for this s4u example"); +namespace sg4 = simgrid::s4u; +namespace sp = simgrid::plugins; + +static void irradiance_manager(sp::SolarPanelPtr solar_panel) +{ + int time = 0; + int time_step = 10; + double amplitude = 1000 / 2.0; + double period = 24 * 60 * 60; + double shift = 16 * 60 * 60; + double irradiance; + while (true) { + irradiance = amplitude * sin(2 * M_PI * (time + shift) / period); + irradiance = irradiance < 0 ? 0 : irradiance; + solar_panel->set_solar_irradiance(irradiance); + sg4::this_actor::sleep_for(time_step); + time += time_step; + } +} + +static void host_job_manager(double start, double duration) +{ + sg4::this_actor::sleep_until(start); + sg4::this_actor::get_host()->execute(duration * sg4::this_actor::get_host()->get_speed()); +} + +static void end_manager(sp::BatteryPtr b) +{ + sg4::this_actor::sleep_until(86400 * 2); + for (auto& handler : b->get_handlers()) + 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); + e.load_platform(argv[1]); + sg_host_energy_plugin_init(); + + auto myhost1 = e.host_by_name("MyHost1"); + auto myhost2 = e.host_by_name("MyHost2"); + + auto battery = sp::Battery::init("Battery", 0.2, -1e3, 1e3, 0.9, 0.9, 2000, 1000); + auto chiller = sp::Chiller::init("Chiller", 50, 1006, 0.2, 0.9, 24, 24, 1e3); + auto solar_panel = sp::SolarPanel::init("Solar Panel", 1.1, 0.9, 0, 0, 1e3); + chiller->add_host(myhost1); + chiller->add_host(myhost2); + solar_panel->on_this_power_change_cb( + [battery](sp::SolarPanel* s) { battery->set_load("Solar Panel", s->get_power() * -1); }); + battery->schedule_handler(0.8, sp::Battery::CHARGE, sp::Battery::Handler::PERSISTANT, + [battery]() { battery->set_load("Solar Panel", false); }); + battery->schedule_handler(0.75, sp::Battery::DISCHARGE, sp::Battery::Handler::PERSISTANT, + [battery]() { battery->set_load("Solar Panel", true); }); + battery->schedule_handler(0.2, sp::Battery::DISCHARGE, sp::Battery::Handler::PERSISTANT, + [battery, &myhost1, &myhost2]() { + battery->connect_host(myhost1, false); + battery->connect_host(myhost2, false); + }); + battery->schedule_handler(0.25, sp::Battery::CHARGE, sp::Battery::Handler::PERSISTANT, + [battery, &myhost1, &myhost2]() { + battery->connect_host(myhost1); + battery->connect_host(myhost2); + }); + + sg4::Actor::create("irradiance_manager", myhost1, irradiance_manager, solar_panel)->daemonize(); + 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); + XBT_INFO( + "Energy consumed by the hosts (green / brown): %.2fMJ " + "/ %.2fMJ", + battery->get_energy_provided() / 1e6, + (sg_host_get_consumed_energy(myhost1) + sg_host_get_consumed_energy(myhost2) - battery->get_energy_provided()) / + 1e6); + XBT_INFO("Energy consumed by the chiller (brown): %.2fMJ", chiller->get_energy_consumed() / 1e6); + return 0; +} diff --git a/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh new file mode 100644 index 0000000000..f2cddf46e3 --- /dev/null +++ b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh @@ -0,0 +1,10 @@ +#!/usr/bin/env tesh + +$ ${bindir:=.}/s4u-battery-chiller-solar ${platfdir}/energy_platform.xml +> [172800.000000] [host_energy/INFO] Total energy consumption: 53568000.000000 Joules (used hosts: 36288000.000000 Joules; unused/idle hosts: 17280000.000000) +> [172800.000000] [battery_chiller_solar/INFO] State of charge of the battery: 20.4% +> [172800.000000] [battery_chiller_solar/INFO] Energy consumed by the hosts (green / brown): 21.60MJ / 14.69MJ +> [172800.000000] [battery_chiller_solar/INFO] Energy consumed by the chiller (brown): 48.38MJ +> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost1: 17568000.000000 Joules +> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost2: 18720000.000000 Joules +> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost3: 17280000.000000 Joules \ No newline at end of file diff --git a/examples/cpp/battery-degradation/s4u-battery-degradation.cpp b/examples/cpp/battery-degradation/s4u-battery-degradation.cpp index 9510404fa0..13b149ef46 100644 --- a/examples/cpp/battery-degradation/s4u-battery-degradation.cpp +++ b/examples/cpp/battery-degradation/s4u-battery-degradation.cpp @@ -14,13 +14,13 @@ static void manager() { auto battery = simgrid::plugins::Battery::init("Battery", 0.8, -200, 200, 0.9, 0.9, 10, 100); - battery->set_load("load", 100); + battery->set_load("load", 100.0); auto handler1 = battery->schedule_handler( 0.2, simgrid::plugins::Battery::DISCHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, [battery]() { XBT_INFO("%f,%f,SoC", simgrid::s4u::Engine::get_clock(), battery->get_state_of_charge()); XBT_INFO("%f,%f,SoH", simgrid::s4u::Engine::get_clock(), battery->get_state_of_health()); - battery->set_load("load", -100); + battery->set_load("load", -100.0); }); std::shared_ptr handler2; @@ -33,7 +33,7 @@ static void manager() battery->delete_handler(handler1); battery->delete_handler(handler2); } - battery->set_load("load", 100); + battery->set_load("load", 100.0); }); } diff --git a/include/simgrid/plugins/battery.hpp b/include/simgrid/plugins/battery.hpp index 7f0c3618ef..64c97532da 100644 --- a/include/simgrid/plugins/battery.hpp +++ b/include/simgrid/plugins/battery.hpp @@ -94,8 +94,8 @@ private: double initial_capacity_wh_; double energy_budget_j_; - std::map host_loads_ = {}; - std::map named_loads_ = {}; + std::map host_loads_ = {}; + std::map> named_loads_ = {}; std::vector> handlers_; double capacity_wh_; @@ -128,6 +128,7 @@ public: double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency, double initial_capacity_wh, int cycles); void set_load(const std::string& name, double power_w); + void set_load(const std::string& name, bool active); void connect_host(s4u::Host* host, bool active = true); double get_state_of_charge(); double get_state_of_health(); diff --git a/include/simgrid/plugins/solar_panel.hpp b/include/simgrid/plugins/solar_panel.hpp index b9097b416f..5fa424bd36 100644 --- a/include/simgrid/plugins/solar_panel.hpp +++ b/include/simgrid/plugins/solar_panel.hpp @@ -16,37 +16,18 @@ using SolarPanelPtr = boost::intrusive_ptr; XBT_PUBLIC void intrusive_ptr_release(SolarPanel* o); XBT_PUBLIC void intrusive_ptr_add_ref(SolarPanel* o); -class SolarPanelModel : public kernel::resource::Model { - std::vector solar_panels_; - -public: - explicit SolarPanelModel(); - - void add_solar_panel(SolarPanelPtr b); - void update_actions_state(double now, double delta) override; - double next_occurring_event(double now) override; -}; - class SolarPanel { - friend SolarPanelModel; - -private: - static std::shared_ptr solar_panel_model_; - std::string name_; double area_m2_; double conversion_efficiency_; double solar_irradiance_w_per_m2_; double min_power_w_; double max_power_w_; - - double power_w_ = 0; - double last_updated_ = 0; + double power_w_ = -1; explicit SolarPanel(std::string name, double area_m2, double conversion_efficiency, double solar_irradiance_w_per_m2, double min_power_w, double max_power_w); - static void init_plugin(); void update(); std::atomic_int_fast32_t refcount_{0}; @@ -61,6 +42,9 @@ private: friend void intrusive_ptr_add_ref(SolarPanel* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); } #endif + inline static xbt::signal on_power_change; + xbt::signal on_this_power_change; + public: static SolarPanelPtr init(const std::string& name, double area_m2, double conversion_efficiency, double solar_irradiance_w_per_m2, double min_power_w, double max_power_w); @@ -72,14 +56,20 @@ public: SolarPanelPtr set_min_power(double power_w); SolarPanelPtr set_max_power(double power_w); - std::string get_name() { return name_; } - const char* get_cname() { return name_.c_str(); } - double get_area() { return area_m2_; } - double get_conversion_efficiency() { return conversion_efficiency_; } - double get_solar_irradiance() { return solar_irradiance_w_per_m2_; } - double get_min_power() { return min_power_w_; } - double get_max_power() { return max_power_w_; } - double get_power() { return power_w_; } + std::string get_name() const { return name_; } + const char* get_cname() const { return name_.c_str(); } + double get_area() const { return area_m2_; } + double get_conversion_efficiency() const { return conversion_efficiency_; } + double get_solar_irradiance() const { return solar_irradiance_w_per_m2_; } + double get_min_power() const { return min_power_w_; } + double get_max_power() const { return max_power_w_; } + double get_power() const { return power_w_; } + + /** Add a callback fired after this solar panel power changed. */ + void on_this_power_change_cb(const std::function& func) { on_this_power_change.connect(func); }; + /** Add a callback fired after a solar panel power changed. + * Triggered after the on_this_power_change function.**/ + static void on_power_change_cb(const std::function& cb) { on_power_change.connect(cb); } }; } // namespace simgrid::plugins #endif diff --git a/src/plugins/battery.cpp b/src/plugins/battery.cpp index 412b69ed0f..bf18ae1946 100644 --- a/src/plugins/battery.cpp +++ b/src/plugins/battery.cpp @@ -6,10 +6,7 @@ #include #include #include -#include #include -#include -#include #include "src/kernel/resource/CpuImpl.hpp" #include "src/simgrid/module.hpp" @@ -154,11 +151,13 @@ void Battery::update() double consumed_power_w = 0; for (auto const& [host, active] : host_loads_) provided_power_w += active ? sg_host_get_current_consumption(host) : 0; - for (auto const& [name, load] : named_loads_) { - if (load > 0) - provided_power_w += load; + for (auto const& [name, pair] : named_loads_) { + if (not pair.first) + continue; + if (pair.second > 0) + provided_power_w += pair.second; else - consumed_power_w += -load; + 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_); @@ -210,11 +209,13 @@ double Battery::next_occurring_handler() double consumed_power_w = 0; for (auto const& [host, active] : host_loads_) provided_power_w += active ? sg_host_get_current_consumption(host) : 0; - for (auto const& [name, load] : named_loads_) { - if (load > 0) - provided_power_w += load; + for (auto const& [name, pair] : named_loads_) { + if (not pair.first) + continue; + if (pair.second > 0) + provided_power_w += pair.second; else - consumed_power_w += -load; + consumed_power_w += -pair.second; } provided_power_w = std::min(provided_power_w, nominal_discharge_power_w_ * discharge_efficiency_); @@ -224,10 +225,11 @@ double Battery::next_occurring_handler() for (auto& handler : handlers_) { double lost_power_w = provided_power_w / discharge_efficiency_; double gained_power_w = consumed_power_w * charge_efficiency_; - // Handler cannot happen - if ((lost_power_w == gained_power_w) or (handler->state_of_charge_ == energy_stored_j_ / (3600 * capacity_wh_)) or - (lost_power_w > gained_power_w and handler->flow_ == Flow::CHARGE) or - (lost_power_w < gained_power_w and handler->flow_ == Flow::DISCHARGE)) { + if ((lost_power_w == gained_power_w) or (handler->state_of_charge_ == get_state_of_charge()) or + (lost_power_w > gained_power_w and + (handler->flow_ == Flow::CHARGE or handler->state_of_charge_ > get_state_of_charge())) or + (lost_power_w < gained_power_w and + (handler->flow_ == Flow::DISCHARGE or handler->state_of_charge_ < get_state_of_charge()))) { continue; } // Evaluate time until handler happen @@ -263,7 +265,7 @@ Battery::Battery(const std::string& name, double state_of_charge, double nominal , capacity_wh_(initial_capacity_wh) , energy_stored_j_(state_of_charge * 3600 * initial_capacity_wh) { - xbt_assert(nominal_charge_power_w <= 0, " : nominal charge power must be non-negative (provided: %f)", + xbt_assert(nominal_charge_power_w <= 0, " : nominal charge power must be <= 0 (provided: %f)", nominal_charge_power_w); xbt_assert(nominal_discharge_power_w >= 0, " : nominal discharge power must be non-negative (provided: %f)", nominal_discharge_power_w); @@ -309,7 +311,21 @@ BatteryPtr Battery::init(const std::string& name, double state_of_charge, double */ void Battery::set_load(const std::string& name, double power_w) { - named_loads_[name] = power_w; + kernel::actor::simcall_answered([this, &name, &power_w] { + if (named_loads_.find(name) == named_loads_.end()) + named_loads_[name] = std::make_pair(true, power_w); + else + named_loads_[name].second = power_w; + }); +} + +/** @ingroup plugin_battery + * @param name The name of the load + * @param active Status of the load. If false then the load is ignored by the Battery. + */ +void Battery::set_load(const std::string& name, bool active) +{ + kernel::actor::simcall_answered([this, &name, &active] { named_loads_[name].first = active; }); } /** @ingroup plugin_battery @@ -322,7 +338,7 @@ void Battery::set_load(const std::string& name, double power_w) */ void Battery::connect_host(s4u::Host* host, bool active) { - host_loads_[host] = active; + kernel::actor::simcall_answered([this, &host, &active] { host_loads_[host] = active; }); } /** @ingroup plugin_battery diff --git a/src/plugins/solar_panel.cpp b/src/plugins/solar_panel.cpp index 8e44734b82..abf999513d 100644 --- a/src/plugins/solar_panel.cpp +++ b/src/plugins/solar_panel.cpp @@ -43,50 +43,22 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(SolarPanel, kernel, "Logging specific to the sol namespace simgrid::plugins { -/* SolarPanelModel */ - -SolarPanelModel::SolarPanelModel() : Model("SolarPanelModel") {} - -void SolarPanelModel::add_solar_panel(SolarPanelPtr b) -{ - solar_panels_.push_back(b); -} - -void SolarPanelModel::update_actions_state(double now, double delta) -{ - for (auto solar_panel : solar_panels_) - solar_panel->update(); -} - -double SolarPanelModel::next_occurring_event(double now) -{ - return -1; -} - /* SolarPanel */ -std::shared_ptr SolarPanel::solar_panel_model_; - -void SolarPanel::init_plugin() -{ - auto model = std::make_shared(); - simgrid::s4u::Engine::get_instance()->add_model(model); - SolarPanel::solar_panel_model_ = model; -} - void SolarPanel::update() { simgrid::kernel::actor::simcall_answered([this] { - double now = simgrid::s4u::Engine::get_clock(); - if (now <= last_updated_) - return; double power_w = conversion_efficiency_ * area_m2_ * solar_irradiance_w_per_m2_; - if (power_w_ < min_power_w_) + if (power_w < min_power_w_) power_w = 0; - if (power_w_ > max_power_w_) + if (power_w > max_power_w_) power_w = max_power_w_; - power_w_ = power_w; - last_updated_ = now; + auto previous_power_w = power_w_; + power_w_ = power_w; + if (previous_power_w != power_w_) { + on_this_power_change(this); + on_power_change(this); + } }); } @@ -122,14 +94,9 @@ SolarPanel::SolarPanel(std::string name, double area_m2, double conversion_effic SolarPanelPtr SolarPanel::init(const std::string& name, double area_m2, double conversion_efficiency, double solar_irradiance_w_per_m2, double min_power_w, double max_power_w) { - static bool plugin_inited = false; - if (not plugin_inited) { - init_plugin(); - plugin_inited = true; - } auto solar_panel = SolarPanelPtr( new SolarPanel(name, area_m2, conversion_efficiency, solar_irradiance_w_per_m2, min_power_w, max_power_w)); - solar_panel_model_->add_solar_panel(solar_panel); + solar_panel->update(); return solar_panel; } @@ -151,6 +118,7 @@ SolarPanelPtr SolarPanel::set_area(double area_m2) { xbt_assert(area_m2 >= 0, " : area must be > 0 (provided: %f)", area_m2); kernel::actor::simcall_answered([this, area_m2] { area_m2_ = area_m2; }); + update(); return this; } @@ -162,6 +130,7 @@ SolarPanelPtr SolarPanel::set_conversion_efficiency(double e) { xbt_assert(e >= 0 and e <= 1, " : conversion efficiency must be in [0,1] (provided: %f)", e); kernel::actor::simcall_answered([this, e] { conversion_efficiency_ = e; }); + update(); return this; } @@ -175,6 +144,7 @@ SolarPanelPtr SolarPanel::set_solar_irradiance(double solar_irradiance_w_per_m2) solar_irradiance_w_per_m2); kernel::actor::simcall_answered( [this, solar_irradiance_w_per_m2] { solar_irradiance_w_per_m2_ = solar_irradiance_w_per_m2; }); + update(); return this; } @@ -188,6 +158,7 @@ SolarPanelPtr SolarPanel::set_min_power(double power_w) xbt_assert(max_power_w_ > power_w, " : maximal power must be above minimal power (provided: %f, max: %f)", power_w, max_power_w_); kernel::actor::simcall_answered([this, power_w] { min_power_w_ = power_w; }); + update(); return this; } @@ -201,6 +172,7 @@ SolarPanelPtr SolarPanel::set_max_power(double power_w) xbt_assert(min_power_w_ < power_w, " : maximal power must be above minimal power (provided: %f, min: %f)", power_w, min_power_w_); kernel::actor::simcall_answered([this, power_w] { max_power_w_ = power_w; }); + update(); return this; }