Skip to content

EntitiesBlocks Základní úvod do knihovny VEDriversLite.EntitiesBlocks

Štefan Prokop edited this page Feb 17, 2023 · 2 revisions

Knihovna VEDriversLite.EntitiesBlocks obsahuje obecné jádro, které umí počítat s časově ohraničenými bloky vyjadřujícími určitou hodnotu. První fáze vývoje knihovny je více zaměřena na výpočty distribuce energií, nicméně základní model jako takový je obecný. Knihovnu lze použít například pro plánovnání cashflow, zaznamenávání časů na projektu či jeho nákladů, distribuci vzduchu, vody, dat, apod.

Základní objekty v knihovně a jejich vazby jsou následující:

classDiagram
    IEntity <|-- IConsumer
    IEntity <|-- ISource
    IEntity <-- CommonEntity

    class IEntityHandler {
        +List IEntitities
    }
    IEntityHandler <-- CommonEntityHandler
    class CommonEntityHandler {
    }
    class IBlock {
    }
    IBlock <-- CommonBlock 
    class CommonBlock{
    }

    class IEntity {
      +List Children
      +List Simulators 
      +List Blocks
    }
    class CommonEntity {
    }
    class IConsumer {
      + Type
    }
    IConsumer <-- CommonConsumer
    CommonEntity <-- CommonConsumer
    class CommonConsumer {
    }
    CommonConsumer <-- Device
    class Device {
    }
    CommonConsumer <-- DeviceGroup
    class DeviceGroup {
    }
    CommonConsumer <-- GroupNetwork
    class GroupNetwork {
    }

    class ISource {
      + Type
    }
    ISource <-- CommonSource
    CommonEntity <-- CommonSource
    class CommonSource {
    }
    CommonSource <-- PVESource
    class PVESource {
    }
       CommonSource <-- BatteryStorage
    class BatteryStorage {
    }
    CommonSource <-- PowerGridSupplier
    class PowerGridSupplier {
    }
 
    class ISimulator {
    }
    ISimulator <-- CommonSimulator
    class CommonSimulator {
    }
    CommonSimulator <-- ConsumerTDDSimulator
    class ConsumerTDDSimulator {
    }
    CommonSimulator <-- PVPanelsGroupsHandler
    class PVPanelsGroupsHandler {
    }
    CommonSimulator <-- BatteryBlockHandler
    class BatteryBlockHandler {
    }
Loading

Diagram je zjednodušený a neobsahuje všechny třídy.

V diagramu je vidět, že knihovna pracuje se stromem entit. Každá entita může obsahovat dceřiné entity. Strom je možné jakkoli větvit. Knihovna obsahuje i funkce pro zpětné dohledání struktury stromu (o tom více v dalších článcích). Každá entita může obsahovat bloky a simulátory. Bloky jsou jasně časově a hodnotou definované úseky "hodnoty" (např. kWh). Simulátory dokážou vygenerovat hodnotu pro daný start-end datum/čas na request.

IEntity je interface, díky čemuž nelze vytvořit jeho instanci. K tomu slouží buď BaseEntity (implementace abstraktní třídy CommonEntity) a nebo specifičtější Source nebo Consumer. To jsou nadstavbové interfacy pro vytváření různých druhů zdrojů nebo spotřebičů ve stromě. Pro vytvoření Source nebo Consumer existují konkrétní factories. Jejich použití je vidět v následujícím kódu:

   var eGrid = new BaseEntitiesHandler();

   var id = Guid.NewGuid().ToString();
   var source = SourceFactory.GetSource(SourceType.PVE, sourceName, "", id);
   var res = eGrid.AddEntity(source, sourceName, owner);
   sourceId = string.Empty;
   if (res.Item1)
      sourceId = res.Item2.Item2;

   id = Guid.NewGuid().ToString();
   var consumer = ConsumerFactory.GetConsumer(ConsumerType.Device, "device1", "", id);
   res = eGrid.AddEntity(consumer, "device1", owner);
   device1Id = string.Empty;
   if (res.Item1)
       device1Id = res.Item2.Item2;

   id = Guid.NewGuid().ToString();
   consumer = ConsumerFactory.GetConsumer(ConsumerType.Device, "device2", "", id);
   res = eGrid.AddEntity(consumer, "device2", owner);
   device2Id = string.Empty;
   if (res.Item1)
       device2Id = res.Item2.Item2;

   id = Guid.NewGuid().ToString();
   source = SourceFactory.GetSource(SourceType.Battery, "devicegroupbattery", "", id);
   res = eGrid.AddEntity(source, "devicegroupbattery", owner);
   devicegroupbatteryId = string.Empty;
   if (res.Item1)
       devicegroupbatteryId = res.Item2.Item2;

V příkladu je také vidět přidání entity do eGrid objektu. Tento objekt je typu IEntitiesHandler.

