Skip to content

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

fyziktom edited this page Feb 12, 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 trochu více zaměřená na výpočty distribuce energií, nicméně základní model jako takový je obecný. Knihovnu lze použít například i pro plánovnání cashflow, časů projektu či jeho nákladů, distribuci vzduchu, vody či 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

Diaram je zjednodušený. Neobsahuje všechny třídy a také třídy PVE Simulátoru a Battery storage budou vysvětleny v samostatném článku.

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

IEntity je interface a nemůžu vytvořit jeho instanci. Pro to slouží buď BaseEntity (implementace abstraktní třídy CommonEntity) a nebo ideálně specifičnější "Source" nebo "Consumer". To jsou nádstavbové interfacy pro vytváření různých druhů zdrojů nebo spotřebičů ve stromě. Pro vytvoření Source nebo Consumer existují konkrétní Factory. 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 vidět také 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.

Už jedna entita může tvořit celou síť, nicméně je vhodné si udělat strukturu. Pokud již je vše ready, 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 pak vypadá zobrazení všech bloků v entitě+subentitách takto:

bloky sítě entit

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

Jakmile jsou bloky v entitě, můžu se zeptat entity 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ž mám v entitě, jeden blok o délce x dní, lze získat jako výsledek zpět 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 potřebuji získat ještě hodnoty jen v rámci určitého okna (například pro každý den spotřebu jen 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 dosti flexibilní. Více příkladů a funkcí bude popsaných v dalších článcích.

Clone this wiki locally