Všechny výše uvedené IEntity by ideálně měli spadnout pod nějakou společnou entitu či skupinu entit. Zde je vidět přidání vytvořených entit do společné DeviceGroup:

 id = Guid.NewGuid().ToString();
 consumer = ConsumerFactory.GetConsumer(ConsumerType.DevicesGroup, "devicegroup", "", id);
 res = eGrid.AddEntity(consumer, "devicegroup", owner);
 devicegroup = string.Empty;
 if (res.Item1)
 {
     devicegroup = res.Item2.Item2;
     eGrid.AddSubEntityToEntity(devicegroup, device1Id);
     eGrid.AddSubEntityToEntity(devicegroup, device2Id);
     // add battery which is placed in this group as backup source to reduce spikes
     eGrid.AddSubEntityToEntity(devicegroup, devicegroupbatteryId);
  }


 id = Guid.NewGuid().ToString();
 consumer = ConsumerFactory.GetConsumer(ConsumerType.GroupNetwork, "network", "", id);
 res = eGrid.AddEntity(consumer, "network", owner);
 // create object for whole network
 networkId = string.Empty;
 if (res.Item1)
 {
     networkId = res.Item2.Item2;
     eGrid.AddSubEntityToEntity(networkId, devicegroup);
     eGrid.AddSubEntityToEntity(networkId, devicegroup2);
     // add common sources in network
     eGrid.AddSubEntityToEntity(networkId, sourceId);
     eGrid.AddSubEntityToEntity(networkId, batteryId);
 }

Celý příklad vygenerování testovací sítě je možné najít v rámci testů v tomto helperu.

I jedna entita může tvořit celou síť, nicméně je vhodné si udělat strukturu. Pokud je vše připravené, je možné přidat do entity bloky a nebo simulátor. Přidání bloků je vidět v tomto testu. Postup je jednoduchý:

var Block = new BaseBlock();

// add some custom blocks of simulated consumption
var blockstoadd = new List<IBlock>();
var starttime = new DateTime(2022, 1, 3, 5, 0, 0);
var timeframe = new TimeSpan(160, 0, 0);
var endtime = starttime + timeframe;

//device which consume 1kW and run 160 hours, started on 3rd of January in 5am, for example PC
blockstoadd.Add(Block.GetBlockByPower(BlockType.Simulated,
                                     BlockDirection.Consumed,
                                     starttime,
                                     timeframe,
                                     1,
                                     egth.sourceName,
                                     egth.device2Id));

//device which consume 1kW and run 160 hours, started on 3rd of January in 5am, for example PC
blockstoadd.Add(Block.GetBlockByPower(BlockType.Simulated,
                                     BlockDirection.Consumed,
                                     starttime,
                                     timeframe,
                                     1,
                                     egth.sourceName,
                                     egth.device2Id));

//device which consume 1kW and run 160 hours, started on 3rd of January in 5am, for example PC
blockstoadd.Add(Block.GetBlockByPower(BlockType.Simulated,
                                     BlockDirection.Consumed,
                                     starttime,
                                     timeframe,
                                     1,
                                     egth.sourceName,
                                     egth.device1Id));

// add three blocks into device2 (network/devicegroup/device2) 
eGrid.AddBlocksToEntity(egth.device2Id, blockstoadd);

Ve vizuální podobě vypadají bloky vložené do entity následovně:

bloky v jedné entitě

Pokud je vybrána entita, která má více dceřinných entit, tak zobrazení všech bloků v entitě a subentitách vypadá takto:

bloky sítě entit

Poznámka: Tyto vizuální komponenty jsou součástí knihovny VEFramework.VEBlazor.EntitiesBlocks.

Jakmile jsou bloky v entitě, je možné se entity zeptat na přepočet spotřeby v rámci určitého časového úseku. Při volání funkce GetConsumptionOfEntity lze nastavit i formát bloků, které budou reprezentovat data po přepočtu. To znamená, že i když je v entitě jeden blok o délce x dní, lze získat jako výsledek seznam bloků, kdy každý má 1h timeframe. Příkladem je toto volání:

var device = eGrid.GetEntity(egth.devicegroup, EntityType.Consumer);
if (device != null)
{
    var consumption = eGrid.GetConsumptionOfEntity(egth.devicegroup, BlockTimeframe.Hour, starttime, endtime);
    var total = 0.0;
    if (consumption != null)
    {
        foreach (var frame in consumption)
           total += frame.Amount;
    }

    Assert.Equal(160 * 3, total);
}

Pokud je potřeba získat hodnoty jen v rámci určitého okna (například pro každý den spotřebu mezi 7:00am a 6:00pm, tak lze použít funkci GetConsumptionOfEntityWithWindow. Tímto lze například získat spotřebu v rámci denního a nočního tarifu. Tento usecase je ukázán v tomto testu.

int windowHourStart = 8;
int windowHourEnd = 20;

// day consumption only
if (devicegroup != null)
{
    var res = eGrid.GetConsumptionOfEntityWithWindow(devicegroup.Id,
                                                     BlockTimeframe.Day,
                                                     starttime,
                                                     endtime2,
                                                     DateTime.MinValue.AddHours(windowHourStart),
                                                     DateTime.MinValue.AddHours(windowHourEnd));
    var total = 0.0;
    foreach (var b in res)
        total += b.Amount;
    Assert.Equal(1 * 12 * 7 + 50, total);
}

// night consumption only
if (devicegroup != null)
{
    var res = eGrid.GetConsumptionOfEntityWithWindow(devicegroup.Id,
                                                     BlockTimeframe.Day,
                                                     starttime,
                                                     endtime2,
                                                     DateTime.MinValue.AddHours(windowHourStart),
                                                     DateTime.MinValue.AddHours(windowHourEnd),
                                                     true);
    var total = 0.0;
    foreach (var b in res)
        total += b.Amount;
    Assert.Equal(1 * 12 * 7 + 20 + 20, total);
}

Kombinací, jak tyto (a různé další) funkce knihovny použít dohromady je mnoho. Knihovna je dost flexibilní. Více příkladů a funkcí bude popsáno v dalších článcích.

Clone this wiki locally