diff --git a/build.gradle b/build.gradle index ba28ebd6c4..36954aa09a 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ ext { scalaVersion = '2.13' scalaBinaryVersion = '2.13.14' - pekkoVersion = '1.0.3' + pekkoVersion = '1.0.2' jtsVersion = '1.19.0' confluentKafkaVersion = '7.4.0' tscfgVersion = '1.0.0' @@ -67,6 +67,11 @@ repositories { } dependencies { + constraints { + implementation( 'com.fasterxml.jackson.core:jackson-databind:2.16.0+' ){ + because "[CVE-2020-25649] CWE-611: Improper Restriction of XML External Entity Reference ('XXE')" + } + } // ie³ internal repository implementation('com.github.ie3-institute:PowerSystemUtils:2.2.1') { @@ -95,6 +100,12 @@ dependencies { exclude group: 'edu.ie3' } + implementation('com.github.ie3-institute:simosaik') { + exclude group: 'org.apache.logging.log4j' + exclude group: 'org.slf4j' + exclude group: 'edu.ie3' + } + /* logging */ implementation "com.typesafe.scala-logging:scala-logging_${scalaVersion}:3.9.5" // pekko scala logging implementation "ch.qos.logback:logback-classic:1.5.6" diff --git a/docs/uml/main/ExtPrimaryResultSimulationClasses.puml b/docs/uml/main/ExtPrimaryResultSimulationClasses.puml new file mode 100644 index 0000000000..e13c3e6be2 --- /dev/null +++ b/docs/uml/main/ExtPrimaryResultSimulationClasses.puml @@ -0,0 +1,166 @@ +@startuml +'https://plantuml.com/class-diagram +skinparam linetype ortho + +package simple-ext-simulation { + class ExtLink + class SimpleExtSimulation { + - ExtPrimaryDataSimulation extPrimaryDataSimulation + - ExtResultDataSimulation extResultDataSimulation + } + class SimplePrimaryDataFactory + + class SimpleResultDataFactory + + SimplePrimaryDataFactory --> SimpleExtSimulation + SimpleResultDataFactory --> SimpleExtSimulation +} + +package simona-api { + + interface ExtData + + class ExtPrimaryData { + - ActorRef dataService + - ActorRef extSimAdapter + - PrimaryDataFactory factory + - List primaryDataAssets + --- + + void providePrimaryData(Long tick, Map primaryData) + + void sendExtMsg(PrimaryDataMessageFromExt msg) + } + ExtPrimaryData --|> ExtData + + class ExtResultData { + - ActorRef dataService + - ActorRef dataServiceActivation + - ActorRef extSimAdapter + - ResultDataFactory factory + - List resultDataAssets + --- + + List requestResults(long tick) + + Map requestResultObjects(long tick) + ~ Map convertResultsList(List results) + } + ExtResultData --|> ExtData + + ' MIDDLE PART + class ExtEvData + ExtEvData --|> ExtData + + interface ExtDataSimulation + + class ExtPrimaryDataSimulation { + - List primaryDataAssets + - PrimaryDataFactory primaryDataFactory + - ExtPrimaryData extPrimaryData + --- + + void setExtPrimaryData(ExtPrimaryData extPrimaryData) + } + ExtPrimaryDataSimulation --|> ExtDataSimulation + + class ExtResultDataSimulation { + - List resultDataAssets + - ResultDataFactory resultDataFactory + - ExtResultData extResultData + --- + + void setExtResultData(ExtResultData extResultData) + } + ExtResultDataSimulation --|> ExtDataSimulation + + interface PrimaryDataFactory { + Value convert(Object entity) + } + PrimaryDataFactory --> ExtPrimaryDataSimulation + + interface ResultDataFactory { + Object convert(ResultEntity entity) + } + ResultDataFactory --> ExtResultDataSimulation + + SimplePrimaryDataFactory --|> PrimaryDataFactory + SimpleResultDataFactory --|> ResultDataFactory + + class ExtSimAdapterData { + ~ LinkedBlockingQueue receiveTriggerQueue + - Map extSimAdapters + + void queueExtMsg(ExtTrigger trigger) + + void send(ExtTriggerResponse msg) + } + + + abstract class ExtSimulation { + - ExtSimAdapterData data + + void setup(ExtSimAdapterData data, List adapters) + + void run() + # Optional doActivity(long tick, int phase) + # {abstract} Optional initialize() + # {abstract} Optional doPreActivity(long tick) + # {abstract} Optional doPostActivity(long tick) + } + + SimpleExtSimulation --|> ExtSimulation + + interface ExtEvSimulation { + + void setExtEvData(ExtEvData evData) + } + + ExtEvSimulation --|> ExtDataSimulation + + interface DataMessageFromExt + interface PrimaryDataMessageFromExt + interface ResultDataMessageFromExt + interface EvDataMessageFromExt + PrimaryDataMessageFromExt --|> DataMessageFromExt + ResultDataMessageFromExt --|> DataMessageFromExt + EvDataMessageFromExt --|> DataMessageFromExt + + class ProvidePrimaryData { + - long tick + - Map primaryData + } + ProvidePrimaryData --|> PrimaryDataMessageFromExt + + class RequestResultEntities { + - long tick + } + RequestResultEntities --|> ResultDataMessageFromExt + + + interface DataResponseMessageToExt + interface ResultDataResponseMessageToExt + interface EvDataResponseMessageToExt + + ResultDataResponseMessageToExt --|> DataResponseMessageToExt + EvDataResponseMessageToExt --|> DataResponseMessageToExt + class ProvideResultEntities { + + List results + } + ProvideResultEntities --|> ResultDataResponseMessageToExt + + ExtSimAdapterData --> ExtSimulation + + interface ExtLinkInterface { + ExtSimulation getExtSimulation() + List getExtDataSimulation() + } + ExtLink --|> ExtLinkInterface + + class ScheduleDataServiceMessage +} + +package simona { + class ExtPrimaryDataService + + ExtPrimaryData --> ExtPrimaryDataService + + class ExtResultDataProvider + + ExtResultData --> ExtResultDataProvider + + class ExtSimAdapter + + ExtSimAdapterData --> ExtSimAdapter +} + +@enduml \ No newline at end of file diff --git a/docs/uml/main/ExtSimulationAndAPIClasses.puml b/docs/uml/main/ExtSimulationAndAPIClasses.puml new file mode 100644 index 0000000000..98942a8d32 --- /dev/null +++ b/docs/uml/main/ExtSimulationAndAPIClasses.puml @@ -0,0 +1,133 @@ +@startuml +'https://plantuml.com/class-diagram +skinparam linetype ortho + +package simona-api { + + interface DataMessageFromExt + interface PrimaryDataMessageFromExt + interface EvDataMessageFromExt + + PrimaryDataMessageFromExt --> DataMessageFromExt + EvDataMessageFromExt --> DataMessageFromExt + ResultDataMessageFromExt --> DataMessageFromExt + + class ProvidePrimaryData { + + long tick + + Map primaryData + } + + ProvidePrimaryData --> PrimaryDataMessageFromExt + + class ProvideArrivingEvs { + + Map> arrivals) + } + + class RequestCurrentPrices + class RequestDepartingEvs + class RequestEvcsFreeLots + + ProvideArrivingEvs --> EvDataMessageFromExt + RequestCurrentPrices --> EvDataMessageFromExt + RequestDepartingEvs --> EvDataMessageFromExt + RequestEvcsFreeLots --> EvDataMessageFromExt + + class RequestResultEntities { + + Long tick + } + + RequestResultEntities --> ResultDataMessageFromExt + + interface DataResponseMessageToExt + interface ResultDataResponseMessageToExt + interface EvDataResponseMessageToExt + + ResultDataResponseMessageToExt --> DataResponseMessageToExt + EvDataResponseMessageToExt --> DataResponseMessageToExt + + class ProvideResultEntities { + + List results + } + + ProvideResultEntities --> ResultDataResponseMessageToExt + + class ProvideCurrentPrices + + class ProvideDepartingEvs + + class ProvideEvcsFreeLots + ProvideCurrentPrices --> EvDataResponseMessageToExt + ProvideDepartingEvs --> EvDataResponseMessageToExt + ProvideEvcsFreeLots --> EvDataResponseMessageToExt + + interface ExtData + + class ExtEvData + class ExtPrimaryData { + PrimaryDataFactory primaryDataFactory + } + class ExtResultData + + ExtEvData --> ExtData + ExtPrimaryData --> ExtData + ExtResultData --> ExtData + + + + interface PrimaryDataFactory { + + Value convert(Object entity) + } + PrimaryDataFactory -- ExtPrimaryData + + interface ResultDataFactory { + + Object convert(ResultEntity entity) + } + ResultDataFactory -- ExtResultData + + interface ExtDataSimulation + interface ExtResultDataSimulation + interface ExtPrimaryDataSimulation + interface ExtEvDataSimulation + + ExtPrimaryDataSimulation --> ExtDataSimulation + ExtResultDataSimulation --> ExtDataSimulation + ExtEvDataSimulation --> ExtDataSimulation + + abstract class ExtSimulation { + - ExtSimAdapterData data + + # Optional initialize() + # Optional doActivity(long tick) + } +} + +package simona { + class SimonaSim + + class SimScheduler + + class SimonaStandaloneSetup + + class ExtSimLoader + + class ExtSimAdapter + + class ExtResultDataProvider + ExtResultDataProvider -- ExtResultData + + class ExtPrimaryDataService + ExtPrimaryDataService -- ExtPrimaryData + + SimScheduler -- SimonaSim + SimonaSim *- SimonaStandaloneSetup + SimonaStandaloneSetup *- ExtSimLoader + + ExtSimAdapter -- SimScheduler + ExtPrimaryDataService -- SimScheduler + + SimonaService <|- ExtPrimaryDataService + + ExtSimAdapterData <--- ExtSimAdapter +} + +@enduml \ No newline at end of file diff --git a/docs/uml/protocol/CouplingTemplate.puml b/docs/uml/protocol/CouplingTemplate.puml new file mode 100644 index 0000000000..29878a966d --- /dev/null +++ b/docs/uml/protocol/CouplingTemplate.puml @@ -0,0 +1,15 @@ +@startuml + +== Phase 1 == +Mosaik -> SIMOSAIK: ! Activation(tick) +SIMOSAIK -> SIMONA: StateData(currentTick = Some(tick)) + +activate SIMOSAIK + +SIMOSAIK -> SIMOSAIK: DoSomething() + +deactivate SIMOSAIK + +SIMOSAIK -> Mosaik: ! Completion(tick) + +@enduml \ No newline at end of file diff --git a/docs/uml/protocol/ExtDataService.puml b/docs/uml/protocol/ExtDataService.puml new file mode 100644 index 0000000000..283eed4175 --- /dev/null +++ b/docs/uml/protocol/ExtDataService.puml @@ -0,0 +1,102 @@ +@startuml + +!theme plain + +==Init== + + + + +SimScheduler -> ExtSimAdapter: ! ActivityStartTrigger(-1L) +activate ExtSimAdapter + +ExtSimAdapter -> ExtSimulation: queue(ActivityStartTrigger(-1L)) +deactivate ExtSimAdapter +activate ExtSimulation +... Initialize external mobility simulation ... + +ExtSimulation -> ExtSimAdapter: ! CompletionMessage(newTriggers) +deactivate ExtSimulation +activate ExtSimAdapter + +ExtSimAdapter -> SimScheduler: ! CompletionMessage(newTriggers) +deactivate ExtSimAdapter + +==Sim== +SimScheduler -> ExtSimAdapter: ! ActivityStartTrigger(tick) +activate ExtSimAdapter + +ExtSimAdapter -> ExtSimulation: queue(ActivityStartTrigger(tick)) +deactivate ExtSimAdapter + +activate ExtSimulation +ExtSimulation -> ExtEvDataService: ! RequestEvcsFreeLots +ExtSimulation -> ExtSimAdapter: ! ScheduleDataServiceMessage(\n\tdataServiceRef\n) + +activate ExtSimAdapter +ExtSimAdapter -> SimScheduler: ! ScheduleTriggerMessage(\n\t_, dataServiceRef) +deactivate ExtSimAdapter + +activate SimScheduler +SimScheduler -> ExtEvDataService: ! ActivityStartTrigger(tick) +deactivate SimScheduler + +activate ExtEvDataService +ExtEvDataService -> EvcsAgent1: ! EvFreeLotsRequest(tick) +activate EvcsAgent1 +ExtEvDataService -> EvcsAgent2: ! EvFreeLotsRequest(tick) +activate EvcsAgent2 + +ExtEvDataService -> SimScheduler: ! CompletionMessage(None) + +EvcsAgent2 -> ExtEvDataService: ! FreeLotsResponse(_, _) +deactivate EvcsAgent2 +EvcsAgent1 -> ExtEvDataService: ! FreeLotsResponse(_, _) +deactivate EvcsAgent1 +ExtEvDataService -> ExtSimulation: queue(ProvideEvcsFreeLots(_)) +deactivate ExtEvDataService + +... Running external mobility simulation,\n determining EV positions ... +ExtSimulation -> ExtEvDataService: ! EvMovementsMessage(_) +ExtSimulation -> ExtSimAdapter: ! ScheduleDataServiceMessage(\n\tdataServiceRef\n) + +activate ExtSimAdapter +ExtSimAdapter -> SimScheduler: ! ScheduleTriggerMessage(\n\t_, dataServiceRef) +deactivate ExtSimAdapter + +activate SimScheduler +SimScheduler -> ExtEvDataService: ! ActivityStartTrigger(tick) +deactivate SimScheduler + +activate ExtEvDataService +ExtEvDataService -> EvcsAgent1: ! ProvideEvDataMessage(\n\ttick, _) +ExtEvDataService -> EvcsAgent2: ! ProvideEvDataMessage(\n\ttick, _) +ExtEvDataService -> SimScheduler: ! CompletionMessage(evcsTriggers) +deactivate ExtEvDataService + +activate SimScheduler +SimScheduler -> EvcsAgent1: ! ActivityStartTrigger(tick) +activate EvcsAgent1 +SimScheduler -> EvcsAgent2: ! ActivityStartTrigger(tick) +deactivate SimScheduler + +activate EvcsAgent2 +EvcsAgent1 -> SimScheduler: ! CompletionMessage(None) +deactivate EvcsAgent1 + +EvcsAgent2 -> ExtEvDataService: ! DepartedEvsResponse(_, _) +activate ExtEvDataService +EvcsAgent2 -> SimScheduler: ! CompletionMessage(None) +deactivate EvcsAgent2 + +ExtEvDataService -> ExtSimulation: queue(AllDepartedEvsResponse(_)) +deactivate ExtEvDataService + +ExtSimulation -> ExtSimAdapter: ! CompletionMessage(newTriggers) +deactivate ExtSimulation + +activate ExtSimAdapter +ExtSimAdapter -> SimScheduler: ! CompletionMessage(newTriggers) +deactivate ExtSimAdapter + +@enduml \ No newline at end of file diff --git a/docs/uml/protocol/ExtSimulationForPrimaryDataAndResultData.puml b/docs/uml/protocol/ExtSimulationForPrimaryDataAndResultData.puml new file mode 100644 index 0000000000..283eed4175 --- /dev/null +++ b/docs/uml/protocol/ExtSimulationForPrimaryDataAndResultData.puml @@ -0,0 +1,102 @@ +@startuml + +!theme plain + +==Init== + + + + +SimScheduler -> ExtSimAdapter: ! ActivityStartTrigger(-1L) +activate ExtSimAdapter + +ExtSimAdapter -> ExtSimulation: queue(ActivityStartTrigger(-1L)) +deactivate ExtSimAdapter +activate ExtSimulation +... Initialize external mobility simulation ... + +ExtSimulation -> ExtSimAdapter: ! CompletionMessage(newTriggers) +deactivate ExtSimulation +activate ExtSimAdapter + +ExtSimAdapter -> SimScheduler: ! CompletionMessage(newTriggers) +deactivate ExtSimAdapter + +==Sim== +SimScheduler -> ExtSimAdapter: ! ActivityStartTrigger(tick) +activate ExtSimAdapter + +ExtSimAdapter -> ExtSimulation: queue(ActivityStartTrigger(tick)) +deactivate ExtSimAdapter + +activate ExtSimulation +ExtSimulation -> ExtEvDataService: ! RequestEvcsFreeLots +ExtSimulation -> ExtSimAdapter: ! ScheduleDataServiceMessage(\n\tdataServiceRef\n) + +activate ExtSimAdapter +ExtSimAdapter -> SimScheduler: ! ScheduleTriggerMessage(\n\t_, dataServiceRef) +deactivate ExtSimAdapter + +activate SimScheduler +SimScheduler -> ExtEvDataService: ! ActivityStartTrigger(tick) +deactivate SimScheduler + +activate ExtEvDataService +ExtEvDataService -> EvcsAgent1: ! EvFreeLotsRequest(tick) +activate EvcsAgent1 +ExtEvDataService -> EvcsAgent2: ! EvFreeLotsRequest(tick) +activate EvcsAgent2 + +ExtEvDataService -> SimScheduler: ! CompletionMessage(None) + +EvcsAgent2 -> ExtEvDataService: ! FreeLotsResponse(_, _) +deactivate EvcsAgent2 +EvcsAgent1 -> ExtEvDataService: ! FreeLotsResponse(_, _) +deactivate EvcsAgent1 +ExtEvDataService -> ExtSimulation: queue(ProvideEvcsFreeLots(_)) +deactivate ExtEvDataService + +... Running external mobility simulation,\n determining EV positions ... +ExtSimulation -> ExtEvDataService: ! EvMovementsMessage(_) +ExtSimulation -> ExtSimAdapter: ! ScheduleDataServiceMessage(\n\tdataServiceRef\n) + +activate ExtSimAdapter +ExtSimAdapter -> SimScheduler: ! ScheduleTriggerMessage(\n\t_, dataServiceRef) +deactivate ExtSimAdapter + +activate SimScheduler +SimScheduler -> ExtEvDataService: ! ActivityStartTrigger(tick) +deactivate SimScheduler + +activate ExtEvDataService +ExtEvDataService -> EvcsAgent1: ! ProvideEvDataMessage(\n\ttick, _) +ExtEvDataService -> EvcsAgent2: ! ProvideEvDataMessage(\n\ttick, _) +ExtEvDataService -> SimScheduler: ! CompletionMessage(evcsTriggers) +deactivate ExtEvDataService + +activate SimScheduler +SimScheduler -> EvcsAgent1: ! ActivityStartTrigger(tick) +activate EvcsAgent1 +SimScheduler -> EvcsAgent2: ! ActivityStartTrigger(tick) +deactivate SimScheduler + +activate EvcsAgent2 +EvcsAgent1 -> SimScheduler: ! CompletionMessage(None) +deactivate EvcsAgent1 + +EvcsAgent2 -> ExtEvDataService: ! DepartedEvsResponse(_, _) +activate ExtEvDataService +EvcsAgent2 -> SimScheduler: ! CompletionMessage(None) +deactivate EvcsAgent2 + +ExtEvDataService -> ExtSimulation: queue(AllDepartedEvsResponse(_)) +deactivate ExtEvDataService + +ExtSimulation -> ExtSimAdapter: ! CompletionMessage(newTriggers) +deactivate ExtSimulation + +activate ExtSimAdapter +ExtSimAdapter -> SimScheduler: ! CompletionMessage(newTriggers) +deactivate ExtSimAdapter + +@enduml \ No newline at end of file diff --git a/docs/uml/protocol/ExtSimulationSequence.puml b/docs/uml/protocol/ExtSimulationSequence.puml new file mode 100644 index 0000000000..c0df9bd9d0 --- /dev/null +++ b/docs/uml/protocol/ExtSimulationSequence.puml @@ -0,0 +1,28 @@ +@startuml + +== Phase 1 == +ExtScheduler -> ExtSimAdapter: ! Activation(tick) +ExtSimAdapter -> ExtSimAdapter: StateData(currentTick = Some(tick)) +ExtSimAdapter -> ExtSimAdapterData: queueExtMessage(ActivationMessage(tick)) + +ExtSimulation -> ExtPrimaryDataService: ProvidePrimaryData +ExtSimulation -> ExtSimAdapter: ! ScheduleDataServiceMessage(dataService) +ExtSimulation -> ExtSimAdapter: ! CompletionMessage(nextTriggers) +ExtSimAdapter -> ExtScheduler: ! Completion +ExtSimAdapter -> ExtPrimaryDataService: ! ScheduleServiceActivation(tick, key) +ExtPrimaryDataService -> ExtScheduler: ! ScheduleActivation(_, tick, _) +ExtScheduler -> ExtPrimaryDataService: ! Activation(tick) + +ExtPrimaryDataService -> ParticipantAgent1: ! ProvisionMessage +ExtPrimaryDataService -> ParticipantAgent2: ! ProvisionMessage +ExtPrimaryDataService -> ExtScheduler: ! Completion(_, maybeNextTriggers) +ExtScheduler -> SimScheduler: ! Completion + +== Phase 2 == + +SimScheduler -> ParticipantAgent1: ! Activation(tick) +SimScheduler -> ParticipantAgent2: ! Activation(tick) + +activate ParticipantAgent1 + +@enduml \ No newline at end of file diff --git a/input/samples/simopsimtestgrid_reduced/fullGrid/em_input.csv b/input/samples/simopsimtestgrid_reduced/fullGrid/em_input.csv new file mode 100644 index 0000000000..b6a794fe65 --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced/fullGrid/em_input.csv @@ -0,0 +1,4 @@ +uuid;control_strategy;parent_em;id;operates_from;operates_until;operator +c3a7e9f5-b492-4c85-af2d-1e93f6a25443;self_optimization;;EM_HH_Bus_25;;; +f9dc7ce6-658c-4101-a12f-d58bb889286b;self_optimization;;EM_HH_Bus_81;;; +957938b7-0476-4fab-a1b3-6ce8615857b3;self_optimization;;EM_HH_Bus_110;;; diff --git a/input/samples/simopsimtestgrid_reduced/fullGrid/ext_entity_mapping.csv b/input/samples/simopsimtestgrid_reduced/fullGrid/ext_entity_mapping.csv new file mode 100644 index 0000000000..58ec9dcd0f --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced/fullGrid/ext_entity_mapping.csv @@ -0,0 +1,7 @@ +uuid,id,columnScheme,dataType +f9dc7ce6-658c-4101-a12f-d58bb889286b,EM_HH_Bus_81,p,result_participant +957938b7-0476-4fab-a1b3-6ce8615857b3,EM_HH_Bus_110,p,result_participant +c3a7e9f5-b492-4c85-af2d-1e93f6a25443,EM_HH_Bus_25,p,result_participant +f9dc7ce6-658c-4101-a12f-d58bb889286b,EM_HH_Bus_81/Schedule,p,input +957938b7-0476-4fab-a1b3-6ce8615857b3,EM_HH_Bus_110/Schedule,p,input +c3a7e9f5-b492-4c85-af2d-1e93f6a25443,EM_HH_Bus_25/Schedule,p,input \ No newline at end of file diff --git a/input/samples/simopsimtestgrid_reduced/fullGrid/line_input.csv b/input/samples/simopsimtestgrid_reduced/fullGrid/line_input.csv new file mode 100644 index 0000000000..f4ff92fbba --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced/fullGrid/line_input.csv @@ -0,0 +1,110 @@ +uuid;geo_position;id;length;node_a;node_b;olm_characteristic;operates_from;operates_until;operator;parallel_devices;type +bdbbb247-57b7-473b-9411-53fcf35032db;"{""type"":""LineString"",""coordinates"":[[11.8213,53.426],[11.8213,53.4257]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 27;0.0161277;093160c4-6482-4c58-b952-217c615e3ada;9cdb3115-cc00-4d61-bc33-442e8f30fb63;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +c48eeb2c-6858-4f96-9a90-20641cc0903d;"{""type"":""LineString"",""coordinates"":[[11.8214,53.4229],[11.8213,53.4225]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 35;0.0150703;002a4495-96e4-49c9-abbe-8fccb3e9c83e;b909fb45-b6ee-427f-afd7-e8a0ec7274c6;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +97e498ae-a4f7-4485-a703-b8c00d0a5e8a;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4221],[11.8201,53.4225]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 8;0.0228449;b565ae3b-68f9-4bca-816d-9b0fc1c6b13f;a7725293-05fc-447f-bc12-38b689b0a956;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f907f152-7bfe-4a17-a63f-adda500f6f0e;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4241],[11.8184,53.4293]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 107;0.04;4749ab2b-4d96-4100-8081-73e77c797d6b;ea4a6507-e504-4542-be5f-1019719b2257;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +6bf14400-8f6c-41ef-b6a4-9e861a3ad08f;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4241],[11.822,53.4294]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 3;0.030304;4749ab2b-4d96-4100-8081-73e77c797d6b;c5b6bfaf-1621-40a7-9c53-02cfb59c04d9;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +18b92b71-320d-4294-a47e-6715f1594755;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4243],[11.8196,53.4247]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 102;0.0251089;f4da61e4-7600-4cd1-95b6-c70b56c049fc;e7908208-77b4-4059-806e-4857262992fc;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +4128307f-3e00-4da9-b629-b696b72165a4;"{""type"":""LineString"",""coordinates"":[[11.815,53.4289],[11.815,53.4293]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 28;0.0377768;8e809cf6-7e05-437c-89a6-f6ca135a403b;35748e60-3be8-4930-8a61-209fd5df1bec;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +92876b53-6bbc-48ff-ba5f-5f5c08313e4d;"{""type"":""LineString"",""coordinates"":[[11.815,53.4277],[11.815,53.4272]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 111;0.031;3e6be3ac-2b51-4080-b815-391313612fc7;78815cf6-70db-432c-96e6-87fe8cf67eee;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +4b557d0c-9992-48b1-b45e-26cccc01db03;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4235],[11.8191,53.4231]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 90;0.00167204;f2724954-34d3-4ddf-b6b0-7a1531639990;2efac9b1-fb0d-4e08-bfac-501798826deb;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +0652d3e0-8c7c-4be2-9a41-00534aa9774b;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4212],[11.8191,53.4209]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 94;0.00182131;02e63e81-2e62-4ef6-8fdb-0b0905a437b6;fd4bebb8-40ca-4eed-92c0-cdd10b86ac20;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +782d8c4c-accb-424b-91ae-9af1b5d4b1af;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4225],[11.8201,53.4229]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 79;0.0338129;a7725293-05fc-447f-bc12-38b689b0a956;83da8d60-405a-45f7-9bb9-9d35607b7927;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +b7cac7a5-f528-45bd-8ced-a16234979e13;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4239],[11.8191,53.4235]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 89;0.0111411;b5c1e826-63fd-4b0c-bec0-0c758389ef58;f2724954-34d3-4ddf-b6b0-7a1531639990;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7ac1a715-e141-429a-8cfe-ff2badd41074;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4257],[11.8174,53.4262]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 65;0.019;8726dc29-621e-4455-a541-cd88d7da457f;814f784b-687f-4dd5-8a91-c7772c916d46;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +77ae4f1e-9ecb-4dda-a5f2-ce7ae3f9bbec;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4264],[11.8213,53.426]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 23;0.00488535;18b4157b-0e47-4c5a-adb8-ccae47372336;093160c4-6482-4c58-b952-217c615e3ada;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +6aaa54d9-d7b7-4adc-a85a-335cdf1393d6;"{""type"":""LineString"",""coordinates"":[[11.8162,53.4284],[11.8169,53.4289]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 40;0.036;6b2881ce-3965-4f5e-98a3-74eb47b0a7ca;a882e666-82d1-4ba6-87df-fc702fe06187;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +c85c107e-82c0-4002-acfa-d7000512a2ad;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4274],[11.8213,53.4271]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 20;0.0182765;2b3d7fb8-0583-4d47-97b1-3b5f232fd462;7b81b518-00e0-4ff1-b4cf-876903958d7a;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +2ef5f888-4341-4eee-b505-ae07a9a60c8d;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4236],[11.8201,53.4239]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 55;0.0259846;f713593a-3fd3-410a-ac08-74202d4f5798;80962bd3-a10f-4ed2-ba6a-3e802189939c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +139ea4f9-9b7f-4825-8919-537a94ff4794;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4277],[11.8174,53.4281]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 59;0.00160952;7f692039-eef6-45f6-9e30-b5983f6750a5;3f6c26dd-842b-4dee-b71f-4aa32e2654ff;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +68853808-8b09-4ff2-9c92-88ed1d78c639;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4236],[11.8213,53.4232]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 33;0.0217875;3464496c-7dd4-41e9-ae0a-99ade0b51572;a966644c-37d5-4400-9fa0-725fd88586a8;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +91bec60c-2951-420c-a35e-2633119ee450;"{""type"":""LineString"",""coordinates"":[[11.8162,53.4277],[11.8162,53.4281]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 30;0.00820054;2d33314e-31db-4ad4-a898-2be5d56a896d;555cd075-0fe4-4a65-b027-f45cffa960d9;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +35ba0827-e27e-496e-b735-c778f3b03019;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4241],[11.8213,53.4293]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 18;0.0139169;4749ab2b-4d96-4100-8081-73e77c797d6b;844c0b9c-058a-4228-a8c4-bf2defff6958;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +60efd159-72d6-4546-b245-8b8fc120a9f8;"{""type"":""LineString"",""coordinates"":[[11.817,53.4293],[11.8166,53.4241]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 26;0.098;85751c9b-3e5e-468a-9dc7-43775b0d4a6f;4749ab2b-4d96-4100-8081-73e77c797d6b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +212b62aa-73c2-47af-95ec-00cad8d4a4f4;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4222],[11.8214,53.4218]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 38;0.00992653;589bf32a-b361-4536-ae96-6d56d184eedb;3b86661a-187d-4aa6-bf37-2014789afc08;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7e61def1-8414-40b3-8775-fad9124f4369;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4282],[11.8213,53.4277]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 16;0.0164234;09285b78-9c18-4af7-9c7a-942cc868016f;3a557b4e-06b8-4f29-929f-81d95c42c897;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f9b4c7dc-c199-4691-8c6d-1faf438cf336;"{""type"":""LineString"",""coordinates"":[[11.8221,53.429],[11.8221,53.4286]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 5;0.0143698;9644f198-e801-4545-87ee-a24e2a8039bd;6ee7ea93-ea9c-40cb-b79a-1c5f287c97a5;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +eebc456e-d11b-4b19-9100-cc1d8e91f926;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4245],[11.8166,53.4249]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 71;0.00648856;7efabb8d-ba17-4487-96d9-5744b1fedf8a;7c35a794-f569-4a9c-acb0-d03647610086;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +8f4c4009-e1ed-4985-8095-729aa5dc8cdd;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4192],[11.8198,53.4195]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 85;0.00737032;594d101c-3a05-45e3-a061-9189f3e848b7;af2b07ce-1a96-4b50-9e21-badf29eed519;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +20db47c8-d154-4ab2-ad65-caa4a37466d2;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4257],[11.8174,53.4262]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 68;0.037;5f153bf6-4f25-41f1-8545-18fe6323bc49;814f784b-687f-4dd5-8a91-c7772c916d46;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7d838003-cd6e-42fd-b75a-eaa354c3993b;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4216],[11.8191,53.4212]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 93;0.0043578;8f53645e-1f28-4eb1-807f-eb2a473f9d4c;02e63e81-2e62-4ef6-8fdb-0b0905a437b6;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +a92013e1-78b7-4447-a505-f25fffbf56f2;"{""type"":""LineString"",""coordinates"":[[11.8174,53.4262],[11.8175,53.4265]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 48;0.0118531;814f784b-687f-4dd5-8a91-c7772c916d46;94fe96b1-f36a-4edd-a107-4ff0376f1066;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +690f8f61-5cc7-448e-8971-a516f784bf11;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4293],[11.8166,53.4241]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 106;0.0131451;20ad9754-e966-4ad1-9541-f968c207f3df;4749ab2b-4d96-4100-8081-73e77c797d6b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +6a00d582-32b1-4581-bdd1-a638ca279597;"{""type"":""LineString"",""coordinates"":[[11.815,53.4272],[11.815,53.4269]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 112;0.028;78815cf6-70db-432c-96e6-87fe8cf67eee;ab8c8f6c-e7a2-4b81-a0d7-5f13789267a2;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +1d5877c1-31cd-4ee8-b0dd-667fa4fffb8a;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4277],[11.8213,53.4274]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 17;0.00286133;3a557b4e-06b8-4f29-929f-81d95c42c897;2b3d7fb8-0583-4d47-97b1-3b5f232fd462;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +a15cd6a4-4b22-434f-be9b-ad2abe6e538c;"{""type"":""LineString"",""coordinates"":[[11.815,53.4289],[11.815,53.4285]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 108;0.033;8e809cf6-7e05-437c-89a6-f6ca135a403b;88cf719a-92df-4dfd-9a83-f84330e28fe0;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +2bd81511-4f19-4374-8ac5-96c2b19eda64;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4223],[11.8191,53.422]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 52;0.00980013;c7e48384-5699-4a38-a887-7e15a9145202;c6dac3ab-f44f-4b87-800c-0f4da64673f1;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +beee40ad-aca3-490f-87d5-a6dfc4bb76e3;"{""type"":""LineString"",""coordinates"":[[11.815,53.4293],[11.8166,53.4241]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 39;0.09;35748e60-3be8-4930-8a61-209fd5df1bec;4749ab2b-4d96-4100-8081-73e77c797d6b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +96b06f87-7905-4d12-99d8-1ed330050659;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4203],[11.8197,53.4207]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 12;0.00473835;5596da2f-ca32-4ad3-81da-1ffa17cd3d7b;839ff0f4-93db-42ec-a928-bbc448b6cf5c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e66890ef-ec02-407f-a5bb-ce32128e7490;"{""type"":""LineString"",""coordinates"":[[11.8162,53.4281],[11.8162,53.4284]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 41;0.00828244;555cd075-0fe4-4a65-b027-f45cffa960d9;6b2881ce-3965-4f5e-98a3-74eb47b0a7ca;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +015b0337-98bd-40d4-97d3-13a0d1da88ee;"{""type"":""LineString"",""coordinates"":[[11.8213,53.425],[11.8214,53.4246]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 84;0.0489789;58b551b6-83bd-4f1c-8d9c-8c9a7f638c0b;a9288e77-2919-4db6-89eb-9737bd07f111;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f9e6b2f1-f8fb-4763-a1d0-36d06170fea0;"{""type"":""LineString"",""coordinates"":[[11.8213,53.429],[11.8213,53.4286]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 98;0.0144283;16091b6d-f1ea-4a07-9ad4-30d595aba68d;1403edf9-e47c-4705-8563-83bcd639482e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f270d6b5-7c94-4397-8ab0-7c39c888d726;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4265],[11.8175,53.427]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 58;0.0036937;94fe96b1-f36a-4edd-a107-4ff0376f1066;80b8d1f8-7e83-421d-a95a-c193fc35f4f7;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +af8c65aa-cfd6-434a-8512-2d80106a2f2c;"{""type"":""LineString"",""coordinates"":[[11.8195,53.426],[11.8195,53.4264]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 31;0.00626899;9f1baf4e-12e1-41d1-8efc-81cfc78f1957;b8e95bf0-3ba8-4d53-a0bf-a3720fb785fb;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +fe28e831-6405-4dfe-987b-d688367694f1;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4247],[11.8195,53.425]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 104;0.00221503;e7908208-77b4-4059-806e-4857262992fc;29516ae3-6676-4797-99c1-1f0a32b989d8;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +eac56d69-5500-4261-9690-adb16c867485;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4231],[11.8191,53.4227]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 92;0.0149219;2efac9b1-fb0d-4e08-bfac-501798826deb;15a86f7d-fb73-49a4-af6a-25b14122378d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +183f3976-48ca-42b2-9af9-7998436fac5b;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4289],[11.8196,53.4293]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 105;0.00721947;47246a84-ad0e-4d04-9d98-1c9cd5d363c1;20ad9754-e966-4ad1-9541-f968c207f3df;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7feef458-03f3-4d23-b3a2-e6f1035398c4;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4243],[11.8213,53.4239]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 29;0.0204277;3fcb94e3-7781-4d83-9030-d9853822e78e;d0bfabdb-0e83-423b-a20a-ab9197c4284e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +592cd979-16c9-43d8-a311-8ac938aa5d03;"{""type"":""LineString"",""coordinates"":[[11.8174,53.4262],[11.8182,53.4257]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 47;0.0181601;814f784b-687f-4dd5-8a91-c7772c916d46;c86d6361-4159-4787-b5f4-e41dcaa95195;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +684146e5-3b58-43b4-9589-45325ab1c0bc;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4257],[11.8213,53.4253]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 24;0.0102233;9cdb3115-cc00-4d61-bc33-442e8f30fb63;a432b8ce-0462-478b-83e7-3107cd2e909c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +d9f9ee76-b016-4588-ac6d-46681894ada7;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4188],[11.8198,53.4192]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 74;0.00421724;952c6b04-0d02-4ea2-a6cc-bb44fbbe4e52;594d101c-3a05-45e3-a061-9189f3e848b7;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +1f7e9cae-460e-47db-8cb8-da5d9f695fd8;"{""type"":""LineString"",""coordinates"":[[11.8197,53.4207],[11.8198,53.4211]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 13;0.00987733;839ff0f4-93db-42ec-a928-bbc448b6cf5c;27b84da5-478e-4a05-8fe7-a9f800db5eff;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f3a592d0-0fd7-42ea-b928-f39473b419aa;"{""type"":""LineString"",""coordinates"":[[11.8214,53.4246],[11.8213,53.4243]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 10;0.0344866;a9288e77-2919-4db6-89eb-9737bd07f111;3fcb94e3-7781-4d83-9030-d9853822e78e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f505bff9-0803-415f-a765-9da981ff6024;"{""type"":""LineString"",""coordinates"":[[11.8195,53.4264],[11.8195,53.4268]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 43;0.00839819;b8e95bf0-3ba8-4d53-a0bf-a3720fb785fb;34031e92-3444-47d5-94ae-cceeb5d96bb2;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +c6501262-2e05-462b-8872-445d2aa1cab8;"{""type"":""LineString"",""coordinates"":[[11.8195,53.4272],[11.8195,53.4275]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 99;0.0157523;120eaa58-a500-4ae2-a86a-56a40b931ec1;9d136a6b-5fdc-44ed-a5ed-599a55281024;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +caac4b4b-4871-4e20-994c-6517931546cb;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4229],[11.8201,53.4232]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 91;0.0220129;83da8d60-405a-45f7-9bb9-9d35607b7927;24b63115-12eb-4e77-b9ef-ca474fed960f;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e9721561-53c0-45cc-a8ed-28861ef9dc66;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4216],[11.8198,53.4221]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 7;0.0333523;883edf38-9a18-4f61-981a-691aaf436cc7;b565ae3b-68f9-4bca-816d-9b0fc1c6b13f;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +ab143df6-d050-47b6-911a-93e462d928ac;"{""type"":""LineString"",""coordinates"":[[11.8173,53.4234],[11.8166,53.4238]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 73;0.0287121;e68a088d-cf1a-40b7-9b1a-e0933352f4e6;4129e079-6712-4275-911c-36729d698c42;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +ab7ab785-36ba-4da1-b176-a7c636cb1372;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4267],[11.8213,53.4264]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 22;0.0102382;dc54bd8a-b7d8-4e99-adb0-d6ee5084241c;18b4157b-0e47-4c5a-adb8-ccae47372336;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +1ae90a03-52a3-40ef-8e06-4ba01888aa5c;"{""type"":""LineString"",""coordinates"":[[11.816,53.4222],[11.816,53.4227]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 44;0.00743191;62d603c3-f306-40b3-a665-ba9892d226f0;3faac527-0ff3-44a7-9e4f-24a41940da90;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +20be9235-f4db-4753-9fa1-223c8519fcd3;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4253],[11.8175,53.4257]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 66;0.00791441;73e7a7e8-2154-46ea-9727-a4916af3570c;5f153bf6-4f25-41f1-8545-18fe6323bc49;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +558e1545-a944-419a-9153-83caa09e1a3c;"{""type"":""LineString"",""coordinates"":[[11.8162,53.4273],[11.8162,53.4277]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 42;0.00357726;0d6ef8f6-0ba1-4fa7-8e63-e55cee12b165;2d33314e-31db-4ad4-a898-2be5d56a896d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +38d60cf7-6099-4bc0-a616-0f0b66c70c9a;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4232],[11.8201,53.4236]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 67;0.0179092;24b63115-12eb-4e77-b9ef-ca474fed960f;f713593a-3fd3-410a-ac08-74202d4f5798;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e74dbbe9-948f-4056-8134-fd1d9d39e773;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4253],[11.8196,53.4257]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 86;0.0190003;03b2aa45-84f6-48c0-9dab-427e046a5672;79e19265-08e8-407f-ae95-2f78e344d3a4;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +24c0dc1c-2e99-46ed-a52b-5a7aae7c9afb;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4249],[11.8166,53.4253]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 72;0.00189914;7c35a794-f569-4a9c-acb0-d03647610086;50cac08e-bf24-4526-9466-53ca5edccd15;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +41a72cb2-f037-4196-a248-2b18a578db50;"{""type"":""LineString"",""coordinates"":[[11.816,53.421],[11.816,53.4214]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 78;0.00156586;98c14f60-e196-4f12-903b-8485f1eacb16;ca0b9e34-ddc8-405e-86a4-ab939626c4a2;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e2919117-f70a-4b32-a5ab-f077fe0a84ef;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4253],[11.8166,53.4257]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 70;0.00263875;50cac08e-bf24-4526-9466-53ca5edccd15;8726dc29-621e-4455-a541-cd88d7da457f;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7d3ee5e1-1749-4e43-afeb-4ccf5f431312;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4282],[11.8196,53.4286]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 103;0.011354;a3ed5af5-1fcb-4fce-af0f-708d3d604124;31e6e197-719d-4aaf-8ca5-ab9e7549390e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +cbba4a6b-27d1-4724-a193-134af220a57d;"{""type"":""LineString"",""coordinates"":[[11.8182,53.4257],[11.8182,53.4254]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 49;0.018118;c86d6361-4159-4787-b5f4-e41dcaa95195;c6c20ab1-16fb-4f82-8017-273022da8bb0;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +b84fad90-182c-4ac1-b77d-394f39024ffc;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4286],[11.8196,53.4289]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 19;0.0115943;31e6e197-719d-4aaf-8ca5-ab9e7549390e;47246a84-ad0e-4d04-9d98-1c9cd5d363c1;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +6c87a571-9d8b-4df9-bd86-cde7954bee28;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4271],[11.8213,53.4267]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 21;0.00282037;7b81b518-00e0-4ff1-b4cf-876903958d7a;dc54bd8a-b7d8-4e99-adb0-d6ee5084241c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +536ef1a2-b988-4474-a5d4-1254598c4716;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4227],[11.8191,53.4223]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 82;0.00544392;15a86f7d-fb73-49a4-af6a-25b14122378d;c7e48384-5699-4a38-a887-7e15a9145202;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +c0c99b3a-1c61-47b8-931d-571d9494d98f;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4241],[11.8166,53.4245]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 51;0.0182324;5682ac05-7336-4ebc-a5d1-3b69c79fb3b1;7efabb8d-ba17-4487-96d9-5744b1fedf8a;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +d3366635-447e-4d45-b839-7a7561f869a3;"{""type"":""LineString"",""coordinates"":[[11.822,53.4294],[11.8221,53.429]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 4;0.0141339;c5b6bfaf-1621-40a7-9c53-02cfb59c04d9;9644f198-e801-4545-87ee-a24e2a8039bd;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +932dd0d7-2051-4a3a-a0e3-489210d3b763;"{""type"":""LineString"",""coordinates"":[[11.8169,53.4289],[11.817,53.4293]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 57;0.0219657;a882e666-82d1-4ba6-87df-fc702fe06187;85751c9b-3e5e-468a-9dc7-43775b0d4a6f;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e718d253-34ea-4c00-a653-80ac0af2934e;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4293],[11.8213,53.429]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 11;0.00557129;844c0b9c-058a-4228-a8c4-bf2defff6958;16091b6d-f1ea-4a07-9ad4-30d595aba68d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +3ac954bf-5c1e-428a-9da7-37331f53d8fe;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4248],[11.8175,53.4253]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 69;0.0017759;0d6c3f2b-5296-4ec1-995c-b150e72f035f;73e7a7e8-2154-46ea-9727-a4916af3570c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7e9a0440-2a62-4daf-a4ab-e9f14f6cfd77;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4238],[11.8166,53.4234]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 53;0.0337731;4129e079-6712-4275-911c-36729d698c42;57b40047-4f9d-46bb-bf19-c0a86bbd4f5b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +10a2050e-173b-43a7-91a0-157cee5c900d;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4257],[11.8195,53.426]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 87;0.00654022;79e19265-08e8-407f-ae95-2f78e344d3a4;9f1baf4e-12e1-41d1-8efc-81cfc78f1957;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +0dfd30a5-394e-49ff-95e9-50e73bf2604c;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4232],[11.8214,53.4229]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 34;0.0199334;a966644c-37d5-4400-9fa0-725fd88586a8;002a4495-96e4-49c9-abbe-8fccb3e9c83e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +847934a0-e2b7-4caf-bb40-2e6af5bcb0ab;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4238],[11.8166,53.4241]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 50;0.0101795;4129e079-6712-4275-911c-36729d698c42;5682ac05-7336-4ebc-a5d1-3b69c79fb3b1;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +2daf9021-eb24-4d0c-bced-00e713a65b3a;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4225],[11.8213,53.4222]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 36;0.010188;b909fb45-b6ee-427f-afd7-e8a0ec7274c6;589bf32a-b361-4536-ae96-6d56d184eedb;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +2f1b02a3-5a58-4723-ab8f-827118a4c611;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4239],[11.8213,53.4236]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 32;0.0188563;d0bfabdb-0e83-423b-a20a-ab9197c4284e;3464496c-7dd4-41e9-ae0a-99ade0b51572;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +a5e9b6b0-2afc-49b0-8aad-705410b823c2;"{""type"":""LineString"",""coordinates"":[[11.815,53.4285],[11.815,53.4281]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 109;0.027;88cf719a-92df-4dfd-9a83-f84330e28fe0;d38d936a-9c05-4bdc-8331-418fef27f492;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +ae82a1c1-9790-44d1-8dab-52d75c7b79ce;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4286],[11.8213,53.4282]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 6;0.0050064;1403edf9-e47c-4705-8563-83bcd639482e;09285b78-9c18-4af7-9c7a-942cc868016f;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e642eafb-2b6e-4b78-80b8-1ab15db8cfeb;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4278],[11.8196,53.4282]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 101;0.0153312;7dc43c81-9a61-45a0-9745-800a28bf4a9d;a3ed5af5-1fcb-4fce-af0f-708d3d604124;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +41a4c5e5-7b54-46a8-b6b6-d7b5861a251c;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4195],[11.8198,53.4199]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 96;0.0010841;af2b07ce-1a96-4b50-9e21-badf29eed519;215eaa45-82c3-49c7-a60f-4fa13215de05;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +44821cfc-7670-4f28-8941-70e9345cb069;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4225],[11.8203,53.4221]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 15;0.027677;a7725293-05fc-447f-bc12-38b689b0a956;eae8a04c-44f2-4da3-95f6-cae48f85737c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +d665e8c6-40fb-4608-97fb-99a4cf52560e;"{""type"":""LineString"",""coordinates"":[[11.815,53.4281],[11.815,53.4277]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 110;0.041;d38d936a-9c05-4bdc-8331-418fef27f492;3e6be3ac-2b51-4080-b815-391313612fc7;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +2f37bd36-f356-4d29-81c7-dd9c2fba5e7d;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4234],[11.8166,53.423]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 45;0.00223482;57b40047-4f9d-46bb-bf19-c0a86bbd4f5b;5b73ded9-3ca4-4f18-a2ab-c27b9a3dcf9d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +bcccf0b5-e0e3-4cc7-82bb-262ebc19415e;"{""type"":""LineString"",""coordinates"":[[11.8169,53.4289],[11.8168,53.4285]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 56;0.039;a882e666-82d1-4ba6-87df-fc702fe06187;c41ebab8-16a0-4a3a-b4af-26073932d462;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +3685f389-6822-4522-a633-74265b67eaee;"{""type"":""LineString"",""coordinates"":[[11.816,53.4227],[11.816,53.423]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 76;0.00185168;3faac527-0ff3-44a7-9e4f-24a41940da90;2575f527-1f4e-45e2-bed2-4a5427f122e0;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +48347702-9e58-49f3-a7de-72024d4b296c;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4199],[11.8198,53.4203]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 2;0.00995493;215eaa45-82c3-49c7-a60f-4fa13215de05;5596da2f-ca32-4ad3-81da-1ffa17cd3d7b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +ec2a73ea-50ba-4187-b8b0-a5046cf6b632;"{""type"":""LineString"",""coordinates"":[[11.8195,53.425],[11.8196,53.4253]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 83;0.00510961;29516ae3-6676-4797-99c1-1f0a32b989d8;03b2aa45-84f6-48c0-9dab-427e046a5672;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +d1940183-f7bb-42df-b8ff-63ac7aff0b1d;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4211],[11.8198,53.4216]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 9;0.00439896;27b84da5-478e-4a05-8fe7-a9f800db5eff;883edf38-9a18-4f61-981a-691aaf436cc7;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +dd618e3f-9ef9-4e4b-b632-737d79c4d8c3;"{""type"":""LineString"",""coordinates"":[[11.8175,53.427],[11.8174,53.4273]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 62;0.00124645;80b8d1f8-7e83-421d-a95a-c193fc35f4f7;8ace5c2b-584a-4015-990f-6f1e14de4ddb;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +ed80666a-cf86-404a-b3a7-ad49be1cd40c;"{""type"":""LineString"",""coordinates"":[[11.816,53.423],[11.816,53.4234]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 77;0.00232237;2575f527-1f4e-45e2-bed2-4a5427f122e0;5d3bcf55-0520-43ff-8d63-3d0eb421e442;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +444615ed-26f2-45a7-8b5d-213c72e83a4f;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4239],[11.8196,53.4243]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 95;0.0281251;80962bd3-a10f-4ed2-ba6a-3e802189939c;f4da61e4-7600-4cd1-95b6-c70b56c049fc;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +05ebbc17-61bc-4810-ae19-9ee04d7ce8d0;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4285],[11.8169,53.4289]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 54;0.0173762;30b2ce2d-41dd-4d1d-866d-47abd24bfc3e;a882e666-82d1-4ba6-87df-fc702fe06187;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +caf90323-aad2-496e-a0e3-a4ba7c9a481c;"{""type"":""LineString"",""coordinates"":[[11.8174,53.4273],[11.8175,53.4277]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 64;0.00314803;8ace5c2b-584a-4015-990f-6f1e14de4ddb;7f692039-eef6-45f6-9e30-b5983f6750a5;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +60b400db-b048-4bed-be29-8abc18780d10;"{""type"":""LineString"",""coordinates"":[[11.816,53.4206],[11.816,53.421]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 14;0.045296;d6dbb0ae-13c9-438e-93b3-b6c63a0708df;98c14f60-e196-4f12-903b-8485f1eacb16;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +cf13634d-abd2-465d-8839-c95a54af7a80;"{""type"":""LineString"",""coordinates"":[[11.816,53.4214],[11.816,53.4218]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 80;0.0101988;ca0b9e34-ddc8-405e-86a4-ab939626c4a2;43040a39-8b6c-401f-9dfd-82b42aa6dec6;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +30044e09-a0f8-417d-a949-afcfa940f671;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4253],[11.8213,53.425]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 25;0.0124821;a432b8ce-0462-478b-83e7-3107cd2e909c;58b551b6-83bd-4f1c-8d9c-8c9a7f638c0b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +fe71fe2b-8dd0-4942-b0b5-d241e095b912;"{""type"":""LineString"",""coordinates"":[[11.8195,53.4268],[11.8195,53.4272]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 97;0.0032723;34031e92-3444-47d5-94ae-cceeb5d96bb2;120eaa58-a500-4ae2-a86a-56a40b931ec1;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +66e44163-7091-4f1b-991c-64108e2238f6;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4243],[11.8191,53.4239]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 88;0.0185855;f4da61e4-7600-4cd1-95b6-c70b56c049fc;b5c1e826-63fd-4b0c-bec0-0c758389ef58;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +82bac681-169f-48d8-9842-fd69d3adbfe0;"{""type"":""LineString"",""coordinates"":[[11.816,53.4234],[11.8166,53.4238]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 75;0.0109137;5d3bcf55-0520-43ff-8d63-3d0eb421e442;4129e079-6712-4275-911c-36729d698c42;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +74a5dc42-e689-490f-a611-ae7c3767f01b;"{""type"":""LineString"",""coordinates"":[[11.816,53.4218],[11.816,53.4222]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 81;0.0100396;43040a39-8b6c-401f-9dfd-82b42aa6dec6;62d603c3-f306-40b3-a665-ba9892d226f0;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +0eedb3d0-cedc-4798-b42e-d8e8ef646b82;"{""type"":""LineString"",""coordinates"":[[11.8195,53.4275],[11.8196,53.4278]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 100;0.0129061;9d136a6b-5fdc-44ed-a5ed-599a55281024;7dc43c81-9a61-45a0-9745-800a28bf4a9d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +b44446fd-2125-4c7b-850e-b0f3d6c8b110;"{""type"":""LineString"",""coordinates"":[[11.8174,53.4281],[11.8175,53.4285]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 61;0.014766;3f6c26dd-842b-4dee-b71f-4aa32e2654ff;30b2ce2d-41dd-4d1d-866d-47abd24bfc3e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +31c914bc-dd9e-4825-9b4b-b5fc1b971e0d;"{""type"":""LineString"",""coordinates"":[[11.8166,53.423],[11.8166,53.4227]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 46;0.00683612;5b73ded9-3ca4-4f18-a2ab-c27b9a3dcf9d;ad30322c-0c99-4669-8e4b-25265087a66d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e7ac7023-f4e3-460d-8d02-4c9c444d2e18;"{""type"":""LineString"",""coordinates"":[[11.8191,53.422],[11.8191,53.4216]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 63;0.0149947;c6dac3ab-f44f-4b87-800c-0f4da64673f1;8f53645e-1f28-4eb1-807f-eb2a473f9d4c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e diff --git a/input/samples/simopsimtestgrid_reduced/fullGrid/line_type_input.csv b/input/samples/simopsimtestgrid_reduced/fullGrid/line_type_input.csv new file mode 100644 index 0000000000..d7786c38cd --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced/fullGrid/line_type_input.csv @@ -0,0 +1,2 @@ +uuid;b;g;i_max;id;r;v_rated;x +9a8e9b63-af21-4c1b-8db7-fc2924f9610e;273.31899999999996;0.0;357.0;NAYY 4x240SE 0.6/1kV;0.1267;0.4;0.0797965 diff --git a/input/samples/simopsimtestgrid_reduced/fullGrid/load_input.csv b/input/samples/simopsimtestgrid_reduced/fullGrid/load_input.csv new file mode 100644 index 0000000000..6ad16189a5 --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced/fullGrid/load_input.csv @@ -0,0 +1,4 @@ +uuid;cos_phi_rated;dsm;e_cons_annual;id;load_profile;node;operates_from;operates_until;operator;q_characteristics;s_rated;em +c3434742-e4f0-49e5-baa7-c1e3045c732c;0.93;false;0.0;LV5.201 Load 64;h0;dc54bd8a-b7d8-4e99-adb0-d6ee5084241c;;;;"cosPhiFixed:{(0.0,0.93)}";3.2;f9dc7ce6-658c-4101-a12f-d58bb889286b +fd2e19b6-d5e3-4776-9456-8787a2160d9d;0.93;false;0.0;LV5.201 Load 74;h0;43040a39-8b6c-401f-9dfd-82b42aa6dec6;;;;"cosPhiFixed:{(0.0,0.93)}";1.1;c3a7e9f5-b492-4c85-af2d-1e93f6a25443 +98c1a2ab-bd09-4c77-a389-d088aed894b1;0.93;false;0.0;LV5.201 Load 102;h0;3e6be3ac-2b51-4080-b815-391313612fc7;;;;"cosPhiFixed:{(0.0,0.93)}";5.3;957938b7-0476-4fab-a1b3-6ce8615857b3 diff --git a/input/samples/simopsimtestgrid_reduced/fullGrid/node_input.csv b/input/samples/simopsimtestgrid_reduced/fullGrid/node_input.csv new file mode 100644 index 0000000000..ab9f9335ca --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced/fullGrid/node_input.csv @@ -0,0 +1,112 @@ +uuid;geo_position;id;operates_from;operates_until;operator;slack;subnet;v_rated;v_target;volt_lvl +16091b6d-f1ea-4a07-9ad4-30d595aba68d;"{""type"":""Point"",""coordinates"":[11.8213,53.429],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 26;;;;false;2;0.4;1.0;Niederspannung +27b84da5-478e-4a05-8fe7-a9f800db5eff;"{""type"":""Point"",""coordinates"":[11.8198,53.4211],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 7;;;;false;2;0.4;1.0;Niederspannung +7f692039-eef6-45f6-9e30-b5983f6750a5;"{""type"":""Point"",""coordinates"":[11.8175,53.4277],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 54;;;;false;2;0.4;1.0;Niederspannung +20ad9754-e966-4ad1-9541-f968c207f3df;"{""type"":""Point"",""coordinates"":[11.8196,53.4293],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 84;;;;false;2;0.4;1.0;Niederspannung +98c14f60-e196-4f12-903b-8485f1eacb16;"{""type"":""Point"",""coordinates"":[11.816,53.421],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 29;;;;false;2;0.4;1.0;Niederspannung +09285b78-9c18-4af7-9c7a-942cc868016f;"{""type"":""Point"",""coordinates"":[11.8213,53.4282],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 58;;;;false;2;0.4;1.0;Niederspannung +0d6ef8f6-0ba1-4fa7-8e63-e55cee12b165;"{""type"":""Point"",""coordinates"":[11.8162,53.4273],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 103;;;;false;2;0.4;1.0;Niederspannung +43040a39-8b6c-401f-9dfd-82b42aa6dec6;"{""type"":""Point"",""coordinates"":[11.816,53.4218],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 25;;;;false;2;0.4;1.0;Niederspannung +dc54bd8a-b7d8-4e99-adb0-d6ee5084241c;"{""type"":""Point"",""coordinates"":[11.8213,53.4267],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 81;;;;false;2;0.4;1.0;Niederspannung +2575f527-1f4e-45e2-bed2-4a5427f122e0;"{""type"":""Point"",""coordinates"":[11.816,53.423],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 3;;;;false;2;0.4;1.0;Niederspannung +30b2ce2d-41dd-4d1d-866d-47abd24bfc3e;"{""type"":""Point"",""coordinates"":[11.8175,53.4285],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 34;;;;false;2;0.4;1.0;Niederspannung +589bf32a-b361-4536-ae96-6d56d184eedb;"{""type"":""Point"",""coordinates"":[11.8213,53.4222],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 101;;;;false;2;0.4;1.0;Niederspannung +555cd075-0fe4-4a65-b027-f45cffa960d9;"{""type"":""Point"",""coordinates"":[11.8162,53.4281],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 31;;;;false;2;0.4;1.0;Niederspannung +62d603c3-f306-40b3-a665-ba9892d226f0;"{""type"":""Point"",""coordinates"":[11.816,53.4222],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 55;;;;false;2;0.4;1.0;Niederspannung +215eaa45-82c3-49c7-a60f-4fa13215de05;"{""type"":""Point"",""coordinates"":[11.8198,53.4199],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 24;;;;false;2;0.4;1.0;Niederspannung +f4da61e4-7600-4cd1-95b6-c70b56c049fc;"{""type"":""Point"",""coordinates"":[11.8196,53.4243],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 76;;;;false;2;0.4;1.0;Niederspannung +73e7a7e8-2154-46ea-9727-a4916af3570c;"{""type"":""Point"",""coordinates"":[11.8175,53.4253],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 18;;;;false;2;0.4;1.0;Niederspannung +85751c9b-3e5e-468a-9dc7-43775b0d4a6f;"{""type"":""Point"",""coordinates"":[11.817,53.4293],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 51;;;;false;2;0.4;1.0;Niederspannung +093160c4-6482-4c58-b952-217c615e3ada;"{""type"":""Point"",""coordinates"":[11.8213,53.426],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 68;;;;false;2;0.4;1.0;Niederspannung +79e19265-08e8-407f-ae95-2f78e344d3a4;"{""type"":""Point"",""coordinates"":[11.8196,53.4257],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 28;;;;false;2;0.4;1.0;Niederspannung +a966644c-37d5-4400-9fa0-725fd88586a8;"{""type"":""Point"",""coordinates"":[11.8213,53.4232],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 59;;;;false;2;0.4;1.0;Niederspannung +952c6b04-0d02-4ea2-a6cc-bb44fbbe4e52;"{""type"":""Point"",""coordinates"":[11.8198,53.4188],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 94;;;;false;2;0.4;1.0;Niederspannung +c6c20ab1-16fb-4f82-8017-273022da8bb0;"{""type"":""Point"",""coordinates"":[11.8182,53.4254],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 62;;;;false;2;0.4;1.0;Niederspannung +e68a088d-cf1a-40b7-9b1a-e0933352f4e6;"{""type"":""Point"",""coordinates"":[11.8173,53.4234],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 67;;;;false;2;0.4;1.0;Niederspannung +8f53645e-1f28-4eb1-807f-eb2a473f9d4c;"{""type"":""Point"",""coordinates"":[11.8191,53.4216],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 86;;;;false;2;0.4;1.0;Niederspannung +0d6c3f2b-5296-4ec1-995c-b150e72f035f;"{""type"":""Point"",""coordinates"":[11.8175,53.4248],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 80;;;;false;2;0.4;1.0;Niederspannung +ea4a6507-e504-4542-be5f-1019719b2257;"{""type"":""Point"",""coordinates"":[11.8184,53.4293],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 111;;;;false;2;0.4;1.0;Niederspannung +9644f198-e801-4545-87ee-a24e2a8039bd;"{""type"":""Point"",""coordinates"":[11.8221,53.429],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 39;;;;false;2;0.4;1.0;Niederspannung +a9288e77-2919-4db6-89eb-9737bd07f111;"{""type"":""Point"",""coordinates"":[11.8214,53.4246],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 63;;;;false;2;0.4;1.0;Niederspannung +d6dbb0ae-13c9-438e-93b3-b6c63a0708df;"{""type"":""Point"",""coordinates"":[11.816,53.4206],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 89;;;;false;2;0.4;1.0;Niederspannung +5596da2f-ca32-4ad3-81da-1ffa17cd3d7b;"{""type"":""Point"",""coordinates"":[11.8198,53.4203],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 102;;;;false;2;0.4;1.0;Niederspannung +ad30322c-0c99-4669-8e4b-25265087a66d;"{""type"":""Point"",""coordinates"":[11.8166,53.4227],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 65;;;;false;2;0.4;1.0;Niederspannung +120eaa58-a500-4ae2-a86a-56a40b931ec1;"{""type"":""Point"",""coordinates"":[11.8195,53.4272],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 57;;;;false;2;0.4;1.0;Niederspannung +29516ae3-6676-4797-99c1-1f0a32b989d8;"{""type"":""Point"",""coordinates"":[11.8195,53.425],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 52;;;;false;2;0.4;1.0;Niederspannung +24b63115-12eb-4e77-b9ef-ca474fed960f;"{""type"":""Point"",""coordinates"":[11.8201,53.4232],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 46;;;;false;2;0.4;1.0;Niederspannung +a7725293-05fc-447f-bc12-38b689b0a956;"{""type"":""Point"",""coordinates"":[11.8201,53.4225],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 72;;;;false;2;0.4;1.0;Niederspannung +3b86661a-187d-4aa6-bf37-2014789afc08;"{""type"":""Point"",""coordinates"":[11.8214,53.4218],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 20;;;;false;2;0.4;1.0;Niederspannung +a3ed5af5-1fcb-4fce-af0f-708d3d604124;"{""type"":""Point"",""coordinates"":[11.8196,53.4282],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 33;;;;false;2;0.4;1.0;Niederspannung +ec8f2c82-a1b2-487c-b573-250859e3b414;"{""type"":""Point"",""coordinates"":[11.8166,53.4241],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";MV2.101 Bus 5;;;;true;1;20.0;1.025;Mittelspannung +5f153bf6-4f25-41f1-8545-18fe6323bc49;"{""type"":""Point"",""coordinates"":[11.8175,53.4257],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 17;;;;false;2;0.4;1.0;Niederspannung +b565ae3b-68f9-4bca-816d-9b0fc1c6b13f;"{""type"":""Point"",""coordinates"":[11.8198,53.4221],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 70;;;;false;2;0.4;1.0;Niederspannung +8e809cf6-7e05-437c-89a6-f6ca135a403b;"{""type"":""Point"",""coordinates"":[11.815,53.4289],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 47;;;;false;2;0.4;1.0;Niederspannung +ca0b9e34-ddc8-405e-86a4-ab939626c4a2;"{""type"":""Point"",""coordinates"":[11.816,53.4214],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 99;;;;false;2;0.4;1.0;Niederspannung +3e6be3ac-2b51-4080-b815-391313612fc7;"{""type"":""Point"",""coordinates"":[11.815,53.4277],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 110;;;;false;2;0.4;1.0;Niederspannung +4749ab2b-4d96-4100-8081-73e77c797d6b;"{""type"":""Point"",""coordinates"":[11.8166,53.4241],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 73;;;;false;2;0.4;1.0;Niederspannung +3f6c26dd-842b-4dee-b71f-4aa32e2654ff;"{""type"":""Point"",""coordinates"":[11.8174,53.4281],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 97;;;;false;2;0.4;1.0;Niederspannung +c6dac3ab-f44f-4b87-800c-0f4da64673f1;"{""type"":""Point"",""coordinates"":[11.8191,53.422],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 10;;;;false;2;0.4;1.0;Niederspannung +eae8a04c-44f2-4da3-95f6-cae48f85737c;"{""type"":""Point"",""coordinates"":[11.8203,53.4221],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 45;;;;false;2;0.4;1.0;Niederspannung +94fe96b1-f36a-4edd-a107-4ff0376f1066;"{""type"":""Point"",""coordinates"":[11.8175,53.4265],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 61;;;;false;2;0.4;1.0;Niederspannung +31e6e197-719d-4aaf-8ca5-ab9e7549390e;"{""type"":""Point"",""coordinates"":[11.8196,53.4286],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 32;;;;false;2;0.4;1.0;Niederspannung +002a4495-96e4-49c9-abbe-8fccb3e9c83e;"{""type"":""Point"",""coordinates"":[11.8214,53.4229],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 90;;;;false;2;0.4;1.0;Niederspannung +c7e48384-5699-4a38-a887-7e15a9145202;"{""type"":""Point"",""coordinates"":[11.8191,53.4223],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 107;;;;false;2;0.4;1.0;Niederspannung +8ace5c2b-584a-4015-990f-6f1e14de4ddb;"{""type"":""Point"",""coordinates"":[11.8174,53.4273],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 27;;;;false;2;0.4;1.0;Niederspannung +c41ebab8-16a0-4a3a-b4af-26073932d462;"{""type"":""Point"",""coordinates"":[11.8168,53.4285],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 35;;;;false;2;0.4;1.0;Niederspannung +ab8c8f6c-e7a2-4b81-a0d7-5f13789267a2;"{""type"":""Point"",""coordinates"":[11.815,53.4269],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 113;;;;false;2;0.4;1.0;Niederspannung +9f1baf4e-12e1-41d1-8efc-81cfc78f1957;"{""type"":""Point"",""coordinates"":[11.8195,53.426],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 71;;;;false;2;0.4;1.0;Niederspannung +02e63e81-2e62-4ef6-8fdb-0b0905a437b6;"{""type"":""Point"",""coordinates"":[11.8191,53.4212],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 12;;;;false;2;0.4;1.0;Niederspannung +2d33314e-31db-4ad4-a898-2be5d56a896d;"{""type"":""Point"",""coordinates"":[11.8162,53.4277],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 48;;;;false;2;0.4;1.0;Niederspannung +b8e95bf0-3ba8-4d53-a0bf-a3720fb785fb;"{""type"":""Point"",""coordinates"":[11.8195,53.4264],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 49;;;;false;2;0.4;1.0;Niederspannung +d0bfabdb-0e83-423b-a20a-ab9197c4284e;"{""type"":""Point"",""coordinates"":[11.8213,53.4239],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 82;;;;false;2;0.4;1.0;Niederspannung +6b2881ce-3965-4f5e-98a3-74eb47b0a7ca;"{""type"":""Point"",""coordinates"":[11.8162,53.4284],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 53;;;;false;2;0.4;1.0;Niederspannung +af2b07ce-1a96-4b50-9e21-badf29eed519;"{""type"":""Point"",""coordinates"":[11.8198,53.4195],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 100;;;;false;2;0.4;1.0;Niederspannung +844c0b9c-058a-4228-a8c4-bf2defff6958;"{""type"":""Point"",""coordinates"":[11.8213,53.4293],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 1;;;;false;2;0.4;1.0;Niederspannung +a432b8ce-0462-478b-83e7-3107cd2e909c;"{""type"":""Point"",""coordinates"":[11.8213,53.4253],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 56;;;;false;2;0.4;1.0;Niederspannung +4129e079-6712-4275-911c-36729d698c42;"{""type"":""Point"",""coordinates"":[11.8166,53.4238],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 77;;;;false;2;0.4;1.0;Niederspannung +883edf38-9a18-4f61-981a-691aaf436cc7;"{""type"":""Point"",""coordinates"":[11.8198,53.4216],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 4;;;;false;2;0.4;1.0;Niederspannung +f2724954-34d3-4ddf-b6b0-7a1531639990;"{""type"":""Point"",""coordinates"":[11.8191,53.4235],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 6;;;;false;2;0.4;1.0;Niederspannung +5d3bcf55-0520-43ff-8d63-3d0eb421e442;"{""type"":""Point"",""coordinates"":[11.816,53.4234],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 91;;;;false;2;0.4;1.0;Niederspannung +3a557b4e-06b8-4f29-929f-81d95c42c897;"{""type"":""Point"",""coordinates"":[11.8213,53.4277],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 42;;;;false;2;0.4;1.0;Niederspannung +7dc43c81-9a61-45a0-9745-800a28bf4a9d;"{""type"":""Point"",""coordinates"":[11.8196,53.4278],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 50;;;;false;2;0.4;1.0;Niederspannung +fd4bebb8-40ca-4eed-92c0-cdd10b86ac20;"{""type"":""Point"",""coordinates"":[11.8191,53.4209],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 60;;;;false;2;0.4;1.0;Niederspannung +3464496c-7dd4-41e9-ae0a-99ade0b51572;"{""type"":""Point"",""coordinates"":[11.8213,53.4236],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 40;;;;false;2;0.4;1.0;Niederspannung +d38d936a-9c05-4bdc-8331-418fef27f492;"{""type"":""Point"",""coordinates"":[11.815,53.4281],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 109;;;;false;2;0.4;1.0;Niederspannung +58b551b6-83bd-4f1c-8d9c-8c9a7f638c0b;"{""type"":""Point"",""coordinates"":[11.8213,53.425],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 38;;;;false;2;0.4;1.0;Niederspannung +b5c1e826-63fd-4b0c-bec0-0c758389ef58;"{""type"":""Point"",""coordinates"":[11.8191,53.4239],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 104;;;;false;2;0.4;1.0;Niederspannung +7c35a794-f569-4a9c-acb0-d03647610086;"{""type"":""Point"",""coordinates"":[11.8166,53.4249],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 98;;;;false;2;0.4;1.0;Niederspannung +78815cf6-70db-432c-96e6-87fe8cf67eee;"{""type"":""Point"",""coordinates"":[11.815,53.4272],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 112;;;;false;2;0.4;1.0;Niederspannung +c5b6bfaf-1621-40a7-9c53-02cfb59c04d9;"{""type"":""Point"",""coordinates"":[11.822,53.4294],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 14;;;;false;2;0.4;1.0;Niederspannung +2b3d7fb8-0583-4d47-97b1-3b5f232fd462;"{""type"":""Point"",""coordinates"":[11.8213,53.4274],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 87;;;;false;2;0.4;1.0;Niederspannung +3fcb94e3-7781-4d83-9030-d9853822e78e;"{""type"":""Point"",""coordinates"":[11.8213,53.4243],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 85;;;;false;2;0.4;1.0;Niederspannung +f713593a-3fd3-410a-ac08-74202d4f5798;"{""type"":""Point"",""coordinates"":[11.8201,53.4236],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 79;;;;false;2;0.4;1.0;Niederspannung +47246a84-ad0e-4d04-9d98-1c9cd5d363c1;"{""type"":""Point"",""coordinates"":[11.8196,53.4289],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 16;;;;false;2;0.4;1.0;Niederspannung +9cdb3115-cc00-4d61-bc33-442e8f30fb63;"{""type"":""Point"",""coordinates"":[11.8213,53.4257],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 83;;;;false;2;0.4;1.0;Niederspannung +839ff0f4-93db-42ec-a928-bbc448b6cf5c;"{""type"":""Point"",""coordinates"":[11.8197,53.4207],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 69;;;;false;2;0.4;1.0;Niederspannung +e7908208-77b4-4059-806e-4857262992fc;"{""type"":""Point"",""coordinates"":[11.8196,53.4247],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 105;;;;false;2;0.4;1.0;Niederspannung +83da8d60-405a-45f7-9bb9-9d35607b7927;"{""type"":""Point"",""coordinates"":[11.8201,53.4229],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 2;;;;false;2;0.4;1.0;Niederspannung +9d136a6b-5fdc-44ed-a5ed-599a55281024;"{""type"":""Point"",""coordinates"":[11.8195,53.4275],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 9;;;;false;2;0.4;1.0;Niederspannung +3faac527-0ff3-44a7-9e4f-24a41940da90;"{""type"":""Point"",""coordinates"":[11.816,53.4227],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 15;;;;false;2;0.4;1.0;Niederspannung +5682ac05-7336-4ebc-a5d1-3b69c79fb3b1;"{""type"":""Point"",""coordinates"":[11.8166,53.4241],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 44;;;;false;2;0.4;1.0;Niederspannung +5b73ded9-3ca4-4f18-a2ab-c27b9a3dcf9d;"{""type"":""Point"",""coordinates"":[11.8166,53.423],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 36;;;;false;2;0.4;1.0;Niederspannung +594d101c-3a05-45e3-a061-9189f3e848b7;"{""type"":""Point"",""coordinates"":[11.8198,53.4192],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 88;;;;false;2;0.4;1.0;Niederspannung +7b81b518-00e0-4ff1-b4cf-876903958d7a;"{""type"":""Point"",""coordinates"":[11.8213,53.4271],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 8;;;;false;2;0.4;1.0;Niederspannung +a882e666-82d1-4ba6-87df-fc702fe06187;"{""type"":""Point"",""coordinates"":[11.8169,53.4289],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 74;;;;false;2;0.4;1.0;Niederspannung +1403edf9-e47c-4705-8563-83bcd639482e;"{""type"":""Point"",""coordinates"":[11.8213,53.4286],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 75;;;;false;2;0.4;1.0;Niederspannung +03b2aa45-84f6-48c0-9dab-427e046a5672;"{""type"":""Point"",""coordinates"":[11.8196,53.4253],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 22;;;;false;2;0.4;1.0;Niederspannung +6ee7ea93-ea9c-40cb-b79a-1c5f287c97a5;"{""type"":""Point"",""coordinates"":[11.8221,53.4286],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 66;;;;false;2;0.4;1.0;Niederspannung +88cf719a-92df-4dfd-9a83-f84330e28fe0;"{""type"":""Point"",""coordinates"":[11.815,53.4285],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 108;;;;false;2;0.4;1.0;Niederspannung +80962bd3-a10f-4ed2-ba6a-3e802189939c;"{""type"":""Point"",""coordinates"":[11.8201,53.4239],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 21;;;;false;2;0.4;1.0;Niederspannung +80b8d1f8-7e83-421d-a95a-c193fc35f4f7;"{""type"":""Point"",""coordinates"":[11.8175,53.427],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 95;;;;false;2;0.4;1.0;Niederspannung +b909fb45-b6ee-427f-afd7-e8a0ec7274c6;"{""type"":""Point"",""coordinates"":[11.8213,53.4225],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 92;;;;false;2;0.4;1.0;Niederspannung +57b40047-4f9d-46bb-bf19-c0a86bbd4f5b;"{""type"":""Point"",""coordinates"":[11.8166,53.4234],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 37;;;;false;2;0.4;1.0;Niederspannung +18b4157b-0e47-4c5a-adb8-ccae47372336;"{""type"":""Point"",""coordinates"":[11.8213,53.4264],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 5;;;;false;2;0.4;1.0;Niederspannung +8726dc29-621e-4455-a541-cd88d7da457f;"{""type"":""Point"",""coordinates"":[11.8166,53.4257],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 96;;;;false;2;0.4;1.0;Niederspannung +814f784b-687f-4dd5-8a91-c7772c916d46;"{""type"":""Point"",""coordinates"":[11.8174,53.4262],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 19;;;;false;2;0.4;1.0;Niederspannung +7efabb8d-ba17-4487-96d9-5744b1fedf8a;"{""type"":""Point"",""coordinates"":[11.8166,53.4245],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 23;;;;false;2;0.4;1.0;Niederspannung +15a86f7d-fb73-49a4-af6a-25b14122378d;"{""type"":""Point"",""coordinates"":[11.8191,53.4227],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 11;;;;false;2;0.4;1.0;Niederspannung +34031e92-3444-47d5-94ae-cceeb5d96bb2;"{""type"":""Point"",""coordinates"":[11.8195,53.4268],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 106;;;;false;2;0.4;1.0;Niederspannung +35748e60-3be8-4930-8a61-209fd5df1bec;"{""type"":""Point"",""coordinates"":[11.815,53.4293],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 30;;;;false;2;0.4;1.0;Niederspannung +50cac08e-bf24-4526-9466-53ca5edccd15;"{""type"":""Point"",""coordinates"":[11.8166,53.4253],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 64;;;;false;2;0.4;1.0;Niederspannung +2efac9b1-fb0d-4e08-bfac-501798826deb;"{""type"":""Point"",""coordinates"":[11.8191,53.4231],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 93;;;;false;2;0.4;1.0;Niederspannung +c86d6361-4159-4787-b5f4-e41dcaa95195;"{""type"":""Point"",""coordinates"":[11.8182,53.4257],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 13;;;;false;2;0.4;1.0;Niederspannung diff --git a/input/samples/simopsimtestgrid_reduced/fullGrid/pv_input.csv b/input/samples/simopsimtestgrid_reduced/fullGrid/pv_input.csv new file mode 100644 index 0000000000..b883b51783 --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced/fullGrid/pv_input.csv @@ -0,0 +1,4 @@ +uuid;albedo;azimuth;cos_phi_rated;elevation_angle;eta_conv;id;k_g;k_t;market_reaction;node;operates_from;operates_until;operator;q_characteristics;s_rated;em +a1eb7fc1-3bee-4b65-a387-ef3046644bf0;0.20000000298023224;4.093344211578369;0.8999999761581421;37.69556427001953;97.0;LV5.201 PV 10;0.8999999761581421;1.0;false;dc54bd8a-b7d8-4e99-adb0-d6ee5084241c;;;;"cosPhiFixed:{(0.0,0.9)}";4.2;f9dc7ce6-658c-4101-a12f-d58bb889286b +de8cfef5-7620-4b9e-9a10-1faebb5a80c0;0.20000000298023224;4.093344211578369;0.8999999761581421;37.69556427001953;97.0;LV5.201 PV 11;0.8999999761581421;1.0;false;3e6be3ac-2b51-4080-b815-391313612fc7;;;;"cosPhiFixed:{(0.0,0.9)}";10.9;957938b7-0476-4fab-a1b3-6ce8615857b3 +2560c371-f420-4c2a-b4e6-e04c11b64c03;0.20000000298023224;0.7802008390426636;0.8999999761581421;40.086585998535156;98.0;LV5.201 PV 15;0.8999999761581421;1.0;false;43040a39-8b6c-401f-9dfd-82b42aa6dec6;;;;"cosPhiFixed:{(0.0,0.9)}";2.9;c3a7e9f5-b492-4c85-af2d-1e93f6a25443 diff --git a/input/samples/simopsimtestgrid_reduced/fullGrid/transformer_2_w_input.csv b/input/samples/simopsimtestgrid_reduced/fullGrid/transformer_2_w_input.csv new file mode 100644 index 0000000000..d1f9f5d13c --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced/fullGrid/transformer_2_w_input.csv @@ -0,0 +1,2 @@ +uuid;auto_tap;id;node_a;node_b;operates_from;operates_until;operator;parallel_devices;tap_pos;type +adaba416-9b52-45df-9d91-f67d0dd28ecb;false;MV2.101-LV5.201-Trafo 1;ec8f2c82-a1b2-487c-b573-250859e3b414;4749ab2b-4d96-4100-8081-73e77c797d6b;;;;1;0;417407d2-1e74-4f37-9b64-f701f53f8842 diff --git a/input/samples/simopsimtestgrid_reduced/fullGrid/transformer_2_w_type_input.csv b/input/samples/simopsimtestgrid_reduced/fullGrid/transformer_2_w_type_input.csv new file mode 100644 index 0000000000..b13848b159 --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced/fullGrid/transformer_2_w_type_input.csv @@ -0,0 +1,2 @@ +uuid;b_m;d_phi;d_v;g_m;id;r_sc;s_rated;tap_max;tap_min;tap_neutr;tap_side;v_rated_a;v_rated_b;x_sc +417407d2-1e74-4f37-9b64-f701f53f8842;-36.47380569074435;0.0;2.5;4124.999999999999;0.63 MVA 20/0.4 kV Dyn5 ASEA;6.953892668178382;630.0;2;-2;0;false;20.0;0.4;37.45518044666632 diff --git a/input/samples/simopsimtestgrid_reduced/simopsimtestgrid.conf b/input/samples/simopsimtestgrid_reduced/simopsimtestgrid.conf new file mode 100644 index 0000000000..c75ef413e2 --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced/simopsimtestgrid.conf @@ -0,0 +1,249 @@ +include "../common/pekko.conf" + +######### +# ATTENTION: Do not change this config file directly but use it as a base for your personal delta config for the +# vn_simona scenario! Delta configs can be created by including the config you want to change +# parameters from via include (e.g. include "input/samples/vn_simona/vn_simona.conf") at the +# beginning of your config file and then just override the parameters you want to change! +######### + +################################################################## +# Simulation Parameters +################################################################## +simona.simulationName = "simopsimtest" + +################################################################## +# Time Parameters +################################################################## +simona.time.startDateTime = "2024-02-27T00:00:00Z" +simona.time.endDateTime = "2024-02-27T23:45:00Z" +simona.time.schedulerReadyCheckWindow = 900 + +################################################################## +# Input Parameters +################################################################## +simona.input.primary.csvParams = { + directoryPath: "simona/input/samples/simopsimtestgrid_reduced/fullGrid" + csvSep: ";" + isHierarchic: false +} +simona.input.grid.datasource.id = "csv" +simona.input.grid.datasource.csvParams = { + directoryPath: "simona/input/samples/simopsimtestgrid_reduced/fullGrid" + csvSep: ";" + isHierarchic: false +} + +simona.input.weather.datasource = { + scheme = "icon" + sampleParams.use = true + coordinateSource.sampleParams.use = true + maxCoordinateDistance = 50000 +} + +################################################################## +# Output Parameters +################################################################## +simona.output.base.dir = "simona/output/simopsimtestgrid_reduced" +simona.output.base.addTimestampToOutputDir = true + +simona.output.sink.csv { + fileFormat = ".csv" + filePrefix = "" + fileSuffix = "" +} + +simona.output.grid = { + notifier = "grid" + nodes = false + lines = false + switches = false + transformers2w = false + transformers3w = false +} +simona.output.participant.defaultConfig = { + notifier = "default" + powerRequestReply = false + simulationResult = true +} +simona.output.participant.individualConfigs = [ + { + notifier = "pv" + powerRequestReply = false + simulationResult = true + }, + { + notifier = "wec" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "evcs" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "bm" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "chp" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "ev" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "hp" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "storage" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "fixedFeedIn" + powerRequestReply = false + simulationResult = false + } +] +simona.output.thermal = { + defaultConfig = { + notifier = "default", + simulationResult = false + } + individualConfigs = [ + { + notifier = "house", + simulationResult = false + } + ] +} + +################################################################## +# Runtime Configuration // todo refactor as this naming is misleading and partly unneeded +################################################################## +simona.runtime.selected_subgrids = [] +simona.runtime.selected_volt_lvls = [] + +simona.runtime.participant.load = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + modelBehaviour = "profile" + reference = "power" + } + individualConfigs = [] +} + +simona.runtime.participant.fixedFeedIn = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.pv = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.wec = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.evcs = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.hp = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.storage = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +# # # # # +# ATTENTION: calculateMissingReactivePowerWithModel and scaling is ignored here. +# # # # # +simona.runtime.participant.em = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +################################################################## +# Event Configuration +################################################################## +simona.event.listener = [] + +################################################################## +# Grid Configuration +################################################################## + +simona.gridConfig.refSystems = [ + {sNom = "100 kVA", vNom = "0.4 kV", voltLvls = [{id = "NS", vNom = "0.4 kV"}]}, + {sNom = "60 MVA", vNom = "20 kV", voltLvls = [{id = "MS", vNom = "20 kV"}]}, + {sNom = "600 MVA", vNom = "110 kV", voltLvls = [{id = "HS", vNom = "110 kV"}]}, + {sNom = "1000 MVA", vNom = "380 kV", voltLvls = [{id = "HoeS", vNom = "380 kV"}]} +] + +################################################################## +# Power Flow Configuration +################################################################## +simona.powerflow.maxSweepPowerDeviation = 1E-5 // the maximum allowed deviation in power between two sweeps, before overall convergence is assumed +simona.powerflow.newtonraphson.epsilon = [1E-12] +simona.powerflow.newtonraphson.iterations = 50 +simona.powerflow.resolution = "87300s" +simona.powerflow.stopOnFailure = true + +simona.control.transformer = [ + { + transformers = ["31a2b9bf-e785-4475-aa44-1c34646e8c79"], + measurements = ["923f2d69-3093-4198-86e4-13d2d1c220f8"], + vMin = 0.98, + vMax = 1.02 + }, { + transformers = ["1132dbf4-e8a1-44ae-8415-f42d4497aa1d"], + measurements = ["7686b818-a0ba-465c-8e4e-f7d3c4e171fc"], + vMin = 0.98, + vMax = 1.02 + } +] diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/em_input.csv b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/em_input.csv new file mode 100644 index 0000000000..b6a794fe65 --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/em_input.csv @@ -0,0 +1,4 @@ +uuid;control_strategy;parent_em;id;operates_from;operates_until;operator +c3a7e9f5-b492-4c85-af2d-1e93f6a25443;self_optimization;;EM_HH_Bus_25;;; +f9dc7ce6-658c-4101-a12f-d58bb889286b;self_optimization;;EM_HH_Bus_81;;; +957938b7-0476-4fab-a1b3-6ce8615857b3;self_optimization;;EM_HH_Bus_110;;; diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/ext_entity_mapping.csv b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/ext_entity_mapping.csv new file mode 100644 index 0000000000..58ec9dcd0f --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/ext_entity_mapping.csv @@ -0,0 +1,7 @@ +uuid,id,columnScheme,dataType +f9dc7ce6-658c-4101-a12f-d58bb889286b,EM_HH_Bus_81,p,result_participant +957938b7-0476-4fab-a1b3-6ce8615857b3,EM_HH_Bus_110,p,result_participant +c3a7e9f5-b492-4c85-af2d-1e93f6a25443,EM_HH_Bus_25,p,result_participant +f9dc7ce6-658c-4101-a12f-d58bb889286b,EM_HH_Bus_81/Schedule,p,input +957938b7-0476-4fab-a1b3-6ce8615857b3,EM_HH_Bus_110/Schedule,p,input +c3a7e9f5-b492-4c85-af2d-1e93f6a25443,EM_HH_Bus_25/Schedule,p,input \ No newline at end of file diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/line_input.csv b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/line_input.csv new file mode 100644 index 0000000000..f4ff92fbba --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/line_input.csv @@ -0,0 +1,110 @@ +uuid;geo_position;id;length;node_a;node_b;olm_characteristic;operates_from;operates_until;operator;parallel_devices;type +bdbbb247-57b7-473b-9411-53fcf35032db;"{""type"":""LineString"",""coordinates"":[[11.8213,53.426],[11.8213,53.4257]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 27;0.0161277;093160c4-6482-4c58-b952-217c615e3ada;9cdb3115-cc00-4d61-bc33-442e8f30fb63;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +c48eeb2c-6858-4f96-9a90-20641cc0903d;"{""type"":""LineString"",""coordinates"":[[11.8214,53.4229],[11.8213,53.4225]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 35;0.0150703;002a4495-96e4-49c9-abbe-8fccb3e9c83e;b909fb45-b6ee-427f-afd7-e8a0ec7274c6;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +97e498ae-a4f7-4485-a703-b8c00d0a5e8a;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4221],[11.8201,53.4225]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 8;0.0228449;b565ae3b-68f9-4bca-816d-9b0fc1c6b13f;a7725293-05fc-447f-bc12-38b689b0a956;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f907f152-7bfe-4a17-a63f-adda500f6f0e;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4241],[11.8184,53.4293]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 107;0.04;4749ab2b-4d96-4100-8081-73e77c797d6b;ea4a6507-e504-4542-be5f-1019719b2257;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +6bf14400-8f6c-41ef-b6a4-9e861a3ad08f;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4241],[11.822,53.4294]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 3;0.030304;4749ab2b-4d96-4100-8081-73e77c797d6b;c5b6bfaf-1621-40a7-9c53-02cfb59c04d9;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +18b92b71-320d-4294-a47e-6715f1594755;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4243],[11.8196,53.4247]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 102;0.0251089;f4da61e4-7600-4cd1-95b6-c70b56c049fc;e7908208-77b4-4059-806e-4857262992fc;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +4128307f-3e00-4da9-b629-b696b72165a4;"{""type"":""LineString"",""coordinates"":[[11.815,53.4289],[11.815,53.4293]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 28;0.0377768;8e809cf6-7e05-437c-89a6-f6ca135a403b;35748e60-3be8-4930-8a61-209fd5df1bec;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +92876b53-6bbc-48ff-ba5f-5f5c08313e4d;"{""type"":""LineString"",""coordinates"":[[11.815,53.4277],[11.815,53.4272]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 111;0.031;3e6be3ac-2b51-4080-b815-391313612fc7;78815cf6-70db-432c-96e6-87fe8cf67eee;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +4b557d0c-9992-48b1-b45e-26cccc01db03;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4235],[11.8191,53.4231]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 90;0.00167204;f2724954-34d3-4ddf-b6b0-7a1531639990;2efac9b1-fb0d-4e08-bfac-501798826deb;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +0652d3e0-8c7c-4be2-9a41-00534aa9774b;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4212],[11.8191,53.4209]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 94;0.00182131;02e63e81-2e62-4ef6-8fdb-0b0905a437b6;fd4bebb8-40ca-4eed-92c0-cdd10b86ac20;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +782d8c4c-accb-424b-91ae-9af1b5d4b1af;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4225],[11.8201,53.4229]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 79;0.0338129;a7725293-05fc-447f-bc12-38b689b0a956;83da8d60-405a-45f7-9bb9-9d35607b7927;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +b7cac7a5-f528-45bd-8ced-a16234979e13;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4239],[11.8191,53.4235]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 89;0.0111411;b5c1e826-63fd-4b0c-bec0-0c758389ef58;f2724954-34d3-4ddf-b6b0-7a1531639990;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7ac1a715-e141-429a-8cfe-ff2badd41074;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4257],[11.8174,53.4262]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 65;0.019;8726dc29-621e-4455-a541-cd88d7da457f;814f784b-687f-4dd5-8a91-c7772c916d46;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +77ae4f1e-9ecb-4dda-a5f2-ce7ae3f9bbec;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4264],[11.8213,53.426]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 23;0.00488535;18b4157b-0e47-4c5a-adb8-ccae47372336;093160c4-6482-4c58-b952-217c615e3ada;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +6aaa54d9-d7b7-4adc-a85a-335cdf1393d6;"{""type"":""LineString"",""coordinates"":[[11.8162,53.4284],[11.8169,53.4289]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 40;0.036;6b2881ce-3965-4f5e-98a3-74eb47b0a7ca;a882e666-82d1-4ba6-87df-fc702fe06187;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +c85c107e-82c0-4002-acfa-d7000512a2ad;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4274],[11.8213,53.4271]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 20;0.0182765;2b3d7fb8-0583-4d47-97b1-3b5f232fd462;7b81b518-00e0-4ff1-b4cf-876903958d7a;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +2ef5f888-4341-4eee-b505-ae07a9a60c8d;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4236],[11.8201,53.4239]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 55;0.0259846;f713593a-3fd3-410a-ac08-74202d4f5798;80962bd3-a10f-4ed2-ba6a-3e802189939c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +139ea4f9-9b7f-4825-8919-537a94ff4794;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4277],[11.8174,53.4281]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 59;0.00160952;7f692039-eef6-45f6-9e30-b5983f6750a5;3f6c26dd-842b-4dee-b71f-4aa32e2654ff;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +68853808-8b09-4ff2-9c92-88ed1d78c639;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4236],[11.8213,53.4232]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 33;0.0217875;3464496c-7dd4-41e9-ae0a-99ade0b51572;a966644c-37d5-4400-9fa0-725fd88586a8;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +91bec60c-2951-420c-a35e-2633119ee450;"{""type"":""LineString"",""coordinates"":[[11.8162,53.4277],[11.8162,53.4281]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 30;0.00820054;2d33314e-31db-4ad4-a898-2be5d56a896d;555cd075-0fe4-4a65-b027-f45cffa960d9;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +35ba0827-e27e-496e-b735-c778f3b03019;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4241],[11.8213,53.4293]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 18;0.0139169;4749ab2b-4d96-4100-8081-73e77c797d6b;844c0b9c-058a-4228-a8c4-bf2defff6958;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +60efd159-72d6-4546-b245-8b8fc120a9f8;"{""type"":""LineString"",""coordinates"":[[11.817,53.4293],[11.8166,53.4241]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 26;0.098;85751c9b-3e5e-468a-9dc7-43775b0d4a6f;4749ab2b-4d96-4100-8081-73e77c797d6b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +212b62aa-73c2-47af-95ec-00cad8d4a4f4;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4222],[11.8214,53.4218]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 38;0.00992653;589bf32a-b361-4536-ae96-6d56d184eedb;3b86661a-187d-4aa6-bf37-2014789afc08;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7e61def1-8414-40b3-8775-fad9124f4369;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4282],[11.8213,53.4277]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 16;0.0164234;09285b78-9c18-4af7-9c7a-942cc868016f;3a557b4e-06b8-4f29-929f-81d95c42c897;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f9b4c7dc-c199-4691-8c6d-1faf438cf336;"{""type"":""LineString"",""coordinates"":[[11.8221,53.429],[11.8221,53.4286]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 5;0.0143698;9644f198-e801-4545-87ee-a24e2a8039bd;6ee7ea93-ea9c-40cb-b79a-1c5f287c97a5;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +eebc456e-d11b-4b19-9100-cc1d8e91f926;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4245],[11.8166,53.4249]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 71;0.00648856;7efabb8d-ba17-4487-96d9-5744b1fedf8a;7c35a794-f569-4a9c-acb0-d03647610086;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +8f4c4009-e1ed-4985-8095-729aa5dc8cdd;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4192],[11.8198,53.4195]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 85;0.00737032;594d101c-3a05-45e3-a061-9189f3e848b7;af2b07ce-1a96-4b50-9e21-badf29eed519;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +20db47c8-d154-4ab2-ad65-caa4a37466d2;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4257],[11.8174,53.4262]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 68;0.037;5f153bf6-4f25-41f1-8545-18fe6323bc49;814f784b-687f-4dd5-8a91-c7772c916d46;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7d838003-cd6e-42fd-b75a-eaa354c3993b;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4216],[11.8191,53.4212]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 93;0.0043578;8f53645e-1f28-4eb1-807f-eb2a473f9d4c;02e63e81-2e62-4ef6-8fdb-0b0905a437b6;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +a92013e1-78b7-4447-a505-f25fffbf56f2;"{""type"":""LineString"",""coordinates"":[[11.8174,53.4262],[11.8175,53.4265]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 48;0.0118531;814f784b-687f-4dd5-8a91-c7772c916d46;94fe96b1-f36a-4edd-a107-4ff0376f1066;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +690f8f61-5cc7-448e-8971-a516f784bf11;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4293],[11.8166,53.4241]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 106;0.0131451;20ad9754-e966-4ad1-9541-f968c207f3df;4749ab2b-4d96-4100-8081-73e77c797d6b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +6a00d582-32b1-4581-bdd1-a638ca279597;"{""type"":""LineString"",""coordinates"":[[11.815,53.4272],[11.815,53.4269]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 112;0.028;78815cf6-70db-432c-96e6-87fe8cf67eee;ab8c8f6c-e7a2-4b81-a0d7-5f13789267a2;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +1d5877c1-31cd-4ee8-b0dd-667fa4fffb8a;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4277],[11.8213,53.4274]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 17;0.00286133;3a557b4e-06b8-4f29-929f-81d95c42c897;2b3d7fb8-0583-4d47-97b1-3b5f232fd462;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +a15cd6a4-4b22-434f-be9b-ad2abe6e538c;"{""type"":""LineString"",""coordinates"":[[11.815,53.4289],[11.815,53.4285]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 108;0.033;8e809cf6-7e05-437c-89a6-f6ca135a403b;88cf719a-92df-4dfd-9a83-f84330e28fe0;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +2bd81511-4f19-4374-8ac5-96c2b19eda64;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4223],[11.8191,53.422]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 52;0.00980013;c7e48384-5699-4a38-a887-7e15a9145202;c6dac3ab-f44f-4b87-800c-0f4da64673f1;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +beee40ad-aca3-490f-87d5-a6dfc4bb76e3;"{""type"":""LineString"",""coordinates"":[[11.815,53.4293],[11.8166,53.4241]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 39;0.09;35748e60-3be8-4930-8a61-209fd5df1bec;4749ab2b-4d96-4100-8081-73e77c797d6b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +96b06f87-7905-4d12-99d8-1ed330050659;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4203],[11.8197,53.4207]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 12;0.00473835;5596da2f-ca32-4ad3-81da-1ffa17cd3d7b;839ff0f4-93db-42ec-a928-bbc448b6cf5c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e66890ef-ec02-407f-a5bb-ce32128e7490;"{""type"":""LineString"",""coordinates"":[[11.8162,53.4281],[11.8162,53.4284]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 41;0.00828244;555cd075-0fe4-4a65-b027-f45cffa960d9;6b2881ce-3965-4f5e-98a3-74eb47b0a7ca;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +015b0337-98bd-40d4-97d3-13a0d1da88ee;"{""type"":""LineString"",""coordinates"":[[11.8213,53.425],[11.8214,53.4246]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 84;0.0489789;58b551b6-83bd-4f1c-8d9c-8c9a7f638c0b;a9288e77-2919-4db6-89eb-9737bd07f111;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f9e6b2f1-f8fb-4763-a1d0-36d06170fea0;"{""type"":""LineString"",""coordinates"":[[11.8213,53.429],[11.8213,53.4286]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 98;0.0144283;16091b6d-f1ea-4a07-9ad4-30d595aba68d;1403edf9-e47c-4705-8563-83bcd639482e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f270d6b5-7c94-4397-8ab0-7c39c888d726;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4265],[11.8175,53.427]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 58;0.0036937;94fe96b1-f36a-4edd-a107-4ff0376f1066;80b8d1f8-7e83-421d-a95a-c193fc35f4f7;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +af8c65aa-cfd6-434a-8512-2d80106a2f2c;"{""type"":""LineString"",""coordinates"":[[11.8195,53.426],[11.8195,53.4264]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 31;0.00626899;9f1baf4e-12e1-41d1-8efc-81cfc78f1957;b8e95bf0-3ba8-4d53-a0bf-a3720fb785fb;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +fe28e831-6405-4dfe-987b-d688367694f1;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4247],[11.8195,53.425]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 104;0.00221503;e7908208-77b4-4059-806e-4857262992fc;29516ae3-6676-4797-99c1-1f0a32b989d8;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +eac56d69-5500-4261-9690-adb16c867485;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4231],[11.8191,53.4227]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 92;0.0149219;2efac9b1-fb0d-4e08-bfac-501798826deb;15a86f7d-fb73-49a4-af6a-25b14122378d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +183f3976-48ca-42b2-9af9-7998436fac5b;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4289],[11.8196,53.4293]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 105;0.00721947;47246a84-ad0e-4d04-9d98-1c9cd5d363c1;20ad9754-e966-4ad1-9541-f968c207f3df;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7feef458-03f3-4d23-b3a2-e6f1035398c4;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4243],[11.8213,53.4239]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 29;0.0204277;3fcb94e3-7781-4d83-9030-d9853822e78e;d0bfabdb-0e83-423b-a20a-ab9197c4284e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +592cd979-16c9-43d8-a311-8ac938aa5d03;"{""type"":""LineString"",""coordinates"":[[11.8174,53.4262],[11.8182,53.4257]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 47;0.0181601;814f784b-687f-4dd5-8a91-c7772c916d46;c86d6361-4159-4787-b5f4-e41dcaa95195;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +684146e5-3b58-43b4-9589-45325ab1c0bc;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4257],[11.8213,53.4253]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 24;0.0102233;9cdb3115-cc00-4d61-bc33-442e8f30fb63;a432b8ce-0462-478b-83e7-3107cd2e909c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +d9f9ee76-b016-4588-ac6d-46681894ada7;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4188],[11.8198,53.4192]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 74;0.00421724;952c6b04-0d02-4ea2-a6cc-bb44fbbe4e52;594d101c-3a05-45e3-a061-9189f3e848b7;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +1f7e9cae-460e-47db-8cb8-da5d9f695fd8;"{""type"":""LineString"",""coordinates"":[[11.8197,53.4207],[11.8198,53.4211]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 13;0.00987733;839ff0f4-93db-42ec-a928-bbc448b6cf5c;27b84da5-478e-4a05-8fe7-a9f800db5eff;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f3a592d0-0fd7-42ea-b928-f39473b419aa;"{""type"":""LineString"",""coordinates"":[[11.8214,53.4246],[11.8213,53.4243]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 10;0.0344866;a9288e77-2919-4db6-89eb-9737bd07f111;3fcb94e3-7781-4d83-9030-d9853822e78e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +f505bff9-0803-415f-a765-9da981ff6024;"{""type"":""LineString"",""coordinates"":[[11.8195,53.4264],[11.8195,53.4268]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 43;0.00839819;b8e95bf0-3ba8-4d53-a0bf-a3720fb785fb;34031e92-3444-47d5-94ae-cceeb5d96bb2;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +c6501262-2e05-462b-8872-445d2aa1cab8;"{""type"":""LineString"",""coordinates"":[[11.8195,53.4272],[11.8195,53.4275]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 99;0.0157523;120eaa58-a500-4ae2-a86a-56a40b931ec1;9d136a6b-5fdc-44ed-a5ed-599a55281024;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +caac4b4b-4871-4e20-994c-6517931546cb;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4229],[11.8201,53.4232]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 91;0.0220129;83da8d60-405a-45f7-9bb9-9d35607b7927;24b63115-12eb-4e77-b9ef-ca474fed960f;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e9721561-53c0-45cc-a8ed-28861ef9dc66;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4216],[11.8198,53.4221]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 7;0.0333523;883edf38-9a18-4f61-981a-691aaf436cc7;b565ae3b-68f9-4bca-816d-9b0fc1c6b13f;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +ab143df6-d050-47b6-911a-93e462d928ac;"{""type"":""LineString"",""coordinates"":[[11.8173,53.4234],[11.8166,53.4238]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 73;0.0287121;e68a088d-cf1a-40b7-9b1a-e0933352f4e6;4129e079-6712-4275-911c-36729d698c42;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +ab7ab785-36ba-4da1-b176-a7c636cb1372;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4267],[11.8213,53.4264]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 22;0.0102382;dc54bd8a-b7d8-4e99-adb0-d6ee5084241c;18b4157b-0e47-4c5a-adb8-ccae47372336;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +1ae90a03-52a3-40ef-8e06-4ba01888aa5c;"{""type"":""LineString"",""coordinates"":[[11.816,53.4222],[11.816,53.4227]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 44;0.00743191;62d603c3-f306-40b3-a665-ba9892d226f0;3faac527-0ff3-44a7-9e4f-24a41940da90;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +20be9235-f4db-4753-9fa1-223c8519fcd3;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4253],[11.8175,53.4257]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 66;0.00791441;73e7a7e8-2154-46ea-9727-a4916af3570c;5f153bf6-4f25-41f1-8545-18fe6323bc49;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +558e1545-a944-419a-9153-83caa09e1a3c;"{""type"":""LineString"",""coordinates"":[[11.8162,53.4273],[11.8162,53.4277]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 42;0.00357726;0d6ef8f6-0ba1-4fa7-8e63-e55cee12b165;2d33314e-31db-4ad4-a898-2be5d56a896d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +38d60cf7-6099-4bc0-a616-0f0b66c70c9a;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4232],[11.8201,53.4236]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 67;0.0179092;24b63115-12eb-4e77-b9ef-ca474fed960f;f713593a-3fd3-410a-ac08-74202d4f5798;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e74dbbe9-948f-4056-8134-fd1d9d39e773;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4253],[11.8196,53.4257]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 86;0.0190003;03b2aa45-84f6-48c0-9dab-427e046a5672;79e19265-08e8-407f-ae95-2f78e344d3a4;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +24c0dc1c-2e99-46ed-a52b-5a7aae7c9afb;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4249],[11.8166,53.4253]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 72;0.00189914;7c35a794-f569-4a9c-acb0-d03647610086;50cac08e-bf24-4526-9466-53ca5edccd15;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +41a72cb2-f037-4196-a248-2b18a578db50;"{""type"":""LineString"",""coordinates"":[[11.816,53.421],[11.816,53.4214]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 78;0.00156586;98c14f60-e196-4f12-903b-8485f1eacb16;ca0b9e34-ddc8-405e-86a4-ab939626c4a2;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e2919117-f70a-4b32-a5ab-f077fe0a84ef;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4253],[11.8166,53.4257]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 70;0.00263875;50cac08e-bf24-4526-9466-53ca5edccd15;8726dc29-621e-4455-a541-cd88d7da457f;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7d3ee5e1-1749-4e43-afeb-4ccf5f431312;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4282],[11.8196,53.4286]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 103;0.011354;a3ed5af5-1fcb-4fce-af0f-708d3d604124;31e6e197-719d-4aaf-8ca5-ab9e7549390e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +cbba4a6b-27d1-4724-a193-134af220a57d;"{""type"":""LineString"",""coordinates"":[[11.8182,53.4257],[11.8182,53.4254]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 49;0.018118;c86d6361-4159-4787-b5f4-e41dcaa95195;c6c20ab1-16fb-4f82-8017-273022da8bb0;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +b84fad90-182c-4ac1-b77d-394f39024ffc;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4286],[11.8196,53.4289]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 19;0.0115943;31e6e197-719d-4aaf-8ca5-ab9e7549390e;47246a84-ad0e-4d04-9d98-1c9cd5d363c1;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +6c87a571-9d8b-4df9-bd86-cde7954bee28;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4271],[11.8213,53.4267]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 21;0.00282037;7b81b518-00e0-4ff1-b4cf-876903958d7a;dc54bd8a-b7d8-4e99-adb0-d6ee5084241c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +536ef1a2-b988-4474-a5d4-1254598c4716;"{""type"":""LineString"",""coordinates"":[[11.8191,53.4227],[11.8191,53.4223]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 82;0.00544392;15a86f7d-fb73-49a4-af6a-25b14122378d;c7e48384-5699-4a38-a887-7e15a9145202;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +c0c99b3a-1c61-47b8-931d-571d9494d98f;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4241],[11.8166,53.4245]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 51;0.0182324;5682ac05-7336-4ebc-a5d1-3b69c79fb3b1;7efabb8d-ba17-4487-96d9-5744b1fedf8a;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +d3366635-447e-4d45-b839-7a7561f869a3;"{""type"":""LineString"",""coordinates"":[[11.822,53.4294],[11.8221,53.429]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 4;0.0141339;c5b6bfaf-1621-40a7-9c53-02cfb59c04d9;9644f198-e801-4545-87ee-a24e2a8039bd;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +932dd0d7-2051-4a3a-a0e3-489210d3b763;"{""type"":""LineString"",""coordinates"":[[11.8169,53.4289],[11.817,53.4293]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 57;0.0219657;a882e666-82d1-4ba6-87df-fc702fe06187;85751c9b-3e5e-468a-9dc7-43775b0d4a6f;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e718d253-34ea-4c00-a653-80ac0af2934e;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4293],[11.8213,53.429]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 11;0.00557129;844c0b9c-058a-4228-a8c4-bf2defff6958;16091b6d-f1ea-4a07-9ad4-30d595aba68d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +3ac954bf-5c1e-428a-9da7-37331f53d8fe;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4248],[11.8175,53.4253]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 69;0.0017759;0d6c3f2b-5296-4ec1-995c-b150e72f035f;73e7a7e8-2154-46ea-9727-a4916af3570c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +7e9a0440-2a62-4daf-a4ab-e9f14f6cfd77;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4238],[11.8166,53.4234]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 53;0.0337731;4129e079-6712-4275-911c-36729d698c42;57b40047-4f9d-46bb-bf19-c0a86bbd4f5b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +10a2050e-173b-43a7-91a0-157cee5c900d;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4257],[11.8195,53.426]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 87;0.00654022;79e19265-08e8-407f-ae95-2f78e344d3a4;9f1baf4e-12e1-41d1-8efc-81cfc78f1957;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +0dfd30a5-394e-49ff-95e9-50e73bf2604c;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4232],[11.8214,53.4229]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 34;0.0199334;a966644c-37d5-4400-9fa0-725fd88586a8;002a4495-96e4-49c9-abbe-8fccb3e9c83e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +847934a0-e2b7-4caf-bb40-2e6af5bcb0ab;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4238],[11.8166,53.4241]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 50;0.0101795;4129e079-6712-4275-911c-36729d698c42;5682ac05-7336-4ebc-a5d1-3b69c79fb3b1;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +2daf9021-eb24-4d0c-bced-00e713a65b3a;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4225],[11.8213,53.4222]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 36;0.010188;b909fb45-b6ee-427f-afd7-e8a0ec7274c6;589bf32a-b361-4536-ae96-6d56d184eedb;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +2f1b02a3-5a58-4723-ab8f-827118a4c611;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4239],[11.8213,53.4236]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 32;0.0188563;d0bfabdb-0e83-423b-a20a-ab9197c4284e;3464496c-7dd4-41e9-ae0a-99ade0b51572;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +a5e9b6b0-2afc-49b0-8aad-705410b823c2;"{""type"":""LineString"",""coordinates"":[[11.815,53.4285],[11.815,53.4281]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 109;0.027;88cf719a-92df-4dfd-9a83-f84330e28fe0;d38d936a-9c05-4bdc-8331-418fef27f492;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +ae82a1c1-9790-44d1-8dab-52d75c7b79ce;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4286],[11.8213,53.4282]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 6;0.0050064;1403edf9-e47c-4705-8563-83bcd639482e;09285b78-9c18-4af7-9c7a-942cc868016f;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e642eafb-2b6e-4b78-80b8-1ab15db8cfeb;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4278],[11.8196,53.4282]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 101;0.0153312;7dc43c81-9a61-45a0-9745-800a28bf4a9d;a3ed5af5-1fcb-4fce-af0f-708d3d604124;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +41a4c5e5-7b54-46a8-b6b6-d7b5861a251c;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4195],[11.8198,53.4199]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 96;0.0010841;af2b07ce-1a96-4b50-9e21-badf29eed519;215eaa45-82c3-49c7-a60f-4fa13215de05;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +44821cfc-7670-4f28-8941-70e9345cb069;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4225],[11.8203,53.4221]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 15;0.027677;a7725293-05fc-447f-bc12-38b689b0a956;eae8a04c-44f2-4da3-95f6-cae48f85737c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +d665e8c6-40fb-4608-97fb-99a4cf52560e;"{""type"":""LineString"",""coordinates"":[[11.815,53.4281],[11.815,53.4277]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 110;0.041;d38d936a-9c05-4bdc-8331-418fef27f492;3e6be3ac-2b51-4080-b815-391313612fc7;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +2f37bd36-f356-4d29-81c7-dd9c2fba5e7d;"{""type"":""LineString"",""coordinates"":[[11.8166,53.4234],[11.8166,53.423]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 45;0.00223482;57b40047-4f9d-46bb-bf19-c0a86bbd4f5b;5b73ded9-3ca4-4f18-a2ab-c27b9a3dcf9d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +bcccf0b5-e0e3-4cc7-82bb-262ebc19415e;"{""type"":""LineString"",""coordinates"":[[11.8169,53.4289],[11.8168,53.4285]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 56;0.039;a882e666-82d1-4ba6-87df-fc702fe06187;c41ebab8-16a0-4a3a-b4af-26073932d462;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +3685f389-6822-4522-a633-74265b67eaee;"{""type"":""LineString"",""coordinates"":[[11.816,53.4227],[11.816,53.423]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 76;0.00185168;3faac527-0ff3-44a7-9e4f-24a41940da90;2575f527-1f4e-45e2-bed2-4a5427f122e0;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +48347702-9e58-49f3-a7de-72024d4b296c;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4199],[11.8198,53.4203]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 2;0.00995493;215eaa45-82c3-49c7-a60f-4fa13215de05;5596da2f-ca32-4ad3-81da-1ffa17cd3d7b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +ec2a73ea-50ba-4187-b8b0-a5046cf6b632;"{""type"":""LineString"",""coordinates"":[[11.8195,53.425],[11.8196,53.4253]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 83;0.00510961;29516ae3-6676-4797-99c1-1f0a32b989d8;03b2aa45-84f6-48c0-9dab-427e046a5672;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +d1940183-f7bb-42df-b8ff-63ac7aff0b1d;"{""type"":""LineString"",""coordinates"":[[11.8198,53.4211],[11.8198,53.4216]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 9;0.00439896;27b84da5-478e-4a05-8fe7-a9f800db5eff;883edf38-9a18-4f61-981a-691aaf436cc7;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +dd618e3f-9ef9-4e4b-b632-737d79c4d8c3;"{""type"":""LineString"",""coordinates"":[[11.8175,53.427],[11.8174,53.4273]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 62;0.00124645;80b8d1f8-7e83-421d-a95a-c193fc35f4f7;8ace5c2b-584a-4015-990f-6f1e14de4ddb;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +ed80666a-cf86-404a-b3a7-ad49be1cd40c;"{""type"":""LineString"",""coordinates"":[[11.816,53.423],[11.816,53.4234]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 77;0.00232237;2575f527-1f4e-45e2-bed2-4a5427f122e0;5d3bcf55-0520-43ff-8d63-3d0eb421e442;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +444615ed-26f2-45a7-8b5d-213c72e83a4f;"{""type"":""LineString"",""coordinates"":[[11.8201,53.4239],[11.8196,53.4243]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 95;0.0281251;80962bd3-a10f-4ed2-ba6a-3e802189939c;f4da61e4-7600-4cd1-95b6-c70b56c049fc;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +05ebbc17-61bc-4810-ae19-9ee04d7ce8d0;"{""type"":""LineString"",""coordinates"":[[11.8175,53.4285],[11.8169,53.4289]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 54;0.0173762;30b2ce2d-41dd-4d1d-866d-47abd24bfc3e;a882e666-82d1-4ba6-87df-fc702fe06187;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +caf90323-aad2-496e-a0e3-a4ba7c9a481c;"{""type"":""LineString"",""coordinates"":[[11.8174,53.4273],[11.8175,53.4277]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 64;0.00314803;8ace5c2b-584a-4015-990f-6f1e14de4ddb;7f692039-eef6-45f6-9e30-b5983f6750a5;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +60b400db-b048-4bed-be29-8abc18780d10;"{""type"":""LineString"",""coordinates"":[[11.816,53.4206],[11.816,53.421]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 14;0.045296;d6dbb0ae-13c9-438e-93b3-b6c63a0708df;98c14f60-e196-4f12-903b-8485f1eacb16;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +cf13634d-abd2-465d-8839-c95a54af7a80;"{""type"":""LineString"",""coordinates"":[[11.816,53.4214],[11.816,53.4218]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 80;0.0101988;ca0b9e34-ddc8-405e-86a4-ab939626c4a2;43040a39-8b6c-401f-9dfd-82b42aa6dec6;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +30044e09-a0f8-417d-a949-afcfa940f671;"{""type"":""LineString"",""coordinates"":[[11.8213,53.4253],[11.8213,53.425]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 25;0.0124821;a432b8ce-0462-478b-83e7-3107cd2e909c;58b551b6-83bd-4f1c-8d9c-8c9a7f638c0b;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +fe71fe2b-8dd0-4942-b0b5-d241e095b912;"{""type"":""LineString"",""coordinates"":[[11.8195,53.4268],[11.8195,53.4272]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 97;0.0032723;34031e92-3444-47d5-94ae-cceeb5d96bb2;120eaa58-a500-4ae2-a86a-56a40b931ec1;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +66e44163-7091-4f1b-991c-64108e2238f6;"{""type"":""LineString"",""coordinates"":[[11.8196,53.4243],[11.8191,53.4239]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 88;0.0185855;f4da61e4-7600-4cd1-95b6-c70b56c049fc;b5c1e826-63fd-4b0c-bec0-0c758389ef58;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +82bac681-169f-48d8-9842-fd69d3adbfe0;"{""type"":""LineString"",""coordinates"":[[11.816,53.4234],[11.8166,53.4238]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 75;0.0109137;5d3bcf55-0520-43ff-8d63-3d0eb421e442;4129e079-6712-4275-911c-36729d698c42;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +74a5dc42-e689-490f-a611-ae7c3767f01b;"{""type"":""LineString"",""coordinates"":[[11.816,53.4218],[11.816,53.4222]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 81;0.0100396;43040a39-8b6c-401f-9dfd-82b42aa6dec6;62d603c3-f306-40b3-a665-ba9892d226f0;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +0eedb3d0-cedc-4798-b42e-d8e8ef646b82;"{""type"":""LineString"",""coordinates"":[[11.8195,53.4275],[11.8196,53.4278]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 100;0.0129061;9d136a6b-5fdc-44ed-a5ed-599a55281024;7dc43c81-9a61-45a0-9745-800a28bf4a9d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +b44446fd-2125-4c7b-850e-b0f3d6c8b110;"{""type"":""LineString"",""coordinates"":[[11.8174,53.4281],[11.8175,53.4285]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 61;0.014766;3f6c26dd-842b-4dee-b71f-4aa32e2654ff;30b2ce2d-41dd-4d1d-866d-47abd24bfc3e;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +31c914bc-dd9e-4825-9b4b-b5fc1b971e0d;"{""type"":""LineString"",""coordinates"":[[11.8166,53.423],[11.8166,53.4227]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 46;0.00683612;5b73ded9-3ca4-4f18-a2ab-c27b9a3dcf9d;ad30322c-0c99-4669-8e4b-25265087a66d;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e +e7ac7023-f4e3-460d-8d02-4c9c444d2e18;"{""type"":""LineString"",""coordinates"":[[11.8191,53.422],[11.8191,53.4216]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Line 63;0.0149947;c6dac3ab-f44f-4b87-800c-0f4da64673f1;8f53645e-1f28-4eb1-807f-eb2a473f9d4c;"olm:{(0.0,1.0)}";;;;1;9a8e9b63-af21-4c1b-8db7-fc2924f9610e diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/line_type_input.csv b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/line_type_input.csv new file mode 100644 index 0000000000..d7786c38cd --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/line_type_input.csv @@ -0,0 +1,2 @@ +uuid;b;g;i_max;id;r;v_rated;x +9a8e9b63-af21-4c1b-8db7-fc2924f9610e;273.31899999999996;0.0;357.0;NAYY 4x240SE 0.6/1kV;0.1267;0.4;0.0797965 diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/load_input.csv b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/load_input.csv new file mode 100644 index 0000000000..55e4abf008 --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/load_input.csv @@ -0,0 +1,4 @@ +uuid;cos_phi_rated;dsm;e_cons_annual;id;load_profile;node;operates_from;operates_until;operator;q_characteristics;s_rated;em +c3434742-e4f0-49e5-baa7-c1e3045c732c;0.93;false;0.0;LV5.201 Load 64;h0;dc54bd8a-b7d8-4e99-adb0-d6ee5084241c;;;;"cosPhiFixed:{(0.0,0.93)}";0.2;f9dc7ce6-658c-4101-a12f-d58bb889286b +fd2e19b6-d5e3-4776-9456-8787a2160d9d;0.93;false;0.0;LV5.201 Load 74;h0;43040a39-8b6c-401f-9dfd-82b42aa6dec6;;;;"cosPhiFixed:{(0.0,0.93)}";1.1;c3a7e9f5-b492-4c85-af2d-1e93f6a25443 +98c1a2ab-bd09-4c77-a389-d088aed894b1;0.93;false;0.0;LV5.201 Load 102;h0;3e6be3ac-2b51-4080-b815-391313612fc7;;;;"cosPhiFixed:{(0.0,0.93)}";5.3;957938b7-0476-4fab-a1b3-6ce8615857b3 diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/node_input.csv b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/node_input.csv new file mode 100644 index 0000000000..ab9f9335ca --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/node_input.csv @@ -0,0 +1,112 @@ +uuid;geo_position;id;operates_from;operates_until;operator;slack;subnet;v_rated;v_target;volt_lvl +16091b6d-f1ea-4a07-9ad4-30d595aba68d;"{""type"":""Point"",""coordinates"":[11.8213,53.429],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 26;;;;false;2;0.4;1.0;Niederspannung +27b84da5-478e-4a05-8fe7-a9f800db5eff;"{""type"":""Point"",""coordinates"":[11.8198,53.4211],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 7;;;;false;2;0.4;1.0;Niederspannung +7f692039-eef6-45f6-9e30-b5983f6750a5;"{""type"":""Point"",""coordinates"":[11.8175,53.4277],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 54;;;;false;2;0.4;1.0;Niederspannung +20ad9754-e966-4ad1-9541-f968c207f3df;"{""type"":""Point"",""coordinates"":[11.8196,53.4293],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 84;;;;false;2;0.4;1.0;Niederspannung +98c14f60-e196-4f12-903b-8485f1eacb16;"{""type"":""Point"",""coordinates"":[11.816,53.421],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 29;;;;false;2;0.4;1.0;Niederspannung +09285b78-9c18-4af7-9c7a-942cc868016f;"{""type"":""Point"",""coordinates"":[11.8213,53.4282],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 58;;;;false;2;0.4;1.0;Niederspannung +0d6ef8f6-0ba1-4fa7-8e63-e55cee12b165;"{""type"":""Point"",""coordinates"":[11.8162,53.4273],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 103;;;;false;2;0.4;1.0;Niederspannung +43040a39-8b6c-401f-9dfd-82b42aa6dec6;"{""type"":""Point"",""coordinates"":[11.816,53.4218],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 25;;;;false;2;0.4;1.0;Niederspannung +dc54bd8a-b7d8-4e99-adb0-d6ee5084241c;"{""type"":""Point"",""coordinates"":[11.8213,53.4267],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 81;;;;false;2;0.4;1.0;Niederspannung +2575f527-1f4e-45e2-bed2-4a5427f122e0;"{""type"":""Point"",""coordinates"":[11.816,53.423],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 3;;;;false;2;0.4;1.0;Niederspannung +30b2ce2d-41dd-4d1d-866d-47abd24bfc3e;"{""type"":""Point"",""coordinates"":[11.8175,53.4285],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 34;;;;false;2;0.4;1.0;Niederspannung +589bf32a-b361-4536-ae96-6d56d184eedb;"{""type"":""Point"",""coordinates"":[11.8213,53.4222],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 101;;;;false;2;0.4;1.0;Niederspannung +555cd075-0fe4-4a65-b027-f45cffa960d9;"{""type"":""Point"",""coordinates"":[11.8162,53.4281],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 31;;;;false;2;0.4;1.0;Niederspannung +62d603c3-f306-40b3-a665-ba9892d226f0;"{""type"":""Point"",""coordinates"":[11.816,53.4222],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 55;;;;false;2;0.4;1.0;Niederspannung +215eaa45-82c3-49c7-a60f-4fa13215de05;"{""type"":""Point"",""coordinates"":[11.8198,53.4199],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 24;;;;false;2;0.4;1.0;Niederspannung +f4da61e4-7600-4cd1-95b6-c70b56c049fc;"{""type"":""Point"",""coordinates"":[11.8196,53.4243],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 76;;;;false;2;0.4;1.0;Niederspannung +73e7a7e8-2154-46ea-9727-a4916af3570c;"{""type"":""Point"",""coordinates"":[11.8175,53.4253],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 18;;;;false;2;0.4;1.0;Niederspannung +85751c9b-3e5e-468a-9dc7-43775b0d4a6f;"{""type"":""Point"",""coordinates"":[11.817,53.4293],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 51;;;;false;2;0.4;1.0;Niederspannung +093160c4-6482-4c58-b952-217c615e3ada;"{""type"":""Point"",""coordinates"":[11.8213,53.426],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 68;;;;false;2;0.4;1.0;Niederspannung +79e19265-08e8-407f-ae95-2f78e344d3a4;"{""type"":""Point"",""coordinates"":[11.8196,53.4257],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 28;;;;false;2;0.4;1.0;Niederspannung +a966644c-37d5-4400-9fa0-725fd88586a8;"{""type"":""Point"",""coordinates"":[11.8213,53.4232],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 59;;;;false;2;0.4;1.0;Niederspannung +952c6b04-0d02-4ea2-a6cc-bb44fbbe4e52;"{""type"":""Point"",""coordinates"":[11.8198,53.4188],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 94;;;;false;2;0.4;1.0;Niederspannung +c6c20ab1-16fb-4f82-8017-273022da8bb0;"{""type"":""Point"",""coordinates"":[11.8182,53.4254],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 62;;;;false;2;0.4;1.0;Niederspannung +e68a088d-cf1a-40b7-9b1a-e0933352f4e6;"{""type"":""Point"",""coordinates"":[11.8173,53.4234],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 67;;;;false;2;0.4;1.0;Niederspannung +8f53645e-1f28-4eb1-807f-eb2a473f9d4c;"{""type"":""Point"",""coordinates"":[11.8191,53.4216],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 86;;;;false;2;0.4;1.0;Niederspannung +0d6c3f2b-5296-4ec1-995c-b150e72f035f;"{""type"":""Point"",""coordinates"":[11.8175,53.4248],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 80;;;;false;2;0.4;1.0;Niederspannung +ea4a6507-e504-4542-be5f-1019719b2257;"{""type"":""Point"",""coordinates"":[11.8184,53.4293],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 111;;;;false;2;0.4;1.0;Niederspannung +9644f198-e801-4545-87ee-a24e2a8039bd;"{""type"":""Point"",""coordinates"":[11.8221,53.429],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 39;;;;false;2;0.4;1.0;Niederspannung +a9288e77-2919-4db6-89eb-9737bd07f111;"{""type"":""Point"",""coordinates"":[11.8214,53.4246],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 63;;;;false;2;0.4;1.0;Niederspannung +d6dbb0ae-13c9-438e-93b3-b6c63a0708df;"{""type"":""Point"",""coordinates"":[11.816,53.4206],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 89;;;;false;2;0.4;1.0;Niederspannung +5596da2f-ca32-4ad3-81da-1ffa17cd3d7b;"{""type"":""Point"",""coordinates"":[11.8198,53.4203],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 102;;;;false;2;0.4;1.0;Niederspannung +ad30322c-0c99-4669-8e4b-25265087a66d;"{""type"":""Point"",""coordinates"":[11.8166,53.4227],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 65;;;;false;2;0.4;1.0;Niederspannung +120eaa58-a500-4ae2-a86a-56a40b931ec1;"{""type"":""Point"",""coordinates"":[11.8195,53.4272],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 57;;;;false;2;0.4;1.0;Niederspannung +29516ae3-6676-4797-99c1-1f0a32b989d8;"{""type"":""Point"",""coordinates"":[11.8195,53.425],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 52;;;;false;2;0.4;1.0;Niederspannung +24b63115-12eb-4e77-b9ef-ca474fed960f;"{""type"":""Point"",""coordinates"":[11.8201,53.4232],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 46;;;;false;2;0.4;1.0;Niederspannung +a7725293-05fc-447f-bc12-38b689b0a956;"{""type"":""Point"",""coordinates"":[11.8201,53.4225],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 72;;;;false;2;0.4;1.0;Niederspannung +3b86661a-187d-4aa6-bf37-2014789afc08;"{""type"":""Point"",""coordinates"":[11.8214,53.4218],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 20;;;;false;2;0.4;1.0;Niederspannung +a3ed5af5-1fcb-4fce-af0f-708d3d604124;"{""type"":""Point"",""coordinates"":[11.8196,53.4282],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 33;;;;false;2;0.4;1.0;Niederspannung +ec8f2c82-a1b2-487c-b573-250859e3b414;"{""type"":""Point"",""coordinates"":[11.8166,53.4241],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";MV2.101 Bus 5;;;;true;1;20.0;1.025;Mittelspannung +5f153bf6-4f25-41f1-8545-18fe6323bc49;"{""type"":""Point"",""coordinates"":[11.8175,53.4257],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 17;;;;false;2;0.4;1.0;Niederspannung +b565ae3b-68f9-4bca-816d-9b0fc1c6b13f;"{""type"":""Point"",""coordinates"":[11.8198,53.4221],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 70;;;;false;2;0.4;1.0;Niederspannung +8e809cf6-7e05-437c-89a6-f6ca135a403b;"{""type"":""Point"",""coordinates"":[11.815,53.4289],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 47;;;;false;2;0.4;1.0;Niederspannung +ca0b9e34-ddc8-405e-86a4-ab939626c4a2;"{""type"":""Point"",""coordinates"":[11.816,53.4214],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 99;;;;false;2;0.4;1.0;Niederspannung +3e6be3ac-2b51-4080-b815-391313612fc7;"{""type"":""Point"",""coordinates"":[11.815,53.4277],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 110;;;;false;2;0.4;1.0;Niederspannung +4749ab2b-4d96-4100-8081-73e77c797d6b;"{""type"":""Point"",""coordinates"":[11.8166,53.4241],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 73;;;;false;2;0.4;1.0;Niederspannung +3f6c26dd-842b-4dee-b71f-4aa32e2654ff;"{""type"":""Point"",""coordinates"":[11.8174,53.4281],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 97;;;;false;2;0.4;1.0;Niederspannung +c6dac3ab-f44f-4b87-800c-0f4da64673f1;"{""type"":""Point"",""coordinates"":[11.8191,53.422],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 10;;;;false;2;0.4;1.0;Niederspannung +eae8a04c-44f2-4da3-95f6-cae48f85737c;"{""type"":""Point"",""coordinates"":[11.8203,53.4221],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 45;;;;false;2;0.4;1.0;Niederspannung +94fe96b1-f36a-4edd-a107-4ff0376f1066;"{""type"":""Point"",""coordinates"":[11.8175,53.4265],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 61;;;;false;2;0.4;1.0;Niederspannung +31e6e197-719d-4aaf-8ca5-ab9e7549390e;"{""type"":""Point"",""coordinates"":[11.8196,53.4286],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 32;;;;false;2;0.4;1.0;Niederspannung +002a4495-96e4-49c9-abbe-8fccb3e9c83e;"{""type"":""Point"",""coordinates"":[11.8214,53.4229],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 90;;;;false;2;0.4;1.0;Niederspannung +c7e48384-5699-4a38-a887-7e15a9145202;"{""type"":""Point"",""coordinates"":[11.8191,53.4223],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 107;;;;false;2;0.4;1.0;Niederspannung +8ace5c2b-584a-4015-990f-6f1e14de4ddb;"{""type"":""Point"",""coordinates"":[11.8174,53.4273],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 27;;;;false;2;0.4;1.0;Niederspannung +c41ebab8-16a0-4a3a-b4af-26073932d462;"{""type"":""Point"",""coordinates"":[11.8168,53.4285],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 35;;;;false;2;0.4;1.0;Niederspannung +ab8c8f6c-e7a2-4b81-a0d7-5f13789267a2;"{""type"":""Point"",""coordinates"":[11.815,53.4269],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 113;;;;false;2;0.4;1.0;Niederspannung +9f1baf4e-12e1-41d1-8efc-81cfc78f1957;"{""type"":""Point"",""coordinates"":[11.8195,53.426],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 71;;;;false;2;0.4;1.0;Niederspannung +02e63e81-2e62-4ef6-8fdb-0b0905a437b6;"{""type"":""Point"",""coordinates"":[11.8191,53.4212],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 12;;;;false;2;0.4;1.0;Niederspannung +2d33314e-31db-4ad4-a898-2be5d56a896d;"{""type"":""Point"",""coordinates"":[11.8162,53.4277],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 48;;;;false;2;0.4;1.0;Niederspannung +b8e95bf0-3ba8-4d53-a0bf-a3720fb785fb;"{""type"":""Point"",""coordinates"":[11.8195,53.4264],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 49;;;;false;2;0.4;1.0;Niederspannung +d0bfabdb-0e83-423b-a20a-ab9197c4284e;"{""type"":""Point"",""coordinates"":[11.8213,53.4239],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 82;;;;false;2;0.4;1.0;Niederspannung +6b2881ce-3965-4f5e-98a3-74eb47b0a7ca;"{""type"":""Point"",""coordinates"":[11.8162,53.4284],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 53;;;;false;2;0.4;1.0;Niederspannung +af2b07ce-1a96-4b50-9e21-badf29eed519;"{""type"":""Point"",""coordinates"":[11.8198,53.4195],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 100;;;;false;2;0.4;1.0;Niederspannung +844c0b9c-058a-4228-a8c4-bf2defff6958;"{""type"":""Point"",""coordinates"":[11.8213,53.4293],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 1;;;;false;2;0.4;1.0;Niederspannung +a432b8ce-0462-478b-83e7-3107cd2e909c;"{""type"":""Point"",""coordinates"":[11.8213,53.4253],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 56;;;;false;2;0.4;1.0;Niederspannung +4129e079-6712-4275-911c-36729d698c42;"{""type"":""Point"",""coordinates"":[11.8166,53.4238],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 77;;;;false;2;0.4;1.0;Niederspannung +883edf38-9a18-4f61-981a-691aaf436cc7;"{""type"":""Point"",""coordinates"":[11.8198,53.4216],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 4;;;;false;2;0.4;1.0;Niederspannung +f2724954-34d3-4ddf-b6b0-7a1531639990;"{""type"":""Point"",""coordinates"":[11.8191,53.4235],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 6;;;;false;2;0.4;1.0;Niederspannung +5d3bcf55-0520-43ff-8d63-3d0eb421e442;"{""type"":""Point"",""coordinates"":[11.816,53.4234],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 91;;;;false;2;0.4;1.0;Niederspannung +3a557b4e-06b8-4f29-929f-81d95c42c897;"{""type"":""Point"",""coordinates"":[11.8213,53.4277],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 42;;;;false;2;0.4;1.0;Niederspannung +7dc43c81-9a61-45a0-9745-800a28bf4a9d;"{""type"":""Point"",""coordinates"":[11.8196,53.4278],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 50;;;;false;2;0.4;1.0;Niederspannung +fd4bebb8-40ca-4eed-92c0-cdd10b86ac20;"{""type"":""Point"",""coordinates"":[11.8191,53.4209],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 60;;;;false;2;0.4;1.0;Niederspannung +3464496c-7dd4-41e9-ae0a-99ade0b51572;"{""type"":""Point"",""coordinates"":[11.8213,53.4236],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 40;;;;false;2;0.4;1.0;Niederspannung +d38d936a-9c05-4bdc-8331-418fef27f492;"{""type"":""Point"",""coordinates"":[11.815,53.4281],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 109;;;;false;2;0.4;1.0;Niederspannung +58b551b6-83bd-4f1c-8d9c-8c9a7f638c0b;"{""type"":""Point"",""coordinates"":[11.8213,53.425],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 38;;;;false;2;0.4;1.0;Niederspannung +b5c1e826-63fd-4b0c-bec0-0c758389ef58;"{""type"":""Point"",""coordinates"":[11.8191,53.4239],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 104;;;;false;2;0.4;1.0;Niederspannung +7c35a794-f569-4a9c-acb0-d03647610086;"{""type"":""Point"",""coordinates"":[11.8166,53.4249],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 98;;;;false;2;0.4;1.0;Niederspannung +78815cf6-70db-432c-96e6-87fe8cf67eee;"{""type"":""Point"",""coordinates"":[11.815,53.4272],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 112;;;;false;2;0.4;1.0;Niederspannung +c5b6bfaf-1621-40a7-9c53-02cfb59c04d9;"{""type"":""Point"",""coordinates"":[11.822,53.4294],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 14;;;;false;2;0.4;1.0;Niederspannung +2b3d7fb8-0583-4d47-97b1-3b5f232fd462;"{""type"":""Point"",""coordinates"":[11.8213,53.4274],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 87;;;;false;2;0.4;1.0;Niederspannung +3fcb94e3-7781-4d83-9030-d9853822e78e;"{""type"":""Point"",""coordinates"":[11.8213,53.4243],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 85;;;;false;2;0.4;1.0;Niederspannung +f713593a-3fd3-410a-ac08-74202d4f5798;"{""type"":""Point"",""coordinates"":[11.8201,53.4236],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 79;;;;false;2;0.4;1.0;Niederspannung +47246a84-ad0e-4d04-9d98-1c9cd5d363c1;"{""type"":""Point"",""coordinates"":[11.8196,53.4289],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 16;;;;false;2;0.4;1.0;Niederspannung +9cdb3115-cc00-4d61-bc33-442e8f30fb63;"{""type"":""Point"",""coordinates"":[11.8213,53.4257],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 83;;;;false;2;0.4;1.0;Niederspannung +839ff0f4-93db-42ec-a928-bbc448b6cf5c;"{""type"":""Point"",""coordinates"":[11.8197,53.4207],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 69;;;;false;2;0.4;1.0;Niederspannung +e7908208-77b4-4059-806e-4857262992fc;"{""type"":""Point"",""coordinates"":[11.8196,53.4247],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 105;;;;false;2;0.4;1.0;Niederspannung +83da8d60-405a-45f7-9bb9-9d35607b7927;"{""type"":""Point"",""coordinates"":[11.8201,53.4229],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 2;;;;false;2;0.4;1.0;Niederspannung +9d136a6b-5fdc-44ed-a5ed-599a55281024;"{""type"":""Point"",""coordinates"":[11.8195,53.4275],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 9;;;;false;2;0.4;1.0;Niederspannung +3faac527-0ff3-44a7-9e4f-24a41940da90;"{""type"":""Point"",""coordinates"":[11.816,53.4227],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 15;;;;false;2;0.4;1.0;Niederspannung +5682ac05-7336-4ebc-a5d1-3b69c79fb3b1;"{""type"":""Point"",""coordinates"":[11.8166,53.4241],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 44;;;;false;2;0.4;1.0;Niederspannung +5b73ded9-3ca4-4f18-a2ab-c27b9a3dcf9d;"{""type"":""Point"",""coordinates"":[11.8166,53.423],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 36;;;;false;2;0.4;1.0;Niederspannung +594d101c-3a05-45e3-a061-9189f3e848b7;"{""type"":""Point"",""coordinates"":[11.8198,53.4192],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 88;;;;false;2;0.4;1.0;Niederspannung +7b81b518-00e0-4ff1-b4cf-876903958d7a;"{""type"":""Point"",""coordinates"":[11.8213,53.4271],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 8;;;;false;2;0.4;1.0;Niederspannung +a882e666-82d1-4ba6-87df-fc702fe06187;"{""type"":""Point"",""coordinates"":[11.8169,53.4289],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 74;;;;false;2;0.4;1.0;Niederspannung +1403edf9-e47c-4705-8563-83bcd639482e;"{""type"":""Point"",""coordinates"":[11.8213,53.4286],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 75;;;;false;2;0.4;1.0;Niederspannung +03b2aa45-84f6-48c0-9dab-427e046a5672;"{""type"":""Point"",""coordinates"":[11.8196,53.4253],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 22;;;;false;2;0.4;1.0;Niederspannung +6ee7ea93-ea9c-40cb-b79a-1c5f287c97a5;"{""type"":""Point"",""coordinates"":[11.8221,53.4286],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 66;;;;false;2;0.4;1.0;Niederspannung +88cf719a-92df-4dfd-9a83-f84330e28fe0;"{""type"":""Point"",""coordinates"":[11.815,53.4285],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 108;;;;false;2;0.4;1.0;Niederspannung +80962bd3-a10f-4ed2-ba6a-3e802189939c;"{""type"":""Point"",""coordinates"":[11.8201,53.4239],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 21;;;;false;2;0.4;1.0;Niederspannung +80b8d1f8-7e83-421d-a95a-c193fc35f4f7;"{""type"":""Point"",""coordinates"":[11.8175,53.427],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 95;;;;false;2;0.4;1.0;Niederspannung +b909fb45-b6ee-427f-afd7-e8a0ec7274c6;"{""type"":""Point"",""coordinates"":[11.8213,53.4225],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 92;;;;false;2;0.4;1.0;Niederspannung +57b40047-4f9d-46bb-bf19-c0a86bbd4f5b;"{""type"":""Point"",""coordinates"":[11.8166,53.4234],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 37;;;;false;2;0.4;1.0;Niederspannung +18b4157b-0e47-4c5a-adb8-ccae47372336;"{""type"":""Point"",""coordinates"":[11.8213,53.4264],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 5;;;;false;2;0.4;1.0;Niederspannung +8726dc29-621e-4455-a541-cd88d7da457f;"{""type"":""Point"",""coordinates"":[11.8166,53.4257],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 96;;;;false;2;0.4;1.0;Niederspannung +814f784b-687f-4dd5-8a91-c7772c916d46;"{""type"":""Point"",""coordinates"":[11.8174,53.4262],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 19;;;;false;2;0.4;1.0;Niederspannung +7efabb8d-ba17-4487-96d9-5744b1fedf8a;"{""type"":""Point"",""coordinates"":[11.8166,53.4245],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 23;;;;false;2;0.4;1.0;Niederspannung +15a86f7d-fb73-49a4-af6a-25b14122378d;"{""type"":""Point"",""coordinates"":[11.8191,53.4227],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 11;;;;false;2;0.4;1.0;Niederspannung +34031e92-3444-47d5-94ae-cceeb5d96bb2;"{""type"":""Point"",""coordinates"":[11.8195,53.4268],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 106;;;;false;2;0.4;1.0;Niederspannung +35748e60-3be8-4930-8a61-209fd5df1bec;"{""type"":""Point"",""coordinates"":[11.815,53.4293],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 30;;;;false;2;0.4;1.0;Niederspannung +50cac08e-bf24-4526-9466-53ca5edccd15;"{""type"":""Point"",""coordinates"":[11.8166,53.4253],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 64;;;;false;2;0.4;1.0;Niederspannung +2efac9b1-fb0d-4e08-bfac-501798826deb;"{""type"":""Point"",""coordinates"":[11.8191,53.4231],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 93;;;;false;2;0.4;1.0;Niederspannung +c86d6361-4159-4787-b5f4-e41dcaa95195;"{""type"":""Point"",""coordinates"":[11.8182,53.4257],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}";LV5.201 Bus 13;;;;false;2;0.4;1.0;Niederspannung diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/pv_input.csv b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/pv_input.csv new file mode 100644 index 0000000000..b883b51783 --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/pv_input.csv @@ -0,0 +1,4 @@ +uuid;albedo;azimuth;cos_phi_rated;elevation_angle;eta_conv;id;k_g;k_t;market_reaction;node;operates_from;operates_until;operator;q_characteristics;s_rated;em +a1eb7fc1-3bee-4b65-a387-ef3046644bf0;0.20000000298023224;4.093344211578369;0.8999999761581421;37.69556427001953;97.0;LV5.201 PV 10;0.8999999761581421;1.0;false;dc54bd8a-b7d8-4e99-adb0-d6ee5084241c;;;;"cosPhiFixed:{(0.0,0.9)}";4.2;f9dc7ce6-658c-4101-a12f-d58bb889286b +de8cfef5-7620-4b9e-9a10-1faebb5a80c0;0.20000000298023224;4.093344211578369;0.8999999761581421;37.69556427001953;97.0;LV5.201 PV 11;0.8999999761581421;1.0;false;3e6be3ac-2b51-4080-b815-391313612fc7;;;;"cosPhiFixed:{(0.0,0.9)}";10.9;957938b7-0476-4fab-a1b3-6ce8615857b3 +2560c371-f420-4c2a-b4e6-e04c11b64c03;0.20000000298023224;0.7802008390426636;0.8999999761581421;40.086585998535156;98.0;LV5.201 PV 15;0.8999999761581421;1.0;false;43040a39-8b6c-401f-9dfd-82b42aa6dec6;;;;"cosPhiFixed:{(0.0,0.9)}";2.9;c3a7e9f5-b492-4c85-af2d-1e93f6a25443 diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/storage_input.csv b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/storage_input.csv new file mode 100644 index 0000000000..60b2df901a --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/storage_input.csv @@ -0,0 +1,2 @@ +uuid;id;node;operates_from;operates_until;operator;q_characteristics;type;em +06b58276-8350-40fb-86c0-2414aa4a0452;LV5.201 Storage 64;dc54bd8a-b7d8-4e99-adb0-d6ee5084241c;;;;"cosPhiFixed:{(0.00,0.95)}";95d4c980-d9e1-4813-9f2a-b0942488a570;f9dc7ce6-658c-4101-a12f-d58bb889286b diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/storage_type_input.csv b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/storage_type_input.csv new file mode 100644 index 0000000000..8c6fb1c867 --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/storage_type_input.csv @@ -0,0 +1,2 @@ +uuid;active_power_gradient;capex;cos_phi_rated;e_storage;eta;id;opex;p_max;s_rated +95d4c980-d9e1-4813-9f2a-b0942488a570;1.0;0.0;0.96;8.0;93.0;Typ_1;0.65;4.0;4.166666666666667 diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/transformer_2_w_input.csv b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/transformer_2_w_input.csv new file mode 100644 index 0000000000..d1f9f5d13c --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/transformer_2_w_input.csv @@ -0,0 +1,2 @@ +uuid;auto_tap;id;node_a;node_b;operates_from;operates_until;operator;parallel_devices;tap_pos;type +adaba416-9b52-45df-9d91-f67d0dd28ecb;false;MV2.101-LV5.201-Trafo 1;ec8f2c82-a1b2-487c-b573-250859e3b414;4749ab2b-4d96-4100-8081-73e77c797d6b;;;;1;0;417407d2-1e74-4f37-9b64-f701f53f8842 diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/transformer_2_w_type_input.csv b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/transformer_2_w_type_input.csv new file mode 100644 index 0000000000..b13848b159 --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid/transformer_2_w_type_input.csv @@ -0,0 +1,2 @@ +uuid;b_m;d_phi;d_v;g_m;id;r_sc;s_rated;tap_max;tap_min;tap_neutr;tap_side;v_rated_a;v_rated_b;x_sc +417407d2-1e74-4f37-9b64-f701f53f8842;-36.47380569074435;0.0;2.5;4124.999999999999;0.63 MVA 20/0.4 kV Dyn5 ASEA;6.953892668178382;630.0;2;-2;0;false;20.0;0.4;37.45518044666632 diff --git a/input/samples/simopsimtestgrid_reduced_with_storage/simopsimtestgrid.conf b/input/samples/simopsimtestgrid_reduced_with_storage/simopsimtestgrid.conf new file mode 100644 index 0000000000..5ed8c36fcd --- /dev/null +++ b/input/samples/simopsimtestgrid_reduced_with_storage/simopsimtestgrid.conf @@ -0,0 +1,249 @@ +include "../common/pekko.conf" + +######### +# ATTENTION: Do not change this config file directly but use it as a base for your personal delta config for the +# vn_simona scenario! Delta configs can be created by including the config you want to change +# parameters from via include (e.g. include "input/samples/vn_simona/vn_simona.conf") at the +# beginning of your config file and then just override the parameters you want to change! +######### + +################################################################## +# Simulation Parameters +################################################################## +simona.simulationName = "simopsimtest" + +################################################################## +# Time Parameters +################################################################## +simona.time.startDateTime = "2024-02-27T00:00:00Z" +simona.time.endDateTime = "2024-02-28T00:00:00Z" +simona.time.schedulerReadyCheckWindow = 900 + +################################################################## +# Input Parameters +################################################################## +simona.input.primary.csvParams = { + directoryPath: "simona/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid" + csvSep: ";" + isHierarchic: false +} +simona.input.grid.datasource.id = "csv" +simona.input.grid.datasource.csvParams = { + directoryPath: "simona/input/samples/simopsimtestgrid_reduced_with_storage/fullGrid" + csvSep: ";" + isHierarchic: false +} + +simona.input.weather.datasource = { + scheme = "icon" + sampleParams.use = true + coordinateSource.sampleParams.use = true + maxCoordinateDistance = 50000 +} + +################################################################## +# Output Parameters +################################################################## +simona.output.base.dir = "simona/output/simopsimtestgrid_reduced_with_storage" +simona.output.base.addTimestampToOutputDir = true + +simona.output.sink.csv { + fileFormat = ".csv" + filePrefix = "" + fileSuffix = "" +} + +simona.output.grid = { + notifier = "grid" + nodes = false + lines = false + switches = false + transformers2w = false + transformers3w = false +} +simona.output.participant.defaultConfig = { + notifier = "default" + powerRequestReply = false + simulationResult = true +} +simona.output.participant.individualConfigs = [ + { + notifier = "pv" + powerRequestReply = false + simulationResult = true + }, + { + notifier = "wec" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "evcs" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "bm" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "chp" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "ev" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "hp" + powerRequestReply = false + simulationResult = false + }, + { + notifier = "storage" + powerRequestReply = false + simulationResult = true + }, + { + notifier = "fixedFeedIn" + powerRequestReply = false + simulationResult = false + } +] +simona.output.thermal = { + defaultConfig = { + notifier = "default", + simulationResult = false + } + individualConfigs = [ + { + notifier = "house", + simulationResult = false + } + ] +} + +################################################################## +# Runtime Configuration // todo refactor as this naming is misleading and partly unneeded +################################################################## +simona.runtime.selected_subgrids = [] +simona.runtime.selected_volt_lvls = [] + +simona.runtime.participant.load = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + modelBehaviour = "fix" + reference = "power" + } + individualConfigs = [] +} + +simona.runtime.participant.fixedFeedIn = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.pv = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.wec = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.evcs = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.hp = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.storage = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +# # # # # +# ATTENTION: calculateMissingReactivePowerWithModel and scaling is ignored here. +# # # # # +simona.runtime.participant.em = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +################################################################## +# Event Configuration +################################################################## +simona.event.listener = [] + +################################################################## +# Grid Configuration +################################################################## + +simona.gridConfig.refSystems = [ + {sNom = "100 kVA", vNom = "0.4 kV", voltLvls = [{id = "NS", vNom = "0.4 kV"}]}, + {sNom = "60 MVA", vNom = "20 kV", voltLvls = [{id = "MS", vNom = "20 kV"}]}, + {sNom = "600 MVA", vNom = "110 kV", voltLvls = [{id = "HS", vNom = "110 kV"}]}, + {sNom = "1000 MVA", vNom = "380 kV", voltLvls = [{id = "HoeS", vNom = "380 kV"}]} +] + +################################################################## +# Power Flow Configuration +################################################################## +simona.powerflow.maxSweepPowerDeviation = 1E-5 // the maximum allowed deviation in power between two sweeps, before overall convergence is assumed +simona.powerflow.newtonraphson.epsilon = [1E-12] +simona.powerflow.newtonraphson.iterations = 50 +simona.powerflow.resolution = "87300s" +simona.powerflow.stopOnFailure = true + +simona.control.transformer = [ + { + transformers = ["31a2b9bf-e785-4475-aa44-1c34646e8c79"], + measurements = ["923f2d69-3093-4198-86e4-13d2d1c220f8"], + vMin = 0.98, + vMax = 1.02 + }, { + transformers = ["1132dbf4-e8a1-44ae-8415-f42d4497aa1d"], + measurements = ["7686b818-a0ba-465c-8e4e-f7d3c4e171fc"], + vMin = 0.98, + vMax = 1.02 + } +] diff --git a/input/samples/vn_simona_small_with_em/fullGrid/em_input.csv b/input/samples/vn_simona_small_with_em/fullGrid/em_input.csv new file mode 100644 index 0000000000..22729f2b61 --- /dev/null +++ b/input/samples/vn_simona_small_with_em/fullGrid/em_input.csv @@ -0,0 +1,3 @@ +uuid,control_strategy,parent_em,id,operates_from,operates_until,operator +fd1a8de9-722a-4304-8799-e1e976d9979c,self_optimization,,EM_NS_Node_3,,, +ff0b995a-86ff-4f4d-987e-e475a64f2180,self_optimization,,EM_NS_Node_4,,, \ No newline at end of file diff --git a/input/samples/vn_simona_small_with_em/fullGrid/fixed_feed_in_input.csv b/input/samples/vn_simona_small_with_em/fullGrid/fixed_feed_in_input.csv new file mode 100644 index 0000000000..90a18373ca --- /dev/null +++ b/input/samples/vn_simona_small_with_em/fullGrid/fixed_feed_in_input.csv @@ -0,0 +1,2 @@ +uuid,cos_phi_rated,id,node,operates_from,operates_until,operator,q_characteristics,s_rated +9abe950d-362e-4efe-b686-500f84d8f368,0.9,feed_in_hs_s4,401f37f8-6f2c-4564-bc78-6736cb9cbf8d,,,,"cosPhiFixed:{(0.0,0.95)}",200.0 diff --git a/input/samples/vn_simona_small_with_em/fullGrid/line_input.csv b/input/samples/vn_simona_small_with_em/fullGrid/line_input.csv new file mode 100644 index 0000000000..0f7b0204e7 --- /dev/null +++ b/input/samples/vn_simona_small_with_em/fullGrid/line_input.csv @@ -0,0 +1,6 @@ +uuid,geo_position,id,length,node_a,node_b,olm_characteristic,operates_from,operates_until,operator,parallel_devices,type +fd04cc09-6ff8-48ea-a5eb-453e9d59d6d7,"{""type"":""LineString"",""coordinates"":[[7.4116482,51.4843281],[7.4116482,51.4843281]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}",LTG_NS_Node_1-NS_Node_3,0.04,00d03670-7833-47ee-ad52-04d18d1c64fd,33f29587-f63e-45b7-960b-037bda37a3cb,"olm:{(0.0,1.0)}",,,,1,9a8e9b63-af21-4c1b-8db7-fc2924f9610e +b5a66c60-7189-4c86-a32a-4d1aa6568475,"{""type"":""LineString"",""coordinates"":[[7.4116482,51.4843281],[7.4116482,51.4843281]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}",LTG_NS_Node_4-NS_Node_1,0.030304,401f37f8-6f2c-4564-bc78-6736cb9cbf8d,00d03670-7833-47ee-ad52-04d18d1c64fd,"olm:{(0.0,1.0)}",,,,1,9a8e9b63-af21-4c1b-8db7-fc2924f9610e +42828cac-b67e-4d5c-b4fa-787c57f16fde,"{""type"":""LineString"",""coordinates"":[[7.4116482,51.4843281],[7.4116482,51.4843281]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}",LTG_NS_Node_3-NS_Node_2,0.0251089,33f29587-f63e-45b7-960b-037bda37a3cb,dfae9806-9b44-4995-ba27-d66d8e4a43e0,"olm:{(0.0,1.0)}",,,,1,9a8e9b63-af21-4c1b-8db7-fc2924f9610e +997840bf-8c94-444f-83f1-e9c991706d7c,"{""type"":""LineString"",""coordinates"":[[7.4116482,51.4843281],[7.4116482,51.4843281]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}",LTG_NS_Node_1-NS_Node_2,0.0377768,00d03670-7833-47ee-ad52-04d18d1c64fd,dfae9806-9b44-4995-ba27-d66d8e4a43e0,"olm:{(0.0,1.0)}",,,,1,9a8e9b63-af21-4c1b-8db7-fc2924f9610e +81f4c585-6170-4a9e-981f-2185a0d7f2ec,"{""type"":""LineString"",""coordinates"":[[7.4116482,51.4843281],[7.4116482,51.4843281]],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}",LTG_NS_Node_3-NS_Node_4,0.031,33f29587-f63e-45b7-960b-037bda37a3cb,401f37f8-6f2c-4564-bc78-6736cb9cbf8d,"olm:{(0.0,1.0)}",,,,1,9a8e9b63-af21-4c1b-8db7-fc2924f9610e diff --git a/input/samples/vn_simona_small_with_em/fullGrid/line_type_input.csv b/input/samples/vn_simona_small_with_em/fullGrid/line_type_input.csv new file mode 100644 index 0000000000..91202b2778 --- /dev/null +++ b/input/samples/vn_simona_small_with_em/fullGrid/line_type_input.csv @@ -0,0 +1,2 @@ +uuid,b,g,i_max,id,r,v_rated,x +9a8e9b63-af21-4c1b-8db7-fc2924f9610e,273.31899999999996,0.0,357.0,NAYY 4x240SE 0.6/1kV,0.1267,0.4,0.0797965 diff --git a/input/samples/vn_simona_small_with_em/fullGrid/load_input.csv b/input/samples/vn_simona_small_with_em/fullGrid/load_input.csv new file mode 100644 index 0000000000..2324353168 --- /dev/null +++ b/input/samples/vn_simona_small_with_em/fullGrid/load_input.csv @@ -0,0 +1,5 @@ +uuid,cos_phi_rated,dsm,e_cons_annual,id,load_profile,node,operates_from,operates_until,operator,q_characteristics,s_rated,em +4dca3b1d-5d24-444a-b4df-f4fa23b9ef1b,0.949999988079071,false,4000.0,LOAD_NS_Node_1,h0,00d03670-7833-47ee-ad52-04d18d1c64fd,,,,"cosPhiFixed:{(0.0,1.0)}",4.1237101554870605, +9c5991bc-24df-496b-b4ce-5ec27657454c,0.949999988079071,false,4000.0,LOAD_NS_Node_2,h0,dfae9806-9b44-4995-ba27-d66d8e4a43e0,,,,"cosPhiFixed:{(0.0,1.0)}",4.1237101554870605, +58b9f934-f7c4-4335-9894-3c80d9e6b852,0.949999988079071,false,4000.0,LOAD_NS_Node_3,h0,33f29587-f63e-45b7-960b-037bda37a3cb,,,,"cosPhiFixed:{(0.0,1.0)}",4.1237101554870605,fd1a8de9-722a-4304-8799-e1e976d9979c +283a1252-a774-4b04-bfcf-fe8879065982,0.949999988079071,false,4000.0,LOAD_NS_Node_4,h0,401f37f8-6f2c-4564-bc78-6736cb9cbf8d,,,,"cosPhiFixed:{(0.0,1.0)}",2.3157899379730225,ff0b995a-86ff-4f4d-987e-e475a64f2180 diff --git a/input/samples/vn_simona_small_with_em/fullGrid/node_input.csv b/input/samples/vn_simona_small_with_em/fullGrid/node_input.csv new file mode 100644 index 0000000000..21772153f5 --- /dev/null +++ b/input/samples/vn_simona_small_with_em/fullGrid/node_input.csv @@ -0,0 +1,6 @@ +uuid,geo_position,id,operates_from,operates_until,operator,slack,subnet,v_rated,v_target,volt_lvl +00d03670-7833-47ee-ad52-04d18d1c64fd,"{""type"":""Point"",""coordinates"":[7.4116482,51.4843281],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}",NS_Node_1,,,,false,2,0.4,1.0,Niederspannung +dfae9806-9b44-4995-ba27-d66d8e4a43e0,"{""type"":""Point"",""coordinates"":[7.4116482,51.4843281],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:0""}}}",NS_Node_2,,,,false,2,0.4,1.0,Niederspannung +34cd8ee0-e607-4c47-89a7-121c3e32768a,"{""type"":""Point"",""coordinates"":[7.4116482,51.4843281],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}",MS_Node_0,,,,true,1,20.0,1.025,Mittelspannung +401f37f8-6f2c-4564-bc78-6736cb9cbf8d,"{""type"":""Point"",""coordinates"":[7.4116482,51.4843281],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:0""}}}",NS_Node_4,,,,false,2,0.4,1.0,Niederspannung +33f29587-f63e-45b7-960b-037bda37a3cb,"{""type"":""Point"",""coordinates"":[7.4116482,51.4843281],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}",NS_Node_3,,,,false,2,0.4,1.0,Niederspannung diff --git a/input/samples/vn_simona_small_with_em/fullGrid/pv_input.csv b/input/samples/vn_simona_small_with_em/fullGrid/pv_input.csv new file mode 100644 index 0000000000..e418358125 --- /dev/null +++ b/input/samples/vn_simona_small_with_em/fullGrid/pv_input.csv @@ -0,0 +1,3 @@ +uuid,albedo,azimuth,cos_phi_rated,elevation_angle,eta_conv,id,k_g,k_t,market_reaction,node,operates_from,operates_until,operator,q_characteristics,s_rated,em +a1eb7fc1-3bee-4b65-a387-ef3046644bf0,0.20000000298023224,-8.999500274658203,0.8999999761581421,37.14517593383789,98.0,PV_NS_Node_4,0.8999999761581421,1.0,false,401f37f8-6f2c-4564-bc78-6736cb9cbf8d,,,,"cosPhiFixed:{(0.0,0.9)}",10.0,ff0b995a-86ff-4f4d-987e-e475a64f2180 +9d7cd8e2-d859-4f4f-9c01-abba06ef2e2c,0.20000000298023224,-14.803051948547363,0.8999999761581421,42.391395568847656,96.0,PV_NS_Node_3,0.8999999761581421,1.0,false,33f29587-f63e-45b7-960b-037bda37a3cb,,,,"cosPhiFixed:{(0.0,0.9)}",10.0,fd1a8de9-722a-4304-8799-e1e976d9979c diff --git a/input/samples/vn_simona_small_with_em/fullGrid/storage_input.csv b/input/samples/vn_simona_small_with_em/fullGrid/storage_input.csv new file mode 100644 index 0000000000..790f88b930 --- /dev/null +++ b/input/samples/vn_simona_small_with_em/fullGrid/storage_input.csv @@ -0,0 +1,2 @@ +uuid,id,node,operates_from,operates_until,operator,q_characteristics,type,em +a2a92cfd-3492-465f-9587-e789f4620af8,Speicher_3,33f29587-f63e-45b7-960b-037bda37a3cb,,,,"cosPhiFixed:{(0.0,0.98)}",95d4c980-d9e1-4813-9f2a-b0942488a570,fd1a8de9-722a-4304-8799-e1e976d9979c diff --git a/input/samples/vn_simona_small_with_em/fullGrid/storage_type_input.csv b/input/samples/vn_simona_small_with_em/fullGrid/storage_type_input.csv new file mode 100644 index 0000000000..31cce697f1 --- /dev/null +++ b/input/samples/vn_simona_small_with_em/fullGrid/storage_type_input.csv @@ -0,0 +1,2 @@ +uuid,active_power_gradient,capex,cos_phi_rated,dod,e_storage,eta,id,life_cycle,life_time,opex,p_max,s_rated +95d4c980-d9e1-4813-9f2a-b0942488a570,1.0,0.0,0.96,8.0,16.0,93.0,Typ_1,5000,5000.0,0.65,4.0,4.166666666666667 diff --git a/input/samples/vn_simona_small_with_em/fullGrid/transformer_2_w_input.csv b/input/samples/vn_simona_small_with_em/fullGrid/transformer_2_w_input.csv new file mode 100644 index 0000000000..9bb70380b6 --- /dev/null +++ b/input/samples/vn_simona_small_with_em/fullGrid/transformer_2_w_input.csv @@ -0,0 +1,2 @@ +uuid,auto_tap,id,node_a,node_b,operates_from,operates_until,operator,parallel_devices,tap_pos,type +d2a3736d-d10b-4f38-88cf-871df43e3665,true,HöS-Trafo_S1,34cd8ee0-e607-4c47-89a7-121c3e32768a,00d03670-7833-47ee-ad52-04d18d1c64fd,,,,1,0,97735722-05cc-4ca8-8a8d-c08ac3ded19a diff --git a/input/samples/vn_simona_small_with_em/fullGrid/transformer_2_w_type_input.csv b/input/samples/vn_simona_small_with_em/fullGrid/transformer_2_w_type_input.csv new file mode 100644 index 0000000000..0d2400e17e --- /dev/null +++ b/input/samples/vn_simona_small_with_em/fullGrid/transformer_2_w_type_input.csv @@ -0,0 +1,2 @@ +uuid,b_m,d_phi,d_v,g_m,id,r_sc,s_rated,tap_max,tap_min,tap_neutr,tap_side,v_rated_a,v_rated_b,x_sc +97735722-05cc-4ca8-8a8d-c08ac3ded19a,-36.47380569074435,0.0,2.5,4124.999999999999,0.63 MVA 20/0.4 kV Dyn5 ASEA,6.953892668178382,630.0,2,-2,0,false,20.0,0.4,37.45518044666632 diff --git a/input/samples/vn_simona_small_with_em/vn_simona_small_withem.conf b/input/samples/vn_simona_small_with_em/vn_simona_small_withem.conf new file mode 100644 index 0000000000..bc2c8b3451 --- /dev/null +++ b/input/samples/vn_simona_small_with_em/vn_simona_small_withem.conf @@ -0,0 +1,224 @@ +include "../common/pekko.conf" + +######### +# ATTENTION: Do not change this config file directly but use it as a base for your personal delta config for the +# vn_simona scenario! Delta configs can be created by including the config you want to change +# parameters from via include (e.g. include "input/samples/vn_simona/vn_simona.conf") at the +# beginning of your config file and then just override the parameters you want to change! +######### + +################################################################## +# Simulation Parameters +################################################################## +simona.simulationName = "simple_vn_simona_withem" + +################################################################## +# Time Parameters +################################################################## +simona.time.startDateTime = "2023-06-01T00:00:00Z" +simona.time.endDateTime = "2023-06-01T23:45:00Z" +simona.time.schedulerReadyCheckWindow = 900 + +################################################################## +# Input Parameters +################################################################## +simona.input.primary.csvParams = { + directoryPath: "simona/input/samples/vn_simona_small_with_em/fullGrid" + csvSep: "," + isHierarchic: false +} +simona.input.grid.datasource.id = "csv" +simona.input.grid.datasource.csvParams = { + directoryPath: "simona/input/samples/vn_simona_small_with_em/fullGrid" + csvSep: "," + isHierarchic: false +} + +simona.input.weather.datasource = { + scheme = "icon" + sampleParams.use = true + coordinateSource.sampleParams.use = true + maxCoordinateDistance = 50000 +} + +################################################################## +# Output Parameters +################################################################## +simona.output.base.dir = "simona/output/vn_simona_small_with_em" +simona.output.base.addTimestampToOutputDir = true + +simona.output.sink.csv { + fileFormat = ".csv" + filePrefix = "" + fileSuffix = "" +} + +simona.output.grid = { + notifier = "grid" + nodes = false + lines = false + switches = false + transformers2w = false + transformers3w = false +} +simona.output.participant.defaultConfig = { + notifier = "default" + powerRequestReply = false + simulationResult = true +} +simona.output.participant.individualConfigs = [ + { + notifier = "pv" + powerRequestReply = false + simulationResult = true + }, + { + notifier = "wec" + powerRequestReply = false + simulationResult = true + }, + { + notifier = "evcs" + powerRequestReply = false + simulationResult = true + }, + { + notifier = "storage" + powerRequestReply = false + simulationResult = true + } +] +simona.output.thermal = { + defaultConfig = { + notifier = "default", + simulationResult = false + } + individualConfigs = [ + { + notifier = "house", + simulationResult = true + } + ] +} + +################################################################## +# Runtime Configuration // todo refactor as this naming is misleading and partly unneeded +################################################################## +simona.runtime.selected_subgrids = [] +simona.runtime.selected_volt_lvls = [] + +simona.runtime.participant.load = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + modelBehaviour = "profile" + reference = "power" + } + individualConfigs = [] +} + +simona.runtime.participant.fixedFeedIn = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.pv = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.wec = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.evcs = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.hp = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +simona.runtime.participant.storage = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +# # # # # +# ATTENTION: calculateMissingReactivePowerWithModel and scaling is ignored here. +# # # # # +simona.runtime.participant.em = { + defaultConfig = { + calculateMissingReactivePowerWithModel = false + uuids = ["default"] + scaling = 1.0 + } + individualConfigs = [] +} + +################################################################## +# Event Configuration +################################################################## +simona.event.listener = [] + +################################################################## +# Grid Configuration +################################################################## + +simona.gridConfig.refSystems = [ + {sNom = "100 kVA", vNom = "0.4 kV", voltLvls = [{id = "LV", vNom = "0.4 kV"}]}, + {sNom = "60 MVA", vNom = "20 kV", voltLvls = [{id = "MV", vNom = "20 kV"}]}, + {sNom = "600 MVA", vNom = "110 kV", voltLvls = [{id = "HV", vNom = "110 kV"}]}, + {sNom = "1000 MVA", vNom = "380 kV", voltLvls = [{id = "EHV", vNom = "380 kV"}]} +] + +################################################################## +# Power Flow Configuration +################################################################## +simona.powerflow.maxSweepPowerDeviation = 1E-5 // the maximum allowed deviation in power between two sweeps, before overall convergence is assumed +simona.powerflow.newtonraphson.epsilon = [1E-12] +simona.powerflow.newtonraphson.iterations = 50 +simona.powerflow.resolution = "86400s" +simona.powerflow.stopOnFailure = true + +simona.control.transformer = [ + { + transformers = ["31a2b9bf-e785-4475-aa44-1c34646e8c79"], + measurements = ["923f2d69-3093-4198-86e4-13d2d1c220f8"], + vMin = 0.98, + vMax = 1.02 + }, { + transformers = ["1132dbf4-e8a1-44ae-8415-f42d4497aa1d"], + measurements = ["7686b818-a0ba-465c-8e4e-f7d3c4e171fc"], + vMin = 0.98, + vMax = 1.02 + } +] diff --git a/src/main/scala/edu/ie3/simona/agent/EnvironmentRefs.scala b/src/main/scala/edu/ie3/simona/agent/EnvironmentRefs.scala index 4b5c6c920d..3de35b171c 100644 --- a/src/main/scala/edu/ie3/simona/agent/EnvironmentRefs.scala +++ b/src/main/scala/edu/ie3/simona/agent/EnvironmentRefs.scala @@ -31,4 +31,5 @@ final case class EnvironmentRefs( primaryServiceProxy: ClassicRef, weather: ClassicRef, evDataService: Option[ClassicRef], + emDataService: Option[ClassicRef] ) diff --git a/src/main/scala/edu/ie3/simona/agent/em/EmAgent.scala b/src/main/scala/edu/ie3/simona/agent/em/EmAgent.scala index 06a7bf598a..848b429f62 100644 --- a/src/main/scala/edu/ie3/simona/agent/em/EmAgent.scala +++ b/src/main/scala/edu/ie3/simona/agent/em/EmAgent.scala @@ -8,29 +8,29 @@ package edu.ie3.simona.agent.em import edu.ie3.datamodel.models.input.EmInput import edu.ie3.datamodel.models.result.system.{EmResult, FlexOptionsResult} -import edu.ie3.simona.agent.participant.data.Data.PrimaryData.ApparentPower +import edu.ie3.simona.agent.participant.data.Data.PrimaryData.{ApparentPower, ZERO_POWER} import edu.ie3.simona.agent.participant.statedata.BaseStateData.FlexControlledData import edu.ie3.simona.config.SimonaConfig.EmRuntimeConfig import edu.ie3.simona.event.ResultEvent -import edu.ie3.simona.event.ResultEvent.{ - FlexOptionsResultEvent, - ParticipantResultEvent, -} +import edu.ie3.simona.event.ResultEvent.{FlexOptionsResultEvent, ParticipantResultEvent} import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.exceptions.CriticalFailureException import edu.ie3.simona.model.em.{EmModelShell, EmTools} -import edu.ie3.simona.ontology.messages.SchedulerMessage.{ - Completion, - ScheduleActivation, -} -import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage._ +import edu.ie3.simona.ontology.messages.SchedulerMessage.{Completion, ScheduleActivation} +import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage.{IssueFlexControl, _} import edu.ie3.simona.ontology.messages.flex.MinMaxFlexibilityMessage.ProvideMinMaxFlexOptions +import edu.ie3.simona.ontology.messages.services.ServiceMessage.ExtEmDataServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.WrappedRegistrationSuccessfulMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationSuccessfulMessage import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.util.TickUtil.TickLong import edu.ie3.util.quantities.QuantityUtils.RichQuantityDouble import edu.ie3.util.scala.quantities.DefaultQuantities._ -import org.apache.pekko.actor.typed.scaladsl.Behaviors +import org.apache.pekko.actor.typed.scaladsl.{Behaviors, StashBuffer} import org.apache.pekko.actor.typed.{ActorRef, Behavior} +import org.apache.pekko.actor.{ActorRef => ClassicRef} +import org.apache.pekko.actor.typed.scaladsl.adapter._ +import squants.Power import java.time.ZonedDateTime @@ -100,7 +100,19 @@ object EmAgent { simulationStartDate: ZonedDateTime, parent: Either[ActorRef[SchedulerMessage], ActorRef[FlexResponse]], listener: Iterable[ActorRef[ResultEvent]], + extEmDataService: Option[ClassicRef] ): Behavior[Request] = Behaviors.setup[Request] { ctx => + val flexAdapterEmDataService = ctx.messageAdapter[FlexRequest](Flex) + var extInitTick = Option.empty[Long] + if (extEmDataService.isDefined) { + extEmDataService.getOrElse(throw new RuntimeException("No Service")) ! ExtEmDataServiceRegistrationMessage( + inputModel.getUuid, + ctx.self, + flexAdapterEmDataService + ) + extInitTick = Some(0L) + } + val constantData = EmData( outputConfig, simulationStartDate, @@ -117,28 +129,31 @@ object EmAgent { FlexControlledData(parentEm, flexAdapter) } .left - .map { scheduler => - { - val activationAdapter = ctx.messageAdapter[Activation] { msg => - EmActivation(msg.tick) - } - SchedulerData(scheduler, activationAdapter) + .map { scheduler => { + val activationAdapter = ctx.messageAdapter[Activation] { msg => + EmActivation(msg.tick) } + SchedulerData(scheduler, activationAdapter) + } }, listener, + ExternalEmDataServiceData(extEmDataService) ) + val modelShell = EmModelShell( inputModel.getUuid, inputModel.getId, - modelStrategy, + inputModel.getControlStrategy, modelConfig, ) + ctx.log.debug(s"EMAgent ${modelShell.uuid} with $modelShell") + inactive( constantData, modelShell, - EmDataCore.create(simulationStartDate), + EmDataCore.create(simulationStartDate, extInitTick) ) } @@ -146,22 +161,36 @@ object EmAgent { * request to be activated. */ private def inactive( - emData: EmData, - modelShell: EmModelShell, - core: EmDataCore.Inactive, + emData: EmData, + modelShell: EmModelShell, + core: EmDataCore.Inactive, ): Behavior[Request] = Behaviors.receivePartial { - case (_, RegisterParticipant(model, actor, spi)) => + case (ctx, RegisterParticipant(model, actor, spi)) => + ctx.log.debug(s"EM Agent ${modelShell.uuid} RegisterParticipant model $model") val updatedModelShell = modelShell.addParticipant(model, spi) val updatedCore = core.addParticipant(actor, model) inactive(emData, updatedModelShell, updatedCore) - case (_, ScheduleFlexRequest(participant, newTick, scheduleKey)) => + case (ctx, WrappedRegistrationSuccessfulMessage(RegistrationSuccessfulMessage(serviceRef, nextDataTick))) => + ctx.log.info(s"EM Agent ${ctx.self} will use external set points!") + /* + val flexAdapter = ctx.messageAdapter[FlexRequest](Flex) + val updatedEmData = emData.copy( + parentData = Right(FlexControlledData(emData.extEmDataService.getOrElse(throw new RuntimeException("")).toTyped, flexAdapter)) + ) + */ + inactive(emData, modelShell, core) + + + case (ctx, ScheduleFlexRequest(participant, newTick, scheduleKey)) => + ctx.log.debug(s"EM Agent ${modelShell.uuid} got ScheduleFlexRequest!") val (maybeSchedule, newCore) = core .handleSchedule(participant, newTick) maybeSchedule match { case Some(scheduleTick) => + ctx.log.debug(s"EM Agent ${modelShell.uuid} -> parentData = ${emData.parentData}") // also potentially schedule with parent if the new earliest tick is // different from the old earliest tick (including if nothing had // been scheduled before) @@ -188,17 +217,45 @@ object EmAgent { inactive(emData, modelShell, newCore) case (ctx, msg: ActivationRequest) => - val flexOptionsCore = core.activate(msg.tick) + ctx.log.debug(s"\u001b[0;34m[${msg.tick}] ${ctx.self}.inactive got ActivationRequest = $msg, dataProvisionMessage = ${core.nextSetPointMessage}, nextSetPointTick = ${core.nextSetPointTick}\u001b[0;0m") msg match { - case Flex(_: RequestFlexOptions) | EmActivation(_) => - val (toActivate, newCore) = flexOptionsCore.takeNewFlexRequests() - toActivate.foreach { - _ ! RequestFlexOptions(msg.tick) + case Flex(_: RequestFlexOptions) | EmActivation(_) => // Activation by another EMAgent or by the scheduler + val flexOptionsCore = core.activate(msg.tick) + + // Check if there will be a new set point for this tick -> We can't start processing flex options before we know what's the set point for this tick + if (core.nextSetPointTick.contains(msg.tick)) { + // We expect a new set point for this tick + core.nextSetPointMessage match { + case Some(setPointMsg) => // We already got a set point, check if the set point is for the right tick + if (setPointMsg.tick == msg.tick) { // yes, it's for the right tick -> we can activate our connected agents and do the normal stuff + val (toActivate, newCore) = flexOptionsCore.handleSetPoint(setPointMsg).takeNewFlexRequests() + ctx.log.debug(s"\u001b[0;34m[${flexOptionsCore.activeTick}] ${ctx.self}.inactive expects and received set point for this tick\n -> activate connected agents $toActivate\n -> send IssuePowerControl to myself with the new set point ${setPointMsg.setPower} \u001b[0;0m") + toActivate.foreach { + _ ! RequestFlexOptions(msg.tick) + } + ctx.self ! Flex(IssuePowerControl(flexOptionsCore.activeTick, setPointMsg.setPower)) + awaitingFlexOptions(emData, modelShell, newCore) + } else { + throw new RuntimeException("Set point for wrong tick arrived!") + } + case _ => // We still have to wait for a set point + val (toActivate, newCore) = flexOptionsCore.takeNewFlexRequests() + ctx.log.debug(s"\u001b[0;34m[${flexOptionsCore.activeTick}] ${ctx.self}.inactive expects set point for this tick, but I have to wait..., toActivate = $toActivate\u001b[0;0m") + toActivate.foreach { + _ ! RequestFlexOptions(msg.tick) + } + awaitingFlexOptions(emData, modelShell, newCore) + } + } else { // We don't expect a new set point -> we can do our normal stuff, because we are activated because at least one connected agent should provide flex options + val (toActivate, newCore) = flexOptionsCore.updateSetPoint().takeNewFlexRequests() + ctx.log.debug(s"\u001b[0;34m[${flexOptionsCore.activeTick}] EM Agent ${ctx.self} doesn't expect set point for this tick, toActivate = $toActivate\u001b[0;0m") + toActivate.foreach { + _ ! RequestFlexOptions(msg.tick) + } + awaitingFlexOptions(emData, modelShell, newCore) } - awaitingFlexOptions(emData, modelShell, newCore) - case Flex(_: IssueFlexControl) => // We got sent a flex control message instead of a flex request, // this means that flex options must have not changed since @@ -206,9 +263,17 @@ object EmAgent { // Thus, we just jump to the appropriate place and forward the // control message there + val flexOptionsCore = core.activate(msg.tick) ctx.self ! msg awaitingFlexCtrl(emData, modelShell, flexOptionsCore) + + case Flex(msg: SetPointFlexRequest) => + // We didn't get an activation yet, but a set point arrived -> save message and wait for an activation + ctx.log.debug(s"(${core.getLastActiveTick}) ${ctx.self}.inactive got external set point = $msg before activation -> save message and wait...") + val newCore = core.handleSetPointMessage(msg) + + inactive(emData, modelShell, newCore) } } @@ -219,15 +284,17 @@ object EmAgent { private def awaitingFlexOptions( emData: EmData, modelShell: EmModelShell, - flexOptionsCore: EmDataCore.AwaitingFlexOptions, - ): Behavior[Request] = Behaviors.receiveMessagePartial { - case flexOptions: ProvideFlexOptions => + flexOptionsCore: EmDataCore.AwaitingFlexOptions + ): Behavior[Request] = Behaviors.receivePartial { + case (ctx, flexOptions: ProvideFlexOptions) => val updatedCore = flexOptionsCore.handleFlexOptions(flexOptions) if (updatedCore.isComplete) { val allFlexOptions = updatedCore.getFlexOptions + ctx.log.debug(s"EM Agent ${ctx.self} allFlexOptions = $allFlexOptions") + emData.parentData match { case Right(flexStateData) => // aggregate flex options and provide to parent @@ -271,9 +338,8 @@ object EmAgent { case Left(_) => // We're not em-controlled ourselves, - // always desire to come as close as possible to 0 kW - val setPower = zeroKW - + // always desire to come as close as possible to 0 kW -> maybe overwrite it if we get a set point + val setPower = updatedCore.currentSetPower.getOrElse(throw new CriticalFailureException("Uncontrolled agent received ProvideFlexOptions without a set point!")) val flexControl = modelShell.determineFlexControl(allFlexOptions, setPower) @@ -288,7 +354,6 @@ object EmAgent { awaitingCompletions(emData, modelShell, newCore) } - } else { // more flex options expected awaitingFlexOptions( @@ -302,6 +367,67 @@ object EmAgent { can schedule themselves with there completions and inactive agents should be sleeping right now */ + case (ctx, Flex(setPointMsg: SetPointFlexRequest)) => + // We got a set point after Activation -> Check, if setPower changed (yes) we have to calculate new set points for our connected agents (no) activate core and do the updates + ctx.log.info(s"\u001b[0;36m${flexOptionsCore.activeTick} ${ctx.self}.awaitingFlexOptions got external set point = $setPointMsg\u001b[0;0m") + val updatedCore = flexOptionsCore.handleSetPoint(setPointMsg) + ctx.self ! Flex(IssuePowerControl(flexOptionsCore.activeTick, setPointMsg.setPower)) + awaitingFlexCtrl(emData, modelShell, updatedCore) + + case (ctx, Flex(flexCtrl: IssuePowerControl)) => + ctx.log.debug(s"[${flexOptionsCore.activeTick}] ${ctx.self}.awaitingFlexOptions.IssuePowerControl received IssuePowerControl $flexCtrl") + if (flexOptionsCore.isComplete) { + ctx.log.debug(s"[${flexOptionsCore.activeTick}] ${ctx.self}.awaitingFlexOptions.IssuePowerControl core is already complete") + val allFlexOptions = flexOptionsCore.getFlexOptions + // We're not em-controlled ourselves, + // always desire to come as close as possible to 0 kW -> maybe overwrite it if we get a set point + val setPower = flexCtrl.setPower + + val flexControl = + modelShell.determineFlexControl(allFlexOptions, setPower) + + val (allFlexMsgs, newCore) = flexOptionsCore + .handleFlexCtrl(flexControl) + .fillInMissingIssueCtrl() + .complete() + + if(allFlexMsgs.isEmpty) { + newCore + .maybeComplete() + .map { inactiveCore => + sendCompletionCommunication( + emData, + modelShell, + inactiveCore, + flexOptionsCore.activeTick, + flexOptionsCore.nextSetPointTick + ) + inactive(emData, modelShell, inactiveCore) + } + .getOrElse { + // more flex options expected + awaitingCompletions( + emData, + modelShell, + newCore, + ) + } + } else { + allFlexMsgs.foreach { case (actor, msg) => + actor ! msg + } + + awaitingCompletions(emData, modelShell, newCore) + } + + } else { + ctx.log.debug(s"[${flexOptionsCore.activeTick}] ${ctx.self}.awaitingFlexOptions.IssuePowerControl there are still missing ProvideFlexOptions -> we have to wait...") + awaitingFlexOptions( + emData, + modelShell, + flexOptionsCore, + ) + } } /** Behavior of an [[EmAgent]] waiting for a flex control message to be @@ -312,8 +438,8 @@ object EmAgent { emData: EmData, modelShell: EmModelShell, flexOptionsCore: EmDataCore.AwaitingFlexOptions, - ): Behavior[Request] = Behaviors.receiveMessagePartial { - case Flex(flexCtrl: IssueFlexControl) => + ): Behavior[Request] = Behaviors.receivePartial { + case (ctx, Flex(flexCtrl: IssueFlexControl)) => val flexData = emData.parentData.getOrElse( throw new CriticalFailureException(s"EmAgent is not EM-controlled.") ) @@ -370,7 +496,8 @@ object EmAgent { emData, modelShell, inactiveCore, - lastActiveTick = updatedCore.activeTick, + updatedCore.activeTick, + updatedCore.nextSetPointTick ) inactive(emData, modelShell, inactiveCore) } @@ -390,6 +517,7 @@ object EmAgent { modelShell: EmModelShell, inactiveCore: EmDataCore.Inactive, lastActiveTick: Long, + nextSetPointTick: Option[Long], ): Unit = { // calc result val result = inactiveCore.getResults @@ -403,6 +531,11 @@ object EmAgent { ) ) + val nextActiveTick = EmTools.minOptionTicks( + inactiveCore.nextActiveTick, + nextSetPointTick + ) + emData.listener.foreach { _ ! ParticipantResultEvent( new EmResult( @@ -411,15 +544,18 @@ object EmAgent { modelShell.uuid, result.p.toMegawatts.asMegaWatt, result.q.toMegavars.asMegaVar, - ) + ), + tick = lastActiveTick, + nextTick = nextActiveTick ) } + emData.parentData.fold( schedulerData => schedulerData.scheduler ! Completion( schedulerData.activationAdapter, - inactiveCore.nextActiveTick, + nextActiveTick, ), _.emAgent ! FlexCtrlCompletion( modelShell.uuid, @@ -447,6 +583,7 @@ object EmAgent { simulationStartDate: ZonedDateTime, parentData: Either[SchedulerData, FlexControlledData], listener: Iterable[ActorRef[ResultEvent]], + extEmDataServiceData: ExternalEmDataServiceData ) /** The existence of this data object indicates that the corresponding agent @@ -461,5 +598,10 @@ object EmAgent { final case class SchedulerData( scheduler: ActorRef[SchedulerMessage], activationAdapter: ActorRef[Activation], + lastFlexOptions: Option[ProvideFlexOptions] = None, ) + + final case class ExternalEmDataServiceData( + extEmDataService: Option[ClassicRef] + ) } diff --git a/src/main/scala/edu/ie3/simona/agent/em/EmDataCore.scala b/src/main/scala/edu/ie3/simona/agent/em/EmDataCore.scala index 3b46b176ee..5ad3743bf6 100644 --- a/src/main/scala/edu/ie3/simona/agent/em/EmDataCore.scala +++ b/src/main/scala/edu/ie3/simona/agent/em/EmDataCore.scala @@ -12,6 +12,7 @@ import EmAgent.Actor import FlexCorrespondenceStore.WithTime import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage._ import edu.ie3.util.scala.collection.mutable.PriorityMultiBiSet +import edu.ie3.util.scala.quantities.DefaultQuantities.zeroKW import squants.Power import java.time.ZonedDateTime @@ -27,13 +28,16 @@ object EmDataCore { * @param startDate * The start date of the simulation */ - def create(implicit startDate: ZonedDateTime): Inactive = + def create(implicit startDate: ZonedDateTime, extInitTick: Option[Long]): Inactive = Inactive( Map.empty, PriorityMultiBiSet.empty, Set.empty, FlexCorrespondenceStore(), None, + extInitTick, + zeroKW, + None ) /** Data structure holding relevant data and providing methods that handle @@ -59,6 +63,9 @@ object EmDataCore { private val flexWithNext: Set[UUID], private val correspondences: FlexCorrespondenceStore, private val lastActiveTick: Option[Long], + nextSetPointTick: Option[Long], + lastSetPower: Power, + nextSetPointMessage: Option[SetPointFlexRequest] ) { /** Adds a connected agent, given its model UUID and actor reference @@ -109,6 +116,9 @@ object EmDataCore { updatedQueue, correspondences, activeTick = newTick, + nextSetPointTick = nextSetPointTick, + lastSetPower = lastSetPower, + currentSetPower = None, ) } @@ -165,6 +175,13 @@ object EmDataCore { def getResults: Iterable[ApparentPower] = correspondences.store.values.flatMap(_.receivedResult.map(_.get)) + def handleSetPointMessage( + setPointMsg: SetPointFlexRequest + ): Inactive = copy( + nextSetPointMessage = Some(setPointMsg) + ) + + def getLastActiveTick: Option[Long] = lastActiveTick } /** Data structure holding relevant data and providing methods that handle @@ -189,17 +206,22 @@ object EmDataCore { private val correspondences: FlexCorrespondenceStore, private val awaitedFlexOptions: Set[UUID] = Set.empty, activeTick: Long, + nextSetPointTick: Option[Long], + lastSetPower: Power, + currentSetPower: Option[Power] ) { + def getCorrespondences: FlexCorrespondenceStore = correspondences + /** Removes and returns flex requests scheduled for the current tick, which - * can be sent out at the current moment. - * - * @return - * A tuple of a collection of agents scheduled for the current tick, and - * the updated [[AwaitingFlexOptions]] core - * @throws CriticalFailureException - * on critical error - */ + * can be sent out at the current moment. + * + * @return + * A tuple of a collection of agents scheduled for the current tick, and + * the updated [[AwaitingFlexOptions]] core + * @throws CriticalFailureException + * on critical error + */ def takeNewFlexRequests(): (Iterable[Actor], AwaitingFlexOptions) = { val toActivate = activationQueue.getAndRemoveSet(activeTick) val newFlexOptionsCore = @@ -219,16 +241,16 @@ object EmDataCore { } /** Handles the retrieval of flex options sent by some connected agent for - * the currently active tick. - * - * @param flexOptions - * The received flex options - * @return - * The updated [[AwaitingFlexOptions]] core - */ + * the currently active tick. + * + * @param flexOptions + * The received flex options + * @return + * The updated [[AwaitingFlexOptions]] core + */ def handleFlexOptions( - flexOptions: ProvideFlexOptions - ): AwaitingFlexOptions = + flexOptions: ProvideFlexOptions + ): AwaitingFlexOptions = copy( correspondences = correspondences.updateFlexOptions(flexOptions, activeTick), @@ -236,33 +258,35 @@ object EmDataCore { ) /** Checks whether all awaited flex options have been received and we can - * continue by calculating flex control. This method does not change the - * state of the [[AwaitingFlexOptions]] data core. - * @return - * true if all awaited flex options have been received - */ - def isComplete: Boolean = awaitedFlexOptions.isEmpty + * continue by calculating flex control. This method does not change the + * state of the [[AwaitingFlexOptions]] data core. + * + * @return + * true if all awaited flex options have been received + */ + def isComplete: Boolean = awaitedFlexOptions.isEmpty & currentSetPower.isDefined /** Returns all flex options that are currently relevant, which can include - * flex options received at an earlier tick - * @return - * all relevant flex options - */ + * flex options received at an earlier tick + * + * @return + * all relevant flex options + */ def getFlexOptions: Iterable[(UUID, ProvideFlexOptions)] = correspondences.store.flatMap { case (model, correspondence) => correspondence.receivedFlexOptions.map(model -> _.get) } /** Handles and stores the control messages created by this [[EmAgent]] - * - * @param ctrlMsgs - * The control messages created by this EM agent - * @return - * The updated [[AwaitingFlexOptions]] core - */ + * + * @param ctrlMsgs + * The control messages created by this EM agent + * @return + * The updated [[AwaitingFlexOptions]] core + */ def handleFlexCtrl( - ctrlMsgs: Iterable[(UUID, Power)] - ): AwaitingFlexOptions = { + ctrlMsgs: Iterable[(UUID, Power)] + ): AwaitingFlexOptions = { val updatedStore = ctrlMsgs.foldLeft(correspondences) { case (store, (model, power)) => val ctrlMsg = IssuePowerControl(activeTick, power) @@ -272,12 +296,13 @@ object EmDataCore { } /** The model strategy might miss control messages when creating them in - * bulk. This method creates the missing messages, in particular for those - * agents that have been issued a flex request for the current tick and - * those that have received a control messages at an earlier tick. - * @return - * The updated [[AwaitingFlexOptions]] core - */ + * bulk. This method creates the missing messages, in particular for those + * agents that have been issued a flex request for the current tick and + * those that have received a control messages at an earlier tick. + * + * @return + * The updated [[AwaitingFlexOptions]] core + */ def fillInMissingIssueCtrl(): AwaitingFlexOptions = { val updatedStore = correspondences.store .filter { case (_, correspondence) => @@ -296,7 +321,7 @@ object EmDataCore { // at an earlier tick val flexControlCancelled = correspondence.issuedCtrlMsg match { case Some(WithTime(_: IssuePowerControl, tick)) - if tick < activeTick => + if tick < activeTick => true case _ => false } @@ -313,17 +338,17 @@ object EmDataCore { } /** Completes the current state by collecting and returning the control - * messages for the current tick if possible, and otherwise a - * [[CriticalFailureException]] is thrown - * - * @return - * A collection of agent-and-message pairs and an updated - * [[AwaitingCompletions]] core - * @throws CriticalFailureException - * on critical error - */ + * messages for the current tick if possible, and otherwise a + * [[CriticalFailureException]] is thrown + * + * @return + * A collection of agent-and-message pairs and an updated + * [[AwaitingCompletions]] core + * @throws CriticalFailureException + * on critical error + */ def complete() - : (Iterable[(Actor, IssueFlexControl)], AwaitingCompletions) = { + : (Iterable[(Actor, IssueFlexControl)], AwaitingCompletions) = { val modelUuidToMsg = correspondences.store.flatMap { case (modelUuid, correspondence) => @@ -354,10 +379,26 @@ object EmDataCore { participant }.toSet, activeTick = activeTick, + nextSetPointTick = nextSetPointTick, + currentSetPower = currentSetPower.getOrElse(throw new RuntimeException("")) ), ) } + def handleSetPoint( + setPointFlexRequest: SetPointFlexRequest + ): AwaitingFlexOptions = { + copy( + nextSetPointTick = Some(setPointFlexRequest.nextSetPointTick), + currentSetPower = Some(setPointFlexRequest.setPower) + ) + } + + def updateSetPoint(): AwaitingFlexOptions = { + copy( + currentSetPower = Some(lastSetPower) + ) + } } /** Data structure holding relevant data and providing methods that handle @@ -387,6 +428,8 @@ object EmDataCore { private val correspondences: FlexCorrespondenceStore, private val awaitedCompletions: Set[UUID], activeTick: Long, + nextSetPointTick: Option[Long], + currentSetPower: Power ) { /** Tries to handle the completion of some connected agent for the currently @@ -452,9 +495,10 @@ object EmDataCore { flexWithNext, correspondences, Some(activeTick), + nextSetPointTick, + currentSetPower, + None ) } - } - } diff --git a/src/main/scala/edu/ie3/simona/agent/grid/GridAgent.scala b/src/main/scala/edu/ie3/simona/agent/grid/GridAgent.scala index f02d7c36b1..08ef649b5e 100644 --- a/src/main/scala/edu/ie3/simona/agent/grid/GridAgent.scala +++ b/src/main/scala/edu/ie3/simona/agent/grid/GridAgent.scala @@ -210,7 +210,8 @@ object GridAgent extends DBFSAlgorithm { constantData: GridAgentConstantData, buffer: StashBuffer[Request], ): Behavior[Request] = Behaviors.receivePartial { - case (_, WrappedActivation(activation: Activation)) => + case (ctx, WrappedActivation(activation: Activation)) => + ctx.log.info(s"Activation in tick ${activation.tick}") constantData.environmentRefs.scheduler ! Completion( constantData.activationAdapter, Some(activation.tick), diff --git a/src/main/scala/edu/ie3/simona/agent/grid/GridAgentController.scala b/src/main/scala/edu/ie3/simona/agent/grid/GridAgentController.scala index 393e7417e7..e86d914bfe 100644 --- a/src/main/scala/edu/ie3/simona/agent/grid/GridAgentController.scala +++ b/src/main/scala/edu/ie3/simona/agent/grid/GridAgentController.scala @@ -191,14 +191,21 @@ class GridAgentController( _.getControllingEm.toScala.map(em => em.getUuid -> em) }.toMap + //log.info(s"firstLevelEms = $firstLevelEms") + val allEms = buildEmsRecursively( participantConfigUtil, outputConfigUtil, firstLevelEms, + extEmDataService = environmentRefs.emDataService ) + //log.info(s"Built allEms = $allEms") + //log.info(s"Particpants = $participants") + participants .map { participant => + //log.info(s"Built Participant = $participant") val node = participant.getNode val controllingEm = @@ -252,6 +259,7 @@ class GridAgentController( outputConfigUtil: OutputConfigUtil, emInputs: Map[UUID, EmInput], previousLevelEms: Map[UUID, ActorRef[FlexResponse]] = Map.empty, + extEmDataService: Option[ClassicRef] = None ): Map[UUID, ActorRef[FlexResponse]] = { // For the current level, split controlled and uncontrolled EMs. // Uncontrolled EMs can be built right away. @@ -273,6 +281,9 @@ class GridAgentController( val previousLevelAndUncontrolledEms = previousLevelEms ++ uncontrolledEms.toMap + //log.info(s"controlledEmInputs = $controlledEmInputs") + //log.info(s"previousLevelAndUncontrolledEms = $previousLevelAndUncontrolledEms") + if (controlledEmInputs.nonEmpty) { // For controlled EMs at the current level, more EMs // might need to be built at the next recursion level. @@ -280,16 +291,20 @@ class GridAgentController( case (uuid, emInput) => emInput.getControllingEm.toScala.map(uuid -> _) } - + //log.info(s"now build controlled Ems -> These are possible controllers = $controllingEms") // Return value includes previous level and uncontrolled EMs of this level val recursiveEms = buildEmsRecursively( participantConfigUtil, outputConfigUtil, controllingEms, previousLevelAndUncontrolledEms, + extEmDataService = extEmDataService ) + //log.info(s"-> after recursion recursiveEms = $recursiveEms") val controlledEms = controlledEmInputs.map { case (uuid, emInput) => + //log.info(s"-> uuid = $uuid, emInput = $emInput") + /* val controllingEm = emInput.getControllingEm.toScala .map(_.getUuid) .map(uuid => @@ -301,6 +316,15 @@ class GridAgentController( ) ) + */ + val controllingEm = Some(recursiveEms.getOrElse( + uuid, + throw new CriticalFailureException( + s"Actor for EM $uuid not found." + ), + )) + //log.info(s"-> contorllingEm = $controllingEm") + uuid -> buildEm( emInput, participantConfigUtil.getOrDefault[EmRuntimeConfig](uuid), @@ -308,7 +332,7 @@ class GridAgentController( maybeControllingEm = controllingEm, ) }.toMap - + //log.info(s"-> controlledEms = $controlledEms, recursiveEms = $recursiveEms") recursiveEms ++ controlledEms } else { previousLevelAndUncontrolledEms @@ -871,7 +895,8 @@ class GridAgentController( modelConfiguration: EmRuntimeConfig, outputConfig: NotifierConfig, maybeControllingEm: Option[ActorRef[FlexResponse]], - ): ActorRef[FlexResponse] = + ): ActorRef[FlexResponse] = { + //log.info("Spawn Em = " + emInput + ", maybeControlling Em = " + maybeControllingEm) gridAgentContext.spawn( EmAgent( emInput, @@ -885,9 +910,11 @@ class GridAgentController( environmentRefs.scheduler ), listener, + environmentRefs.emDataService ), actorName(classOf[EmAgent.type], emInput.getId), ) + } /** Introduces the given agent to scheduler * diff --git a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala index e636872833..f15532e6d1 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala @@ -142,8 +142,8 @@ protected trait ParticipantAgentFundamentals[ /* Confirm final initialization */ releaseTick() - senderToMaybeTick._2.foreach { tick => - scheduler ! Completion(self.toTyped, Some(tick)) + senderToMaybeTick match { case (_, maybeTick) => + scheduler ! Completion(self.toTyped, maybeTick) } goto(Idle) using stateData } @@ -539,8 +539,13 @@ protected trait ParticipantAgentFundamentals[ msg.unlockKey, ) } - case _ => - false + + case _: FromOutsideBaseStateData[_, _] => + scheduler ! ScheduleActivation( + self.toTyped, + msg.tick, + msg.unlockKey, + ) } } @@ -1789,15 +1794,17 @@ protected trait ParticipantAgentFundamentals[ baseStateData: BaseStateData[PD], tick: Long, result: AccompaniedSimulationResult[PD], - )(implicit outputConfig: NotifierConfig): Unit = + )(implicit outputConfig: NotifierConfig): Unit = { if (outputConfig.simulationResultInfo) { + val (nextTick, _) = popNextActivationTrigger(baseStateData) notifyListener( - buildResultEvent(baseStateData, tick, result.primaryData) + buildResultEvent(baseStateData, tick, result.primaryData, nextTick) ) result.accompanyingResults .flatMap(result => buildResultEvent(result)) .foreach(notifyListener(_)) } + } /** Update the result value store, inform all registered listeners and go to * Idle using the updated base state data @@ -1920,11 +1927,14 @@ protected trait ParticipantAgentFundamentals[ baseStateData: BaseStateData[PD], tick: Long, result: PD, + nextTick: Option[Long] = None ): ParticipantResultEvent = { val uuid = baseStateData.modelUuid val dateTime = tick.toDateTime(baseStateData.startDate) ParticipantResultEvent( - buildResult(uuid, dateTime, result) + buildResult(uuid, dateTime, result), + tick, + nextTick ) } diff --git a/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala b/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala index b71adf4a30..53e5c05550 100644 --- a/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala +++ b/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala @@ -6,27 +6,19 @@ package edu.ie3.simona.api -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.actor.{Actor, ActorRef, PoisonPill, Props} import edu.ie3.simona.api.ExtSimAdapter.{Create, ExtSimAdapterStateData, Stop} import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage import edu.ie3.simona.api.simulation.ExtSimAdapterData -import edu.ie3.simona.api.simulation.ontology.{ - ActivationMessage, - TerminationCompleted, - TerminationMessage, - CompletionMessage => ExtCompletionMessage, -} +import edu.ie3.simona.api.simulation.ontology.{ActivationMessage, TerminationCompleted, TerminationMessage, CompletionMessage => ExtCompletionMessage} import edu.ie3.simona.logging.SimonaActorLogging -import edu.ie3.simona.ontology.messages.SchedulerMessage.{ - Completion, - ScheduleActivation, -} -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.ScheduleServiceActivation import edu.ie3.simona.ontology.messages.Activation +import edu.ie3.simona.ontology.messages.SchedulerMessage.{Completion, ScheduleActivation} +import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.ScheduleServiceActivation import edu.ie3.simona.scheduler.ScheduleLock import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps +import org.apache.pekko.actor.{Actor, ActorRef, PoisonPill, Props} import scala.jdk.OptionConverters._ @@ -43,12 +35,13 @@ object ExtSimAdapter { * @param extSimData * The [[ExtSimAdapterData]] of the corresponding external simulation */ - final case class Create(extSimData: ExtSimAdapterData, unlockKey: ScheduleKey) + final case class Create(extSimData: ExtSimAdapterData, phase: Int, unlockKey: ScheduleKey) final case class Stop(simulationSuccessful: Boolean) final case class ExtSimAdapterStateData( extSimData: ExtSimAdapterData, + phase: Int, currentTick: Option[Long] = None, ) } @@ -56,7 +49,7 @@ object ExtSimAdapter { final case class ExtSimAdapter(scheduler: ActorRef) extends Actor with SimonaActorLogging { - override def receive: Receive = { case Create(extSimAdapterData, unlockKey) => + override def receive: Receive = { case Create(extSimAdapterData, phase, unlockKey) => // triggering first time at init tick scheduler ! ScheduleActivation( self.toTyped, @@ -64,7 +57,7 @@ final case class ExtSimAdapter(scheduler: ActorRef) Some(unlockKey), ) context become receiveIdle( - ExtSimAdapterStateData(extSimAdapterData) + ExtSimAdapterStateData(extSimAdapterData, phase) ) } @@ -73,7 +66,7 @@ final case class ExtSimAdapter(scheduler: ActorRef) ): Receive = { case Activation(tick) => stateData.extSimData.queueExtMsg( - new ActivationMessage(tick) + new ActivationMessage(tick, stateData.phase) ) log.debug( "Tick {} has been activated in external simulation", @@ -112,7 +105,7 @@ final case class ExtSimAdapter(scheduler: ActorRef) case Stop(simulationSuccessful) => // let external sim know that we have terminated stateData.extSimData.queueExtMsg( - new TerminationMessage(simulationSuccessful) + new TerminationMessage(simulationSuccessful, stateData.phase) ) case _: TerminationCompleted => diff --git a/src/main/scala/edu/ie3/simona/config/ArgsParser.scala b/src/main/scala/edu/ie3/simona/config/ArgsParser.scala index 183aa8149c..8629d3dd2e 100644 --- a/src/main/scala/edu/ie3/simona/config/ArgsParser.scala +++ b/src/main/scala/edu/ie3/simona/config/ArgsParser.scala @@ -31,6 +31,8 @@ object ArgsParser extends LazyLogging { seedAddress: Option[String] = None, useLocalWorker: Option[Boolean] = None, tArgs: Map[String, String] = Map.empty, + extAddress: Option[String] = None, + mappingPath: Option[String] = None ) { val useCluster: Boolean = clusterType.isDefined } @@ -102,6 +104,24 @@ object ArgsParser extends LazyLogging { "If cluster is specified then this defaults to false and must be explicitly set to true. " + "NOTE: For cluster, this will ONLY be checked if cluster-type=master" ) + opt[String]("ext-address") + .action((value, args) => args.copy(extAddress = Option(value))) + .validate(value => + if (value.trim.isEmpty) failure("ext-address cannot be empty") + else success + ) + .text( + "Comma separated list (no whitespaces!) of initial addresses used for the rest of the cluster to bootstrap" + ) + opt[String]("mapping-path") + .action((value, args) => args.copy(mappingPath = Option(value))) + .validate(value => + if (value.trim.isEmpty) failure("ext-address cannot be empty") + else success + ) + .text( + "Comma separated list (no whitespaces!) of initial addresses used for the rest of the cluster to bootstrap" + ) checkConfig(args => if ( diff --git a/src/main/scala/edu/ie3/simona/event/ResultEvent.scala b/src/main/scala/edu/ie3/simona/event/ResultEvent.scala index d81242c608..ce5879cbaa 100644 --- a/src/main/scala/edu/ie3/simona/event/ResultEvent.scala +++ b/src/main/scala/edu/ie3/simona/event/ResultEvent.scala @@ -33,7 +33,9 @@ object ResultEvent { * the calculation result */ final case class ParticipantResultEvent( - systemParticipantResult: SystemParticipantResult + systemParticipantResult: SystemParticipantResult, + tick: Long = -2L, + nextTick: Option[Long] = None ) extends ResultEvent /** Event, that is triggered every time a thermal model has a new result @@ -66,6 +68,7 @@ object ResultEvent { lineResults: Iterable[LineResult], transformer2wResults: Iterable[Transformer2WResult], transformer3wResults: Iterable[PartialTransformer3wResult], + tick: Long = -4L ) extends ResultEvent /** Event that holds the flexibility options result of a diff --git a/src/main/scala/edu/ie3/simona/event/listener/DelayedStopHelper.scala b/src/main/scala/edu/ie3/simona/event/listener/DelayedStopHelper.scala index c6d8cea4d5..13225a4dcf 100644 --- a/src/main/scala/edu/ie3/simona/event/listener/DelayedStopHelper.scala +++ b/src/main/scala/edu/ie3/simona/event/listener/DelayedStopHelper.scala @@ -6,6 +6,7 @@ package edu.ie3.simona.event.listener +import edu.ie3.simona.service.results.ExtResultDataProvider import org.apache.pekko.actor.typed.Behavior import org.apache.pekko.actor.typed.scaladsl.{ActorContext, Behaviors} @@ -23,6 +24,7 @@ object DelayedStopHelper { sealed trait StoppingMsg extends ResultEventListener.Request with RuntimeEventListener.Request + with ExtResultDataProvider.Request /** Message indicating that [[RuntimeEventListener]] should stop. Instead of * using [[org.apache.pekko.actor.typed.scaladsl.ActorContext.stop]], this @@ -37,7 +39,7 @@ object DelayedStopHelper { : PartialFunction[(ActorContext[T], StoppingMsg), Behavior[T]] = { case (ctx, FlushAndStop) => - ctx.log.debug( + ctx.log.info( s"Received FlushAndStop message, shutting down once no message has been received for 5 seconds." ) ctx.setReceiveTimeout(5.seconds, StopTimeout) @@ -45,7 +47,7 @@ object DelayedStopHelper { case (ctx, StopTimeout) => // there have been no messages for 5 seconds, let's end this - ctx.log.debug(s"${getClass.getSimpleName} is now stopped.") + ctx.log.info(s"${getClass.getSimpleName} is now stopped.") Behaviors.stopped } diff --git a/src/main/scala/edu/ie3/simona/event/listener/ResultEventListener.scala b/src/main/scala/edu/ie3/simona/event/listener/ResultEventListener.scala index d5acf17912..6f954fc388 100644 --- a/src/main/scala/edu/ie3/simona/event/listener/ResultEventListener.scala +++ b/src/main/scala/edu/ie3/simona/event/listener/ResultEventListener.scala @@ -7,21 +7,15 @@ package edu.ie3.simona.event.listener import org.apache.pekko.actor.typed.scaladsl.Behaviors -import org.apache.pekko.actor.typed.{Behavior, PostStop} +import org.apache.pekko.actor.typed.{ActorRef, Behavior, PostStop} import edu.ie3.datamodel.io.processor.result.ResultEntityProcessor -import edu.ie3.datamodel.models.result.{NodeResult, ResultEntity} +import edu.ie3.datamodel.models.result.{ModelResultEntity, NodeResult, ResultEntity} import edu.ie3.simona.agent.grid.GridResultsSupport.PartialTransformer3wResult -import edu.ie3.simona.event.ResultEvent.{ - FlexOptionsResultEvent, - ParticipantResultEvent, - PowerFlowResultEvent, - ThermalResultEvent, -} -import edu.ie3.simona.exceptions.{ - FileHierarchyException, - ProcessResultEventException, -} +import edu.ie3.simona.event.ResultEvent.{FlexOptionsResultEvent, ParticipantResultEvent, PowerFlowResultEvent, ThermalResultEvent} +import edu.ie3.simona.exceptions.{FileHierarchyException, ProcessResultEventException} import edu.ie3.simona.io.result._ +import edu.ie3.simona.service.results.ExtResultDataProvider +import edu.ie3.simona.service.results.ExtResultDataProvider.ResultResponseMessage import edu.ie3.simona.util.ResultFileHierarchy import org.slf4j.Logger @@ -46,9 +40,12 @@ object ResultEventListener extends Transformer3wResultSupport { * @param classToSink * a map containing the sink for each class that should be processed by the * listener + * @param extResultDataService + * actor for the external data service */ private final case class BaseData( classToSink: Map[Class[_], ResultEntitySink], + extResultDataService: Option[ActorRef[ExtResultDataProvider.Request]], threeWindingResults: Map[ Transformer3wKey, AggregatedTransformer3wResult, @@ -152,8 +149,19 @@ object ResultEventListener extends Transformer3wResultSupport { resultEntity: ResultEntity, baseData: BaseData, log: Logger, + tick: Long = -2L, + nextTick: Option[Long] = None ): BaseData = { + //log.info("Got Result " + resultEntity) handOverToSink(resultEntity, baseData.classToSink, log) + if (baseData.extResultDataService.isDefined) { + handOverToExternalService( + tick, + resultEntity, + baseData.extResultDataService, + nextTick + ) + } baseData } @@ -228,8 +236,26 @@ object ResultEventListener extends Transformer3wResultSupport { log.error("Error while writing result event: ", exception) } + private def handOverToExternalService( + tick: Long, + resultEntity: ResultEntity, + extResultDataService: Option[ActorRef[ExtResultDataProvider.Request]], + nextTick: Option[Long] = None + ): Unit = Try { + val extResultDataServiceRef = extResultDataService.getOrElse( + throw new Exception("No external data service registered!") + ) + resultEntity match { + case modelResultEntity: ModelResultEntity => + extResultDataServiceRef ! ResultResponseMessage(modelResultEntity, tick, nextTick) + case _ => + throw new Exception("Wrong data type!") + } + } + def apply( - resultFileHierarchy: ResultFileHierarchy + resultFileHierarchy: ResultFileHierarchy, + extResultDataService: Option[ActorRef[ExtResultDataProvider.Request]] = Option.empty[ActorRef[ExtResultDataProvider.Request]], ): Behavior[Request] = Behaviors.setup[Request] { ctx => ctx.log.debug("Starting initialization!") resultFileHierarchy.resultSinkType match { @@ -253,14 +279,16 @@ object ResultEventListener extends Transformer3wResultSupport { case Success(result) => SinkResponse(result.toMap) } - init() + init(extResultDataService) } - private def init(): Behavior[Request] = Behaviors.withStash(200) { buffer => + private def init( + extResultDataService: Option[ActorRef[ExtResultDataProvider.Request]] + ): Behavior[Request] = Behaviors.withStash(200) { buffer => Behaviors.receive[Request] { case (ctx, SinkResponse(response)) => ctx.log.debug("Initialization complete!") - buffer.unstashAll(idle(BaseData(response))) + buffer.unstashAll(idle(BaseData(response, extResultDataService))) case (ctx, InitFailed(ex)) => ctx.log.error("Unable to setup ResultEventListener.", ex) @@ -275,8 +303,8 @@ object ResultEventListener extends Transformer3wResultSupport { private def idle(baseData: BaseData): Behavior[Request] = Behaviors .receivePartial[Request] { - case (ctx, ParticipantResultEvent(participantResult)) => - val updatedBaseData = handleResult(participantResult, baseData, ctx.log) + case (ctx, ParticipantResultEvent(participantResult, tick, nextTick)) => + val updatedBaseData = handleResult(participantResult, baseData, ctx.log, tick, nextTick) idle(updatedBaseData) case (ctx, ThermalResultEvent(thermalResult)) => @@ -291,13 +319,14 @@ object ResultEventListener extends Transformer3wResultSupport { lineResults, transformer2wResults, transformer3wResults, + tick ), ) => val updatedBaseData = (nodeResults ++ switchResults ++ lineResults ++ transformer2wResults ++ transformer3wResults) .foldLeft(baseData) { case (currentBaseData, resultEntity: ResultEntity) => - handleResult(resultEntity, currentBaseData, ctx.log) + handleResult(resultEntity, currentBaseData, ctx.log, tick) case ( currentBaseData, partialTransformerResult: PartialTransformer3wResult, @@ -311,7 +340,7 @@ object ResultEventListener extends Transformer3wResultSupport { idle(updatedBaseData) case (ctx, FlexOptionsResultEvent(flexOptionsResult)) => - val updatedBaseData = handleResult(flexOptionsResult, baseData, ctx.log) + val updatedBaseData = handleResult(flexOptionsResult, baseData, ctx.log, -3L) idle(updatedBaseData) case (ctx, msg: DelayedStopHelper.StoppingMsg) => diff --git a/src/main/scala/edu/ie3/simona/io/result/ResultEntityKafkaSink.scala b/src/main/scala/edu/ie3/simona/io/result/ResultEntityKafkaSink.scala index 3effd9dd2d..89c56fa6a8 100644 --- a/src/main/scala/edu/ie3/simona/io/result/ResultEntityKafkaSink.scala +++ b/src/main/scala/edu/ie3/simona/io/result/ResultEntityKafkaSink.scala @@ -13,11 +13,7 @@ import edu.ie3.simona.io.result.plain.PlainWriter.NodeResultWriter import edu.ie3.simona.io.result.plain.{PlainResult, PlainWriter} import edu.ie3.util.scala.io.ScalaReflectionSerde.reflectionSerializer4S import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig.SCHEMA_REGISTRY_URL_CONFIG -import org.apache.kafka.clients.producer.{ - KafkaProducer, - ProducerConfig, - ProducerRecord, -} +import org.apache.kafka.clients.producer.{KafkaProducer, ProducerConfig, ProducerRecord} import org.apache.kafka.common.serialization.{Serdes, Serializer} import java.util.{Properties, UUID} diff --git a/src/main/scala/edu/ie3/simona/io/runtime/RuntimeEventKafkaSink.scala b/src/main/scala/edu/ie3/simona/io/runtime/RuntimeEventKafkaSink.scala index 4698d25215..2ca358109a 100644 --- a/src/main/scala/edu/ie3/simona/io/runtime/RuntimeEventKafkaSink.scala +++ b/src/main/scala/edu/ie3/simona/io/runtime/RuntimeEventKafkaSink.scala @@ -14,11 +14,7 @@ import edu.ie3.simona.io.runtime.RuntimeEventKafkaSink.SimonaEndMessage import edu.ie3.simona.io.runtime.RuntimeEventSink.RuntimeStats import edu.ie3.util.scala.io.ScalaReflectionSerde.reflectionSerializer4S import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig.SCHEMA_REGISTRY_URL_CONFIG -import org.apache.kafka.clients.producer.{ - KafkaProducer, - ProducerConfig, - ProducerRecord, -} +import org.apache.kafka.clients.producer.{KafkaProducer, ProducerConfig, ProducerRecord} import org.apache.kafka.common.serialization.{Serdes, Serializer} import org.slf4j.Logger diff --git a/src/main/scala/edu/ie3/simona/io/runtime/RuntimeEventLogSink.scala b/src/main/scala/edu/ie3/simona/io/runtime/RuntimeEventLogSink.scala index 2af82e5589..26f7714536 100644 --- a/src/main/scala/edu/ie3/simona/io/runtime/RuntimeEventLogSink.scala +++ b/src/main/scala/edu/ie3/simona/io/runtime/RuntimeEventLogSink.scala @@ -38,12 +38,12 @@ final case class RuntimeEventLogSink( case InitComplete(duration) => log.info( - s"Initialization complete. (duration: ${convertDuration(duration)} )" + s"\u001b[0;32mInitialization complete. (duration: ${convertDuration(duration)})\u001b[0;0m" ) case CheckWindowPassed(tick, duration) => log.info( - s"******* Simulation until ${calcTime(tick)} completed. ${durationAndMemoryString(duration)} ******" + s"\u001b[0;32m******* Simulation until ${calcTime(tick)} completed. ${durationAndMemoryString(duration)} ******\u001b[0;0m" ) case Ready(tick, duration) => diff --git a/src/main/scala/edu/ie3/simona/main/RunSimonaStandalone.scala b/src/main/scala/edu/ie3/simona/main/RunSimonaStandalone.scala index d0a50802b8..b8862655fa 100644 --- a/src/main/scala/edu/ie3/simona/main/RunSimonaStandalone.scala +++ b/src/main/scala/edu/ie3/simona/main/RunSimonaStandalone.scala @@ -58,7 +58,5 @@ object RunSimonaStandalone extends RunSimona[SimonaStandaloneSetup] { successful } - } - } diff --git a/src/main/scala/edu/ie3/simona/main/RunSimonaWithMosaik.scala b/src/main/scala/edu/ie3/simona/main/RunSimonaWithMosaik.scala new file mode 100644 index 0000000000..6d950f5620 --- /dev/null +++ b/src/main/scala/edu/ie3/simona/main/RunSimonaWithMosaik.scala @@ -0,0 +1,64 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.main + +import edu.ie3.simona.config.{ArgsParser, ConfigFailFast, SimonaConfig} +import edu.ie3.simona.main.RunSimona._ +import edu.ie3.simona.sim.SimonaSim +import edu.ie3.simona.sim.setup.SimonaMosaikSetup +import org.apache.pekko.actor.typed.scaladsl.AskPattern._ +import org.apache.pekko.actor.typed.{ActorSystem, Scheduler} +import org.apache.pekko.util.Timeout + +import scala.concurrent.Await +import scala.concurrent.duration.DurationInt + +/** Run a standalone simulation of simona + * + * @since 01.07.20 + */ +object RunSimonaWithMosaik extends RunSimona[SimonaMosaikSetup] { + + override implicit val timeout: Timeout = Timeout(12.hours) + + override def setup(args: Array[String]): SimonaMosaikSetup = { + // get the config and prepare it with the provided args + val (arguments, parsedConfig) = ArgsParser.prepareConfig(args) + + // config fail fast check + val simonaConfig = SimonaConfig(parsedConfig) + ConfigFailFast.check(parsedConfig, simonaConfig) + + SimonaMosaikSetup( + parsedConfig, + SimonaMosaikSetup.buildResultFileHierarchy(parsedConfig), + mainArgs = arguments.mainArgs, + mosaikIP = arguments.extAddress, + mosaikMappingPath = arguments.mappingPath + ) + } + + override def run(simonaSetup: SimonaMosaikSetup): Boolean = { + val simonaSim = ActorSystem( + SimonaSim(simonaSetup), + name = "Simona", + config = simonaSetup.typeSafeConfig, + ) + + implicit val scheduler: Scheduler = simonaSim.scheduler + + // run the simulation + val terminated = simonaSim.ask[SimonaEnded](ref => SimonaSim.Start(ref)) + + Await.result(terminated, timeout.duration) match { + case SimonaEnded(successful) => + simonaSim.terminate() + + successful + } + } +} diff --git a/src/main/scala/edu/ie3/simona/main/RunSimonaWithOpsim.scala b/src/main/scala/edu/ie3/simona/main/RunSimonaWithOpsim.scala new file mode 100644 index 0000000000..b0b1070673 --- /dev/null +++ b/src/main/scala/edu/ie3/simona/main/RunSimonaWithOpsim.scala @@ -0,0 +1,64 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.main + +import edu.ie3.simona.config.{ArgsParser, ConfigFailFast, SimonaConfig} +import edu.ie3.simona.main.RunSimona._ +import edu.ie3.simona.sim.SimonaSim +import edu.ie3.simona.sim.setup.{SimonaOpsimSetup, SimonaSimpleExtSimulationSetup, SimonaStandaloneSetup} +import org.apache.pekko.actor.typed.scaladsl.AskPattern._ +import org.apache.pekko.actor.typed.{ActorSystem, Scheduler} +import org.apache.pekko.util.Timeout + +import scala.concurrent.Await +import scala.concurrent.duration.DurationInt + +/** Run a standalone simulation of simona + * + * @since 01.07.20 + */ +object RunSimonaWithOpsim extends RunSimona[SimonaOpsimSetup] { + + override implicit val timeout: Timeout = Timeout(12.hours) + + override def setup(args: Array[String]): SimonaOpsimSetup = { + // get the config and prepare it with the provided args + val (arguments, parsedConfig) = ArgsParser.prepareConfig(args) + + // config fail fast check + val simonaConfig = SimonaConfig(parsedConfig) + ConfigFailFast.check(parsedConfig, simonaConfig) + + SimonaOpsimSetup( + parsedConfig, + SimonaOpsimSetup.buildResultFileHierarchy(parsedConfig), + mainArgs = arguments.mainArgs, + opsimIP = arguments.extAddress, + opsimMapping = arguments.mappingPath + ) + } + + override def run(simonaSetup: SimonaOpsimSetup): Boolean = { + val simonaSim = ActorSystem( + SimonaSim(simonaSetup), + name = "Simona", + config = simonaSetup.typeSafeConfig, + ) + + implicit val scheduler: Scheduler = simonaSim.scheduler + + // run the simulation + val terminated = simonaSim.ask[SimonaEnded](ref => SimonaSim.Start(ref)) + + Await.result(terminated, timeout.duration) match { + case SimonaEnded(successful) => + simonaSim.terminate() + + successful + } + } +} diff --git a/src/main/scala/edu/ie3/simona/main/RunSimonaWithSimpleExtSimulation.scala b/src/main/scala/edu/ie3/simona/main/RunSimonaWithSimpleExtSimulation.scala new file mode 100644 index 0000000000..08052cd169 --- /dev/null +++ b/src/main/scala/edu/ie3/simona/main/RunSimonaWithSimpleExtSimulation.scala @@ -0,0 +1,62 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.main + +import edu.ie3.simona.config.{ArgsParser, ConfigFailFast, SimonaConfig} +import edu.ie3.simona.main.RunSimona._ +import edu.ie3.simona.sim.SimonaSim +import edu.ie3.simona.sim.setup.{SimonaSimpleExtSimulationSetup, SimonaStandaloneSetup} +import org.apache.pekko.actor.typed.scaladsl.AskPattern._ +import org.apache.pekko.actor.typed.{ActorSystem, Scheduler} +import org.apache.pekko.util.Timeout + +import scala.concurrent.Await +import scala.concurrent.duration.DurationInt + +/** Run a standalone simulation of simona + * + * @since 01.07.20 + */ +object RunSimonaWithSimpleExtSimulation extends RunSimona[SimonaSimpleExtSimulationSetup] { + + override implicit val timeout: Timeout = Timeout(12.hours) + + override def setup(args: Array[String]): SimonaSimpleExtSimulationSetup = { + // get the config and prepare it with the provided args + val (arguments, parsedConfig) = ArgsParser.prepareConfig(args) + + // config fail fast check + val simonaConfig = SimonaConfig(parsedConfig) + ConfigFailFast.check(parsedConfig, simonaConfig) + + SimonaSimpleExtSimulationSetup( + parsedConfig, + SimonaSimpleExtSimulationSetup.buildResultFileHierarchy(parsedConfig), + mainArgs = arguments.mainArgs, + ) + } + + override def run(simonaSetup: SimonaSimpleExtSimulationSetup): Boolean = { + val simonaSim = ActorSystem( + SimonaSim(simonaSetup), + name = "Simona", + config = simonaSetup.typeSafeConfig, + ) + + implicit val scheduler: Scheduler = simonaSim.scheduler + + // run the simulation + val terminated = simonaSim.ask[SimonaEnded](ref => SimonaSim.Start(ref)) + + Await.result(terminated, timeout.duration) match { + case SimonaEnded(successful) => + simonaSim.terminate() + + successful + } + } +} diff --git a/src/main/scala/edu/ie3/simona/model/em/EmModelShell.scala b/src/main/scala/edu/ie3/simona/model/em/EmModelShell.scala index 6a15d08624..659d16a4e3 100644 --- a/src/main/scala/edu/ie3/simona/model/em/EmModelShell.scala +++ b/src/main/scala/edu/ie3/simona/model/em/EmModelShell.scala @@ -106,7 +106,6 @@ final case class EmModelShell( model -> power } } - } object EmModelShell { @@ -121,6 +120,8 @@ object EmModelShell { case "PROPORTIONAL" => ProportionalFlexStrat case "PRIORITIZED" => PrioritizedFlexStrat(modelConfig.curtailRegenerative) + case "self_optimization" => ProportionalFlexStrat + case "uncontrolled" => UncontrolledStrat(modelConfig.curtailRegenerative) case unknown => throw new CriticalFailureException(s"Unknown model strategy $unknown") } diff --git a/src/main/scala/edu/ie3/simona/model/em/EmTools.scala b/src/main/scala/edu/ie3/simona/model/em/EmTools.scala index 8a10b9c335..312db41c27 100644 --- a/src/main/scala/edu/ie3/simona/model/em/EmTools.scala +++ b/src/main/scala/edu/ie3/simona/model/em/EmTools.scala @@ -75,4 +75,8 @@ object EmTools { s"The set power $setPower for ${flexOptions.modelUuid} must not be greater than the maximum power ${flexOptions.max}!" ) } + + def minOptionTicks(a: Option[Long], b: Option[Long]): Option[Long] = { + a.flatMap(x => b.map(y => Math.min(x, y))).orElse(a).orElse(b) + } } diff --git a/src/main/scala/edu/ie3/simona/model/em/UncontrolledStrat.scala b/src/main/scala/edu/ie3/simona/model/em/UncontrolledStrat.scala new file mode 100644 index 0000000000..ab32a136e4 --- /dev/null +++ b/src/main/scala/edu/ie3/simona/model/em/UncontrolledStrat.scala @@ -0,0 +1,76 @@ +/* + * © 2022. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.model.em + +import edu.ie3.datamodel.models.input.AssetInput +import edu.ie3.datamodel.models.input.system.{ + EvcsInput, + HpInput, + PvInput, + StorageInput, + WecInput, +} +import edu.ie3.simona.exceptions.CriticalFailureException +import edu.ie3.simona.model.em.EmModelStrat.tolerance +import edu.ie3.simona.ontology.messages.flex.MinMaxFlexibilityMessage.ProvideMinMaxFlexOptions +import edu.ie3.util.scala.quantities.DefaultQuantities._ +import squants.Power + +import java.util.UUID + +/** Determines flex control for connected agents by adhering to a priority + * hierarchy, with some devices not controlled at all. + * + * @param curtailRegenerative + * Whether PV and WEC feed-in can be curtailed or not + */ +final case class UncontrolledStrat(curtailRegenerative: Boolean) + extends EmModelStrat { + + /** Only heat pumps, battery storages, charging stations and PVs/WECs (if + * enabled) are controlled by this strategy + */ + private val controllableAssets: Seq[Class[_ <: AssetInput]] = + Seq(classOf[HpInput], classOf[StorageInput], classOf[EvcsInput]) ++ Option + .when(curtailRegenerative)(Seq(classOf[PvInput], classOf[WecInput])) + .getOrElse(Seq.empty) + + /** Determine the power of controllable devices by using flexibility according + * to a prioritized list of device types. This means that e.g. flexibility of + * storages is used before flexibility of heat pumps is used. Priority lists + * can differ depending on whether positive or negative flexibility needs to + * be used. + * + * @param flexOptions + * The flex options per connected system participant + * @param target + * The target power to aim for when utilizing flexibility + * @return + * Power set points for devices, if applicable + */ + override def determineFlexControl( + flexOptions: Iterable[ + (_ <: AssetInput, ProvideMinMaxFlexOptions) + ], + target: Power, + ): Seq[(UUID, Power)] = Seq.empty + + override def adaptFlexOptions( + assetInput: AssetInput, + flexOptions: ProvideMinMaxFlexOptions, + ): ProvideMinMaxFlexOptions = { + if (controllableAssets.contains(assetInput.getClass)) + flexOptions + else { + // device is not controllable by this EmAgent + flexOptions.copy( + min = flexOptions.ref, + max = flexOptions.ref, + ) + } + } +} diff --git a/src/main/scala/edu/ie3/simona/ontology/messages/flex/FlexibilityMessage.scala b/src/main/scala/edu/ie3/simona/ontology/messages/flex/FlexibilityMessage.scala index 812eafbfff..1a74142417 100644 --- a/src/main/scala/edu/ie3/simona/ontology/messages/flex/FlexibilityMessage.scala +++ b/src/main/scala/edu/ie3/simona/ontology/messages/flex/FlexibilityMessage.scala @@ -37,6 +37,13 @@ object FlexibilityMessage { val modelUuid: UUID } + + final case class SetPointFlexRequest( + tick: Long, + setPower: Power, + nextSetPointTick: Long + ) extends FlexRequest + /** Message that registers a flex options provider with an * [[edu.ie3.simona.agent.em.EmAgent]]. * @@ -85,6 +92,7 @@ object FlexibilityMessage { */ trait ProvideFlexOptions extends FlexResponse + /** Message that issues flexibility control to a flex options provider, i.e. a * feasible set point is delivered that the flex options provider should * adhere to diff --git a/src/main/scala/edu/ie3/simona/ontology/messages/services/DataMessage.scala b/src/main/scala/edu/ie3/simona/ontology/messages/services/DataMessage.scala new file mode 100644 index 0000000000..f83bf2cb09 --- /dev/null +++ b/src/main/scala/edu/ie3/simona/ontology/messages/services/DataMessage.scala @@ -0,0 +1,9 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.ontology.messages.services + +trait DataMessage diff --git a/src/main/scala/edu/ie3/simona/ontology/messages/services/EvMessage.scala b/src/main/scala/edu/ie3/simona/ontology/messages/services/EvMessage.scala index 05a5be6886..5d460596b8 100644 --- a/src/main/scala/edu/ie3/simona/ontology/messages/services/EvMessage.scala +++ b/src/main/scala/edu/ie3/simona/ontology/messages/services/EvMessage.scala @@ -17,7 +17,7 @@ import org.apache.pekko.actor.ActorRef import java.util.UUID -sealed trait EvMessage +sealed trait EvMessage extends DataMessage object EvMessage { diff --git a/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala b/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala index 33946b669f..9a1f2e54da 100644 --- a/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala +++ b/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala @@ -6,10 +6,14 @@ package edu.ie3.simona.ontology.messages.services -import org.apache.pekko.actor.ActorRef +import edu.ie3.simona.agent.em.EmAgent + +import org.apache.pekko.actor.{ActorRef => ClassicRef} +import org.apache.pekko.actor.typed.ActorRef import java.util.UUID import edu.ie3.simona.agent.participant.data.Data +import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage.FlexRequest import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey /** Collections of all messages, that are send to and from the different @@ -19,6 +23,8 @@ sealed trait ServiceMessage case object ServiceMessage { + final case class RequestExtPrimaryDataAssets() extends ServiceMessage {} + /** Message used to register for a service */ trait ServiceRegistrationMessage extends ServiceMessage @@ -38,11 +44,22 @@ case object ServiceMessage { * @param requestingActor * Reference to the requesting actor */ - final case class WorkerRegistrationMessage(requestingActor: ActorRef) + final case class WorkerRegistrationMessage(requestingActor: ClassicRef) extends ServiceRegistrationMessage + final case class ExtPrimaryDataServiceRegistrationMessage( + modelUuid: UUID, + requestingActor: ClassicRef, + ) extends ServiceRegistrationMessage + + final case class ExtEmDataServiceRegistrationMessage( + modelUuid: UUID, + requestingActor: ActorRef[EmAgent.Request], + flexAdapter: ActorRef[FlexRequest] + ) extends ServiceRegistrationMessage + sealed trait RegistrationResponseMessage extends ServiceMessage { - val serviceRef: ActorRef + val serviceRef: ClassicRef } object RegistrationResponseMessage { @@ -50,14 +67,18 @@ case object ServiceMessage { /** Message, that is used to confirm a successful registration */ final case class RegistrationSuccessfulMessage( - override val serviceRef: ActorRef, + override val serviceRef: ClassicRef, nextDataTick: Option[Long], ) extends RegistrationResponseMessage + final case class WrappedRegistrationSuccessfulMessage( + registrationSuccessfulMessage: RegistrationSuccessfulMessage + ) extends EmAgent.Request + /** Message, that is used to announce a failed registration */ final case class RegistrationFailedMessage( - override val serviceRef: ActorRef + override val serviceRef: ClassicRef ) extends RegistrationResponseMessage final case class ScheduleServiceActivation( @@ -73,7 +94,7 @@ case object ServiceMessage { */ trait ProvisionMessage[D <: Data] extends ServiceMessage { val tick: Long - val serviceRef: ActorRef + val serviceRef: ClassicRef val data: D val nextDataTick: Option[Long] val unlockKey: Option[ScheduleKey] diff --git a/src/main/scala/edu/ie3/simona/scheduler/Scheduler.scala b/src/main/scala/edu/ie3/simona/scheduler/Scheduler.scala index 7339fbbe61..3d13d63bb7 100644 --- a/src/main/scala/edu/ie3/simona/scheduler/Scheduler.scala +++ b/src/main/scala/edu/ie3/simona/scheduler/Scheduler.scala @@ -137,7 +137,6 @@ object Scheduler { toActivate.foreach { _ ! Activation(updatedCore.activeTick) } - updatedCore } .map { newCore => diff --git a/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala b/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala index 31800da210..21176bc8fe 100644 --- a/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala +++ b/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala @@ -7,6 +7,8 @@ package edu.ie3.simona.service import edu.ie3.simona.api.data.ontology.DataMessageFromExt +import edu.ie3.simona.api.data.results.ontology.ResultDataMessageFromExt +import edu.ie3.simona.ontology.messages.services.DataMessage import edu.ie3.simona.ontology.messages.services.EvMessage.EvResponseMessage import edu.ie3.simona.service.ServiceStateData.ServiceBaseStateData @@ -49,6 +51,6 @@ trait ExtDataSupport[ * the updated state data */ protected def handleDataResponseMessage( - extResponseMsg: EvResponseMessage + extResponseMsg: DataMessage )(implicit serviceStateData: S): S } diff --git a/src/main/scala/edu/ie3/simona/service/SimonaService.scala b/src/main/scala/edu/ie3/simona/service/SimonaService.scala index 1b41b30400..caa9f12825 100644 --- a/src/main/scala/edu/ie3/simona/service/SimonaService.scala +++ b/src/main/scala/edu/ie3/simona/service/SimonaService.scala @@ -6,23 +6,17 @@ package edu.ie3.simona.service -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.actor.{Actor, ActorContext, ActorRef, Stash} import edu.ie3.simona.logging.SimonaActorLogging import edu.ie3.simona.ontology.messages.Activation -import edu.ie3.simona.ontology.messages.SchedulerMessage.{ - Completion, - ScheduleActivation, -} +import edu.ie3.simona.ontology.messages.SchedulerMessage.{Completion, ScheduleActivation} import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.ScheduleServiceActivation import edu.ie3.simona.ontology.messages.services.ServiceMessage.ServiceRegistrationMessage import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey -import edu.ie3.simona.service.ServiceStateData.{ - InitializeServiceStateData, - ServiceBaseStateData, -} +import edu.ie3.simona.service.ServiceStateData.{InitializeServiceStateData, ServiceBaseStateData} import edu.ie3.simona.service.SimonaService.Create import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps +import org.apache.pekko.actor.{Actor, ActorContext, ActorRef, Stash} import scala.util.{Failure, Success, Try} diff --git a/src/main/scala/edu/ie3/simona/service/em/ExtEmDataService.scala b/src/main/scala/edu/ie3/simona/service/em/ExtEmDataService.scala new file mode 100644 index 0000000000..e2947cc5e9 --- /dev/null +++ b/src/main/scala/edu/ie3/simona/service/em/ExtEmDataService.scala @@ -0,0 +1,229 @@ +package edu.ie3.simona.service.em + +import edu.ie3.datamodel.models.value.PValue +import edu.ie3.simona.agent.em.EmAgent +import edu.ie3.simona.api.data.em.ExtEmData +import edu.ie3.simona.api.data.em.ontology.{EmDataMessageFromExt, ProvideEmData} +import edu.ie3.simona.api.data.ontology.DataMessageFromExt +import edu.ie3.simona.exceptions.WeatherServiceException.InvalidRegistrationRequestException +import edu.ie3.simona.exceptions.{InitializationException, ServiceException} +import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage.{FlexRequest, IssuePowerControl, SetPointFlexRequest} +import edu.ie3.simona.ontology.messages.services.ServiceMessage.ExtEmDataServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.{RegistrationSuccessfulMessage, WrappedRegistrationSuccessfulMessage} +import edu.ie3.simona.ontology.messages.services.{DataMessage, ServiceMessage} +import edu.ie3.simona.service.ServiceStateData.{InitializeServiceStateData, ServiceBaseStateData} +import edu.ie3.simona.service.em.ExtEmDataService.{ExtEmDataStateData, InitExtEmData} +import edu.ie3.simona.service.{ExtDataSupport, SimonaService} +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.{ActorContext, Props, ActorRef => ClassicRef} +import squants.Power +import squants.energy.Kilowatts + +import java.util.UUID +import scala.jdk.CollectionConverters.{CollectionHasAsScala, MapHasAsScala} +import scala.util.{Failure, Success, Try} + +object ExtEmDataService { + + def props(scheduler: ClassicRef): Props = + Props( + new ExtEmDataService(scheduler: ClassicRef) + ) + + final case class ExtEmDataStateData( + extEmData: ExtEmData, + subscribers: List[UUID] = List.empty, + uuidToActorRef: Map[UUID, ActorRef[EmAgent.Request]] = Map.empty[UUID, ActorRef[EmAgent.Request]], // subscribers in SIMONA + uuidToAdapterRef: Map[UUID, ActorRef[FlexRequest]] = Map.empty[UUID, ActorRef[FlexRequest]], // subscribers in SIMONA + extEmDataMessage: Option[EmDataMessageFromExt] = None, + ) extends ServiceBaseStateData + + case class InitExtEmData( + extEmData: ExtEmData + ) extends InitializeServiceStateData + + final case class WrappedIssuePowerControl( + issuePowerControl: IssuePowerControl + ) extends EmAgent.Request +} + + + +final case class ExtEmDataService( + override val scheduler: ClassicRef + ) extends SimonaService[ExtEmDataStateData](scheduler) + with ExtDataSupport[ExtEmDataStateData] { + + /** Initialize the concrete service implementation using the provided + * initialization data. This method should perform all heavyweight tasks + * before the actor becomes ready. The return values are a) the state data of + * the initialized service and b) optional triggers that should be send to + * the [[edu.ie3.simona.scheduler.Scheduler]] together with the completion + * message that is send in response to the trigger that is send to start the + * initialization process + * + * @param initServiceData + * the data that should be used for initialization + * @return + * the state data of this service and optional tick that should be included + * in the completion message + */ + override def init(initServiceData: InitializeServiceStateData): Try[(ExtEmDataStateData, Option[Long])] = initServiceData match { + case InitExtEmData(extEmData) => + val emDataInitializedStateData = ExtEmDataStateData( + extEmData, + subscribers = extEmData.getControlledEms.asScala.toList + ) + Success( + emDataInitializedStateData, + None, + ) + + case invalidData => + Failure( + new InitializationException( + s"Provided init data '${invalidData.getClass.getSimpleName}' for ExtEmDataService are invalid!" + ) + ) + } + + /** Handle a request to register for information from this service + * + * @param registrationMessage + * registration message to handle + * @param serviceStateData + * current state data of the actor + * @return + * the service stata data that should be used in the next state (normally + * with updated values) + */ + override protected def handleRegistrationRequest( + registrationMessage: ServiceMessage.ServiceRegistrationMessage + )( + implicit serviceStateData: ExtEmDataStateData): Try[ExtEmDataStateData] = registrationMessage match { + case ExtEmDataServiceRegistrationMessage( + modelUuid, + requestingActor, + flexAdapter + ) => + Success(handleEmRegistrationRequest(modelUuid, requestingActor, flexAdapter)) + case invalidMessage => + Failure( + InvalidRegistrationRequestException( + s"A primary service provider is not able to handle registration request '$invalidMessage'." + ) + ) + } + + private def handleEmRegistrationRequest( + modelUuid: UUID, + modelActorRef: ActorRef[EmAgent.Request], + flexAdapterRef: ActorRef[FlexRequest] + )( + implicit serviceStateData: ExtEmDataStateData): ExtEmDataStateData = { + if (serviceStateData.subscribers.contains(modelUuid)) { + modelActorRef ! WrappedRegistrationSuccessfulMessage(RegistrationSuccessfulMessage(self, None)) + serviceStateData.copy( + uuidToActorRef = serviceStateData.uuidToActorRef + (modelUuid -> modelActorRef), + uuidToAdapterRef = serviceStateData.uuidToAdapterRef + (modelUuid -> flexAdapterRef) + ) + } else { + serviceStateData + } + } + + + /** Send out the information to all registered recipients + * + * @param tick + * current tick data should be announced for + * @param serviceStateData + * the current state data of this service + * @return + * the service stata data that should be used in the next state (normally + * with updated values) together with the completion message that is send + * in response to the trigger that was sent to start this announcement + */ + override protected def announceInformation(tick: Long)(implicit serviceStateData: ExtEmDataStateData, ctx: ActorContext): (ExtEmDataStateData, Option[Long]) = { + serviceStateData.extEmDataMessage.getOrElse( + throw ServiceException( + "ExtPrimaryDataService was triggered without ExtPrimaryDataMessage available" + ) + ) match { + case providedEmData: ProvideEmData => + announceEmData(tick, providedEmData.emData)( + serviceStateData, + ctx, + ) + } + } + + private def announceEmData( + tick: Long, + emData: java.util.Map[UUID, PValue], + )(implicit serviceStateData: ExtEmDataStateData, ctx: ActorContext): ( + ExtEmDataStateData, + Option[Long] + ) = { + val actorToEmData = emData.asScala.flatMap { + case (agent, emDataPerAgent) => + serviceStateData.uuidToAdapterRef + .get(agent) + .map((_, convertToSetPoint(emDataPerAgent))) + .orElse { + log.warning( + "A corresponding actor ref for UUID {} could not be found", + agent, + ) + None + } + } + + if (actorToEmData.nonEmpty) { + actorToEmData.foreach { + case (actor, setPoint) => + actor ! SetPointFlexRequest( + tick, + setPoint, + tick + 900L + ) + } + } + (serviceStateData.copy(extEmDataMessage = None), None) + } + + private def convertToSetPoint( + value: PValue + ): Power = { + Kilowatts(value.getP.get.getValue.doubleValue()) + } + + /** Handle a message from outside the simulation + * + * @param extMsg + * the external incoming message + * @param serviceStateData + * the current state data of this service + * @return + * the updated state data + */ + override protected def handleDataMessage(extMsg: DataMessageFromExt)(implicit serviceStateData: ExtEmDataStateData): ExtEmDataStateData = { + extMsg match { + case extEmDataMessage: EmDataMessageFromExt => + serviceStateData.copy( + extEmDataMessage = Some(extEmDataMessage) + ) + } + } + + /** Handle a message from inside SIMONA sent to external + * + * @param extResponseMsg + * the external incoming message + * @param serviceStateData + * the current state data of this service + * @return + * the updated state data + */ + override protected def handleDataResponseMessage(extResponseMsg: DataMessage)(implicit serviceStateData: ExtEmDataStateData): ExtEmDataStateData = serviceStateData +} diff --git a/src/main/scala/edu/ie3/simona/service/ev/ExtEvDataService.scala b/src/main/scala/edu/ie3/simona/service/ev/ExtEvDataService.scala index c827cb52fb..27587bfafe 100644 --- a/src/main/scala/edu/ie3/simona/service/ev/ExtEvDataService.scala +++ b/src/main/scala/edu/ie3/simona/service/ev/ExtEvDataService.scala @@ -28,6 +28,7 @@ import edu.ie3.simona.service.ev.ExtEvDataService.{ InitExtEvData, } import edu.ie3.simona.service.{ExtDataSupport, ServiceStateData, SimonaService} +import edu.ie3.simona.ontology.messages.services.DataMessage import edu.ie3.simona.util.ReceiveDataMap import java.util.UUID @@ -185,7 +186,7 @@ class ExtEvDataService(override val scheduler: ActorRef) case departingEvsRequest: RequestDepartingEvs => requestDepartingEvs(tick, departingEvsRequest.departures) case arrivingEvsProvision: ProvideArrivingEvs => - handleArrivingEvs(tick, arrivingEvsProvision.arrivals)( + handleArrivingEvs(tick, null)( serviceStateData, ctx, ) @@ -311,7 +312,7 @@ class ExtEvDataService(override val scheduler: ActorRef) } override protected def handleDataResponseMessage( - extResponseMsg: EvResponseMessage + extResponseMsg: DataMessage )(implicit serviceStateData: ExtEvStateData): ExtEvStateData = { extResponseMsg match { case DepartingEvsResponse(evcs, evModels) => diff --git a/src/main/scala/edu/ie3/simona/service/primary/ExtPrimaryDataService.scala b/src/main/scala/edu/ie3/simona/service/primary/ExtPrimaryDataService.scala new file mode 100644 index 0000000000..5a3eed9f82 --- /dev/null +++ b/src/main/scala/edu/ie3/simona/service/primary/ExtPrimaryDataService.scala @@ -0,0 +1,246 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.service.primary + +import edu.ie3.datamodel.models.value.Value +import edu.ie3.simona.agent.participant.data.Data.PrimaryData.RichValue +import edu.ie3.simona.api.data.ontology.DataMessageFromExt +import edu.ie3.simona.api.data.primarydata.ExtPrimaryData +import edu.ie3.simona.api.data.primarydata.ontology.{ + PrimaryDataMessageFromExt, + ProvidePrimaryData, +} +import edu.ie3.simona.exceptions.WeatherServiceException.InvalidRegistrationRequestException +import edu.ie3.simona.exceptions.{InitializationException, ServiceException} +import edu.ie3.simona.ontology.messages.services.ServiceMessage.ExtPrimaryDataServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationSuccessfulMessage +import edu.ie3.simona.ontology.messages.services.{DataMessage, ServiceMessage} +import edu.ie3.simona.scheduler.ScheduleLock +import edu.ie3.simona.service.ServiceStateData.{ + InitializeServiceStateData, + ServiceBaseStateData, +} +import edu.ie3.simona.service.primary.ExtPrimaryDataService.{ + ExtPrimaryDataStateData, + InitExtPrimaryData, +} +import edu.ie3.simona.service.primary.PrimaryServiceWorker.ProvidePrimaryDataMessage +import edu.ie3.simona.service.{ExtDataSupport, ServiceStateData, SimonaService} +import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps +import org.apache.pekko.actor.{ActorContext, ActorRef, Props} + +import java.util.UUID +import scala.jdk.CollectionConverters.MapHasAsScala +import scala.util.{Failure, Success, Try} + +object ExtPrimaryDataService { + + def props(scheduler: ActorRef): Props = + Props( + new ExtPrimaryDataService(scheduler: ActorRef) + ) + + final case class ExtPrimaryDataStateData( + extPrimaryData: ExtPrimaryData, + subscribers: List[UUID] = List.empty, + uuidToActorRef: Map[UUID, ActorRef] = + Map.empty[UUID, ActorRef], // subscribers in SIMONA + extPrimaryDataMessage: Option[PrimaryDataMessageFromExt] = None, + ) extends ServiceBaseStateData + + case class InitExtPrimaryData( + extPrimaryData: ExtPrimaryData + ) extends InitializeServiceStateData + +} +final case class ExtPrimaryDataService( + override val scheduler: ActorRef +) extends SimonaService[ExtPrimaryDataStateData](scheduler) + with ExtDataSupport[ExtPrimaryDataStateData] { + + override def init( + initServiceData: ServiceStateData.InitializeServiceStateData + ): Try[(ExtPrimaryDataStateData, Option[Long])] = initServiceData match { + case InitExtPrimaryData(extPrimaryData) => + val primaryDataInitializedStateData = ExtPrimaryDataStateData( + extPrimaryData + ) + Success( + primaryDataInitializedStateData, + None, + ) + + case invalidData => + Failure( + new InitializationException( + s"Provided init data '${invalidData.getClass.getSimpleName}' for ExtPrimaryService are invalid!" + ) + ) + } + + override protected def handleRegistrationRequest( + registrationMessage: ServiceMessage.ServiceRegistrationMessage + )(implicit + serviceStateData: ExtPrimaryDataStateData + ): Try[ExtPrimaryDataStateData] = registrationMessage match { + case ExtPrimaryDataServiceRegistrationMessage( + modelUuid, + requestingActor, + ) => + Success(handleRegistrationRequest(requestingActor, modelUuid)) + case invalidMessage => + Failure( + InvalidRegistrationRequestException( + s"A primary service provider is not able to handle registration request '$invalidMessage'." + ) + ) + } + + private def handleRegistrationRequest( + agentToBeRegistered: ActorRef, + agentUUID: UUID, + )(implicit + serviceStateData: ExtPrimaryDataStateData + ): ExtPrimaryDataStateData = { + serviceStateData.uuidToActorRef.get(agentUUID) match { + case None => + // Actor is not registered yet + agentToBeRegistered ! RegistrationSuccessfulMessage(self, None) + serviceStateData.copy( + uuidToActorRef = + serviceStateData.uuidToActorRef + (agentUUID -> agentToBeRegistered) + ) + case Some(_) => + // actor is already registered, do nothing + log.warning( + "Sending actor {} is already registered", + agentToBeRegistered, + ) + serviceStateData + } + } + + /** Send out the information to all registered recipients + * + * @param tick + * current tick data should be announced for + * @param serviceStateData + * the current state data of this service + * @return + * the service stata data that should be used in the next state (normally + * with updated values) together with the completion message that is send + * in response to the trigger that was sent to start this announcement + */ + override protected def announceInformation( + tick: Long + )(implicit + serviceStateData: ExtPrimaryDataStateData, + ctx: ActorContext, + ): (ExtPrimaryDataStateData, Option[Long]) = { + serviceStateData.extPrimaryDataMessage.getOrElse( + throw ServiceException( + "ExtPrimaryDataService was triggered without ExtPrimaryDataMessage available" + ) + ) match { + case providedPrimaryData: ProvidePrimaryData => + processDataAndAnnounce(tick, providedPrimaryData.primaryData)( + serviceStateData, + ctx, + ) + } + } + + private def processDataAndAnnounce( + tick: Long, + primaryData: java.util.Map[UUID, Value], + )(implicit + serviceStateData: ExtPrimaryDataStateData, + ctx: ActorContext, + ): ( + ExtPrimaryDataStateData, + Option[Long], + ) = { + log.debug(s"Got activation to distribute primaryData = $primaryData") + val actorToPrimaryData = primaryData.asScala.flatMap { + case (agent, primaryDataPerAgent) => + serviceStateData.uuidToActorRef + .get(agent) + .map((_, primaryDataPerAgent)) + .orElse { + log.warning( + "A corresponding actor ref for UUID {} could not be found", + agent, + ) + None + } + } + + // Distribute Primary Data + if (actorToPrimaryData.nonEmpty) { + actorToPrimaryData.foreach { + case (actor, value) => + value.toPrimaryData match { + case Success(primaryData) => + actor ! ProvidePrimaryDataMessage( + tick, + self, + primaryData, + None + ) + case Failure(exception) => + /* Processing of data failed */ + log.warning( + "Unable to convert received value to primary data. Skipped that data." + + "\nException: {}", + exception, + ) + } + } + } + + /* + val keys = + ScheduleLock.multiKey( + ctx, + scheduler.toTyped, + tick, + actorToPrimaryData.size, + ) + + actorToPrimaryData.zip(keys).foreach { + case ((actor, primaryDataPerAgent), key) => + log.info(s"actor $actor, unlockKey $key") + primaryDataPerAgent.toPrimaryData v + } + + */ + + ( + serviceStateData.copy(extPrimaryDataMessage = None), + None, + ) + } + + override protected def handleDataMessage( + extMsg: DataMessageFromExt + )(implicit + serviceStateData: ExtPrimaryDataStateData + ): ExtPrimaryDataStateData = { + extMsg match { + case extPrimaryDataMessage: PrimaryDataMessageFromExt => + serviceStateData.copy( + extPrimaryDataMessage = Some(extPrimaryDataMessage) + ) + } + } + + override protected def handleDataResponseMessage( + extResponseMsg: DataMessage + )(implicit + serviceStateData: ExtPrimaryDataStateData + ): ExtPrimaryDataStateData = serviceStateData +} diff --git a/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala b/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala index ca41a11234..0002286e12 100644 --- a/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala +++ b/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala @@ -6,60 +6,32 @@ package edu.ie3.simona.service.primary -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.actor.{Actor, ActorRef, PoisonPill, Props} import edu.ie3.datamodel.io.connectors.SqlConnector import edu.ie3.datamodel.io.csv.CsvIndividualTimeSeriesMetaInformation import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation -import edu.ie3.datamodel.io.naming.{ - DatabaseNamingStrategy, - EntityPersistenceNamingStrategy, - FileNamingStrategy, -} -import edu.ie3.datamodel.io.source.csv.{ - CsvTimeSeriesMappingSource, - CsvTimeSeriesMetaInformationSource, -} -import edu.ie3.datamodel.io.source.sql.{ - SqlTimeSeriesMappingSource, - SqlTimeSeriesMetaInformationSource, -} -import edu.ie3.datamodel.io.source.{ - TimeSeriesMappingSource, - TimeSeriesMetaInformationSource, -} +import edu.ie3.datamodel.io.naming.{DatabaseNamingStrategy, EntityPersistenceNamingStrategy, FileNamingStrategy} +import edu.ie3.datamodel.io.source.csv.{CsvTimeSeriesMappingSource, CsvTimeSeriesMetaInformationSource} +import edu.ie3.datamodel.io.source.sql.{SqlTimeSeriesMappingSource, SqlTimeSeriesMetaInformationSource} +import edu.ie3.datamodel.io.source.{TimeSeriesMappingSource, TimeSeriesMetaInformationSource} import edu.ie3.datamodel.models.value.Value +import edu.ie3.simona.api.data.primarydata.ExtPrimaryData import edu.ie3.simona.config.SimonaConfig.PrimaryDataCsvParams import edu.ie3.simona.config.SimonaConfig.Simona.Input.Primary.SqlParams -import edu.ie3.simona.config.SimonaConfig.Simona.Input.{ - Primary => PrimaryConfig -} -import edu.ie3.simona.exceptions.{ - InitializationException, - InvalidConfigParameterException, -} +import edu.ie3.simona.config.SimonaConfig.Simona.Input.{Primary => PrimaryConfig} +import edu.ie3.simona.exceptions.{InitializationException, InvalidConfigParameterException} import edu.ie3.simona.logging.SimonaActorLogging import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationFailedMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.{ - PrimaryServiceRegistrationMessage, - WorkerRegistrationMessage, -} +import edu.ie3.simona.ontology.messages.services.ServiceMessage.{ExtPrimaryDataServiceRegistrationMessage, PrimaryServiceRegistrationMessage, WorkerRegistrationMessage} import edu.ie3.simona.scheduler.ScheduleLock -import edu.ie3.simona.service.{ServiceStateData, SimonaService} import edu.ie3.simona.service.ServiceStateData.InitializeServiceStateData -import edu.ie3.simona.service.primary.PrimaryServiceProxy.{ - InitPrimaryServiceProxyStateData, - PrimaryServiceStateData, - SourceRef, -} -import edu.ie3.simona.service.primary.PrimaryServiceWorker.{ - CsvInitPrimaryServiceStateData, - InitPrimaryServiceStateData, - SqlInitPrimaryServiceStateData, -} +import edu.ie3.simona.service.primary.PrimaryServiceProxy.{InitPrimaryServiceProxyStateData, PrimaryServiceStateData, SourceRef} +import edu.ie3.simona.service.primary.PrimaryServiceWorker.{CsvInitPrimaryServiceStateData, InitPrimaryServiceStateData, SqlInitPrimaryServiceStateData} +import edu.ie3.simona.service.{ServiceStateData, SimonaService} import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps +import org.apache.pekko.actor.{Actor, ActorRef, PoisonPill, Props} import java.nio.file.Paths import java.text.SimpleDateFormat @@ -107,6 +79,8 @@ case class PrimaryServiceProxy( prepareStateData( initStateData.primaryConfig, initStateData.simulationStart, + initStateData.extSimulation, + initStateData.extPrimaryData ) match { case Success(stateData) => scheduler ! Completion(self.toTyped) @@ -139,6 +113,8 @@ case class PrimaryServiceProxy( private def prepareStateData( primaryConfig: PrimaryConfig, simulationStart: ZonedDateTime, + extSimulation: Option[ActorRef], + extPrimaryData: Option[ExtPrimaryData] ): Try[PrimaryServiceStateData] = { createSources(primaryConfig).map { case (mappingSource, metaInformationSource) => @@ -167,13 +143,26 @@ case class PrimaryServiceProxy( } } .toMap - PrimaryServiceStateData( - modelToTimeSeries, - timeSeriesToSourceRef, - simulationStart, - primaryConfig, - mappingSource, - ) + if (extSimulation.isDefined) { + // Ask ExtPrimaryDataService which UUIDs should be substituted + PrimaryServiceStateData( + modelToTimeSeries, + timeSeriesToSourceRef, + simulationStart, + primaryConfig, + mappingSource, + extPrimaryData.getOrElse(throw new Exception("External Primary Data Simulation is requested without ExtPrimaryData")).getPrimaryDataAssets.asScala, + extSimulation, + ) + } else { + PrimaryServiceStateData( + modelToTimeSeries, + timeSeriesToSourceRef, + simulationStart, + primaryConfig, + mappingSource, + ) + } } } @@ -256,11 +245,27 @@ case class PrimaryServiceProxy( sender(), ) case None => - log.debug( - s"There is no time series apparent for the model with uuid '{}'.", - modelUuid, - ) - sender() ! RegistrationFailedMessage(self) + if (stateData.extSubscribers.nonEmpty) { + log.debug( + s"Try to find external primary data for the model with uuid '{}'.", + modelUuid, + ) + if (stateData.extSubscribers.exists(_ == modelUuid)) { + handleExternalModel(modelUuid, stateData, sender()) + } else { + log.debug( + s"There is no external data apparent for the model with uuid '{}'.", + modelUuid, + ) + sender() ! RegistrationFailedMessage(self) + } + } else { + log.debug( + s"There is no time series apparent for the model with uuid '{}'.", + modelUuid, + ) + sender() ! RegistrationFailedMessage(self) + } } case x => log.error( @@ -325,6 +330,20 @@ case class PrimaryServiceProxy( } } + protected def handleExternalModel( + modelUuid: UUID, + stateData: PrimaryServiceStateData, + requestingActor: ActorRef, + ): Unit = { + stateData.extPrimaryDataService match { + case Some(primaryDataService) => + primaryDataService ! ExtPrimaryDataServiceRegistrationMessage( + modelUuid, + requestingActor, + ) + } + } + /** Instantiate a new [[PrimaryServiceWorker]] and send initialization * information * @@ -510,6 +529,8 @@ object PrimaryServiceProxy { final case class InitPrimaryServiceProxyStateData( primaryConfig: PrimaryConfig, simulationStart: ZonedDateTime, + extSimulation: Option[ActorRef], + extPrimaryData: Option[ExtPrimaryData] ) extends InitializeServiceStateData /** Holding the state of an initialized proxy. @@ -531,6 +552,8 @@ object PrimaryServiceProxy { simulationStart: ZonedDateTime, primaryConfig: PrimaryConfig, mappingSource: TimeSeriesMappingSource, + extSubscribers: Iterable[UUID] = Iterable.empty[UUID], + extPrimaryDataService: Option[ActorRef] = None, ) extends ServiceStateData /** Giving reference to the target time series and source worker. diff --git a/src/main/scala/edu/ie3/simona/service/results/ExtResultDataProvider.scala b/src/main/scala/edu/ie3/simona/service/results/ExtResultDataProvider.scala new file mode 100644 index 0000000000..f60abbae0b --- /dev/null +++ b/src/main/scala/edu/ie3/simona/service/results/ExtResultDataProvider.scala @@ -0,0 +1,306 @@ +package edu.ie3.simona.service.results + +import edu.ie3.datamodel.models.result.{ModelResultEntity, ResultEntity} +import edu.ie3.datamodel.models.result.system.PvResult +import edu.ie3.simona.api.data.results.ExtResultData +import edu.ie3.simona.api.data.results.ontology.{ProvideResultEntities, RequestResultEntities, ResultDataMessageFromExt} +import edu.ie3.simona.event.listener.DelayedStopHelper +import edu.ie3.simona.exceptions.ServiceException +import edu.ie3.simona.ontology.messages.SchedulerMessage.{Completion, ScheduleActivation} +import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.ScheduleServiceActivation +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} +import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey +import edu.ie3.simona.util.ReceiveDataMap +import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import org.apache.pekko.actor.typed.{ActorRef, Behavior, PostStop} +import org.apache.pekko.actor.typed.scaladsl.{Behaviors, StashBuffer} + +import java.util.UUID +import scala.collection.immutable.Set +import scala.jdk.CollectionConverters._ + +object ExtResultDataProvider { + + trait Request + + final case class WrappedActivation(activation: Activation) extends Request + + /** ExtSimulation -> ExtResultDataProvider */ + final case class WrappedResultDataMessageFromExt(extResultDataMessageFromExt: ResultDataMessageFromExt) extends Request + final case class WrappedScheduleServiceActivationAdapter(scheduleServiceActivationMsg: ScheduleServiceActivation) extends Request + + final case class RequestDataMessageAdapter(sender: ActorRef[ActorRef[ResultDataMessageFromExt]]) extends Request + + final case class RequestScheduleActivationAdapter(sender: ActorRef[ActorRef[ScheduleServiceActivation]]) extends Request + + + /** ResultEventListener -> ExtResultDataProvider */ + final case class ResultResponseMessage( + result: ModelResultEntity, + tick: Long, + nextTick: Option[Long] + ) + extends Request + + /** ExtResultDataProvider -> ExtResultDataProvider */ + final case class ResultRequestMessage( + currentTick: Long + ) extends Request + + final case class Create( + initializeStateData: InitExtResultData, + unlockKey: ScheduleKey, + ) extends Request + + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + def apply( + scheduler: ActorRef[SchedulerMessage] + ): Behavior[Request] = Behaviors.withStash(5000) { buffer => + Behaviors.setup[Request] { ctx => + val activationAdapter: ActorRef[Activation] = ctx.messageAdapter[Activation](msg => WrappedActivation(msg)) + val resultDataMessageFromExtAdapter: ActorRef[ResultDataMessageFromExt] = ctx.messageAdapter[ResultDataMessageFromExt](msg => WrappedResultDataMessageFromExt(msg)) + val scheduleServiceActivationAdapter: ActorRef[ScheduleServiceActivation] = ctx.messageAdapter[ScheduleServiceActivation](msg => WrappedScheduleServiceActivationAdapter(msg)) + + uninitialized(scheduler, activationAdapter, resultDataMessageFromExtAdapter, scheduleServiceActivationAdapter, buffer) + } + } + + + private def uninitialized( + implicit scheduler: ActorRef[SchedulerMessage], + activationAdapter: ActorRef[Activation], + resultDataMessageFromExtAdapter: ActorRef[ResultDataMessageFromExt], + scheduleServiceActivationAdapter: ActorRef[ScheduleServiceActivation], + buffer: StashBuffer[Request], + ): Behavior[Request] = Behaviors.receiveMessagePartial { + case RequestDataMessageAdapter(sender) => + sender ! resultDataMessageFromExtAdapter + Behaviors.same + + case RequestScheduleActivationAdapter(sender) => + sender ! scheduleServiceActivationAdapter + Behaviors.same + + case Create( + initializeStateData: InitExtResultData, + unlockKey: ScheduleKey, + ) => + scheduler ! ScheduleActivation(activationAdapter, + INIT_SIM_TICK, + Some(unlockKey)) + + initializing(initializeStateData) + } + + private def initializing( + initServiceData: InitExtResultData + )( + implicit scheduler: ActorRef[SchedulerMessage], + activationAdapter: ActorRef[Activation], + resultDataMessageFromExtAdapter: ActorRef[ResultDataMessageFromExt], + buffer: StashBuffer[Request]): Behavior[Request] = { + Behaviors.receivePartial { + case (ctx, WrappedActivation(Activation(INIT_SIM_TICK))) => + val initGridSubscribers = initServiceData.extResultData.getGridResultDataAssets.asScala.toList + val initParticipantSubscribers = initServiceData.extResultData.getParticipantResultDataAssets.asScala.toList + + var initResultSchedule = Map.empty[Long, Set[UUID]] + initResultSchedule = initResultSchedule + (0L -> initParticipantSubscribers.toSet) + initResultSchedule = initResultSchedule + (initServiceData.extResultData.getPowerFlowResolution.longValue() -> initGridSubscribers.toSet) + + val resultInitializedStateData = ExtResultStateData( + extResultData = initServiceData.extResultData, + currentTick = INIT_SIM_TICK, + extResultScheduler = initResultSchedule + ) + scheduler ! Completion( + activationAdapter, + None + ) + idle(resultInitializedStateData) + } + + } + + private def idle(serviceStateData: ExtResultStateData)( + implicit scheduler: ActorRef[SchedulerMessage], + activationAdapter: ActorRef[Activation], + resultDataMessageFromExtAdapter: ActorRef[ResultDataMessageFromExt], + buffer: StashBuffer[Request], + ): Behavior[Request] = Behaviors + .receivePartial[Request] { + case (ctx, WrappedActivation(activation: Activation)) => + var updatedStateData = serviceStateData.handleActivation(activation) + //ctx.log.info(s"+++++++ Received Activation for tick ${updatedStateData.currentTick} +++++++") + + serviceStateData.extResultsMessage.getOrElse( + throw ServiceException( + "ExtResultDataService was triggered without ResultDataMessageFromExt available" + ) // this should not be possible because the external simulation schedules this service + ) match { + case msg: RequestResultEntities => // ExtResultDataProvider wurde aktiviert und es wurden Nachrichten von ExtSimulation angefragt + //ctx.log.info(s"[${updatedStateData.currentTick}] [requestResults] resultStorage = ${updatedStateData.resultStorage}\n extResultScheduler ${updatedStateData.extResultScheduler}") + + if (msg.tick == updatedStateData.currentTick) { // check, if we are in the right tick + var updatedSchedule = serviceStateData.extResultScheduler + val expectedKeys = serviceStateData.extResultScheduler.getOrElse( + activation.tick, + Set() + ) ++ serviceStateData.extResultScheduler.getOrElse(-2L, Set()) + val receiveDataMap = ReceiveDataMap[UUID, ModelResultEntity](expectedKeys) + updatedSchedule = updatedSchedule.-(activation.tick) + + //ctx.log.info(s"[${updatedStateData.currentTick}] [requestResults] updatedSchedule = $updatedSchedule \n receiveDataMap = $receiveDataMap") + + if (receiveDataMap.isComplete) { + // --- There are no expected results for this tick! Send the send right away! + //ctx.log.info(s"[requestResults] tick ${msg.tick} -> ReceiveDataMap is complete -> send it right away: ${serviceStateData.resultStorage}") + + serviceStateData.extResultData.queueExtResponseMsg( + new ProvideResultEntities(serviceStateData.resultStorage.asJava) + ) + //ctx.log.info("++++++++++++++++++ sended ExtResultData +++++++++++++++++++++++") + updatedStateData = updatedStateData.copy( + extResultsMessage = None, + receiveDataMap = None, + extResultScheduler = updatedSchedule + ) + } else { + //ctx.log.info(s"[requestResults] receiveDataMap was built -> now sending ResultRequestMessage") + ctx.self ! ResultRequestMessage(msg.tick) + updatedStateData = updatedStateData.copy( + extResultsMessage = None, + receiveDataMap = Some(receiveDataMap), + extResultScheduler = updatedSchedule + ) + } + } else { + throw ServiceException(s"Results for the wrong tick ${msg.tick} requested! We are currently in tick ${updatedStateData.currentTick}") + } + + } + + scheduler ! Completion(activationAdapter, None) + idle(updatedStateData) + + case (_, scheduleServiceActivationMsg: WrappedScheduleServiceActivationAdapter) => + scheduler ! ScheduleActivation( + activationAdapter, + scheduleServiceActivationMsg.scheduleServiceActivationMsg.tick, + Some(scheduleServiceActivationMsg.scheduleServiceActivationMsg.unlockKey), + ) + Behaviors.same + + case (ctx, extRequestResultEntitiesMsg: WrappedResultDataMessageFromExt) => + //ctx.log.info("Received WrappedResultDataMessageFromExt") + idle( + serviceStateData.copy( + extResultsMessage = Some(extRequestResultEntitiesMsg.extResultDataMessageFromExt) + )) + + case (ctx, extResultResponseMsg: ResultResponseMessage) => + if (serviceStateData.receiveDataMap.isDefined) { + // process dataResponses + if (serviceStateData.receiveDataMap.getOrElse(throw new Exception("There is no activation yet! Receive Data Map does not exist!")).getExpectedKeys.contains(extResultResponseMsg.result.getInputModel)) { + //ctx.log.info(s"[${serviceStateData.currentTick}] Process ResultsResponseMsg = ${extResultResponseMsg.result.getInputModel}\n receiveDataMap ${serviceStateData.receiveDataMap}\n MsgTick=${extResultResponseMsg.tick}, ServiceStateDataTick=${serviceStateData.currentTick}, nextTick = ${extResultResponseMsg.nextTick}") + + // --- Add received results to receiveDataMap + + if (extResultResponseMsg.tick == -4L || extResultResponseMsg.tick == serviceStateData.currentTick) { //FIXME Not expected results are unconsidered + val updatedReceiveDataMap = serviceStateData + .receiveDataMap + .getOrElse( + throw new Exception("noMap") + ).addData( + extResultResponseMsg.result.getInputModel, + extResultResponseMsg.result + ) + + //ctx.log.info("[hDRM] AddData to RecentResults -> updatedReceivedResults = " + updatedReceiveDataMap) + + // --- Update ResultStorage and Schedule + + val updatedResultStorage = serviceStateData.resultStorage + (extResultResponseMsg.result.getInputModel -> extResultResponseMsg.result) + var updatedResultSchedule = serviceStateData.extResultScheduler + //ctx.log.info(s"[hDRM] updatedResultSchedule = $updatedResultSchedule") + + updatedResultSchedule = extResultResponseMsg.nextTick.fold { + updatedResultSchedule.updated( + -3L, + updatedResultSchedule.getOrElse(-3L, Set[UUID]()) + extResultResponseMsg.result.getInputModel + ) + } { + newTick => + //ctx.log.info(s"[hDRM] update schedule = $newTick, uuid = ${extResultResponseMsg.result.getInputModel}") + updatedResultSchedule.updated( + newTick, + updatedResultSchedule.getOrElse(newTick, Set[UUID]()) + extResultResponseMsg.result.getInputModel + ) + } + + //ctx.log.info(s"[hDRM] updatedResultSchedule = $updatedResultSchedule") + //ctx.log.info(s"[hDRM] updatedResultStorage = $updatedResultStorage") + + // --- Check, if all expected results has been received + + if (updatedReceiveDataMap.nonComplete) { + //ctx.log.info(s"[${serviceStateData.currentTick}] There are still results missing...") + // There are still results missing... + idle(serviceStateData.copy( + receiveDataMap = Some(updatedReceiveDataMap), + resultStorage = updatedResultStorage, + extResultScheduler = updatedResultSchedule + )) + } else { + ctx.log.info(s"\u001b[0;34m[${serviceStateData.currentTick}] Got all ResultResponseMessage -> Now forward to external simulation in a bundle: $updatedResultStorage\u001b[0;0m") + // all responses received, forward them to external simulation in a bundle + serviceStateData.extResultData.queueExtResponseMsg( + new ProvideResultEntities(updatedResultStorage.asJava) + ) + //ctx.log.info("++++++++++++++++++ sended ExtResultData +++++++++++++++++++++++") + idle(serviceStateData.copy( + receiveDataMap = None, + resultStorage = updatedResultStorage, + extResultScheduler = updatedResultSchedule + )) + } + } else { + idle(serviceStateData) + } + } else { + idle(serviceStateData) + } + } else { + // the results arrived too early -> stash them away + buffer.stash(extResultResponseMsg) + idle(serviceStateData) + } + + case (ctx, msg: ResultRequestMessage) => + //ctx.log.info(s"[handleDataResponseMessage] Received ResultRequestMessage $msg -> Now unstash all buffered messages!") + buffer.unstashAll(idle(serviceStateData)) + + case (ctx, msg: DelayedStopHelper.StoppingMsg) => + DelayedStopHelper.handleMsg((ctx, msg)) + } + + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + final case class ExtResultStateData( + extResultData: ExtResultData, + currentTick: Long, + extResultsMessage: Option[ResultDataMessageFromExt] = None, + resultStorage: Map[UUID, ModelResultEntity] = Map.empty, + extResultScheduler: Map[Long, Set[UUID]] = Map.empty, + receiveDataMap: Option[ReceiveDataMap[UUID, ModelResultEntity]] = None, + ) { + def handleActivation(activation: Activation): ExtResultStateData = { + copy( + currentTick = activation.tick + ) + } + } + final case class InitExtResultData( + extResultData: ExtResultData + ) +} \ No newline at end of file diff --git a/src/main/scala/edu/ie3/simona/sim/SimonaSim.scala b/src/main/scala/edu/ie3/simona/sim/SimonaSim.scala index 9126926147..c0a8a22be8 100644 --- a/src/main/scala/edu/ie3/simona/sim/SimonaSim.scala +++ b/src/main/scala/edu/ie3/simona/sim/SimonaSim.scala @@ -70,30 +70,28 @@ object SimonaSim { ): Behavior[Request] = Behaviors .receivePartial[Request] { case (ctx, Start(_)) => - val resultEventListeners = - simonaSetup.resultEventListener(ctx) - val runtimeEventListener = simonaSetup.runtimeEventListener(ctx) val timeAdvancer = simonaSetup.timeAdvancer(ctx, ctx.self, runtimeEventListener) + val rootPhaseSwitch = simonaSetup.scheduler(ctx, timeAdvancer, PhaseSwitchCore) - // External simulations have to be scheduled for initialization first, - // so that the phase switch permanently activates them first - val extSimulationData: ExtSimSetupData = - simonaSetup.extSimulations(ctx, rootPhaseSwitch) - // scheduler for all actors besides external simulation, // which come second in line with phase switch val simScheduler = simonaSetup.scheduler(ctx, rootPhaseSwitch) + // External simulations have to be scheduled for initialization first, + // so that the phase switch permanently activates them first + val extSimulationData: ExtSimSetupData = + simonaSetup.extSimulations(ctx, rootPhaseSwitch, simScheduler) + /* start services */ // primary service proxy val primaryServiceProxy = - simonaSetup.primaryServiceProxy(ctx, simScheduler) + simonaSetup.primaryServiceProxy(ctx, simScheduler, extSimulationData) // weather service val weatherService = @@ -105,8 +103,12 @@ object SimonaSim { primaryServiceProxy, weatherService, extSimulationData.evDataService, + extSimulationData.extEmDataService ) + val resultEventListeners = + simonaSetup.resultEventListener(ctx, extSimulationData) + /* start grid agents */ val gridAgents = simonaSetup.gridAgents( ctx, @@ -128,18 +130,26 @@ object SimonaSim { /* watch all actors */ resultEventListeners.foreach(ctx.watch) ctx.watch(runtimeEventListener) + ctx.watch(extSimulationData.extResultDataService.getOrElse(throw new Exception(""))) extSimulationData.extSimAdapters.map(_.toTyped).foreach(ctx.watch) otherActors.foreach(ctx.watch) // Start simulation timeAdvancer ! TimeAdvancer.Start() + val delayedActors = resultEventListeners.appended(runtimeEventListener) + .appended( + extSimulationData.extResultDataService.getOrElse( + throw new Exception("Problem!") + ) + ) + idle( ActorData( starter, extSimulationData.extSimAdapters, runtimeEventListener, - resultEventListeners.appended(runtimeEventListener), + delayedActors, otherActors, ) ) diff --git a/src/main/scala/edu/ie3/simona/sim/setup/ExtSimSetupData.scala b/src/main/scala/edu/ie3/simona/sim/setup/ExtSimSetupData.scala index 40443cad5f..0d68368bfe 100644 --- a/src/main/scala/edu/ie3/simona/sim/setup/ExtSimSetupData.scala +++ b/src/main/scala/edu/ie3/simona/sim/setup/ExtSimSetupData.scala @@ -8,15 +8,50 @@ package edu.ie3.simona.sim.setup import edu.ie3.simona.ontology.messages.SchedulerMessage import org.apache.pekko.actor.{ActorRef => ClassicRef} +import edu.ie3.simona.api.data.ExtData +import edu.ie3.simona.api.data.ev.ExtEvData +import edu.ie3.simona.api.data.primarydata.ExtPrimaryData +import edu.ie3.simona.api.data.results.ExtResultData +import edu.ie3.simona.api.data.em.ExtEmData +import edu.ie3.simona.service.em.ExtEmDataService import edu.ie3.simona.service.ev.ExtEvDataService import org.apache.pekko.actor.typed.ActorRef +import edu.ie3.simona.service.primary.ExtPrimaryDataService +import edu.ie3.simona.service.results.ExtResultDataProvider +import edu.ie3.simona.service.results.ExtResultDataProvider.Request final case class ExtSimSetupData( - extSimAdapters: Iterable[ClassicRef], - extDataServices: Map[Class[_], ClassicRef], - extScheduler: Option[ActorRef[SchedulerMessage]], + extSimAdapters: Iterable[ClassicRef], + extDataServices: Map[Class[_], ClassicRef], + extDataListener: Map[Class[_], ActorRef[ExtResultDataProvider.Request]], + extDatas: Set[ExtData], + extScheduler: Option[ActorRef[SchedulerMessage]], ) { def evDataService: Option[ClassicRef] = extDataServices.get(classOf[ExtEvDataService]) + + def extPrimaryDataService: Option[ClassicRef] = + extDataServices.get(classOf[ExtPrimaryDataService]) + + def extEmDataService: Option[ClassicRef] = + extDataServices.get(classOf[ExtEmDataService]) + + def extResultDataService: Option[ActorRef[ExtResultDataProvider.Request]] = + extDataListener.get(ExtResultDataProvider.getClass) + + def extEvData: Option[ExtEvData] = { + extDatas.collectFirst { case extData: ExtEvData => extData } + } + def extPrimaryData: Option[ExtPrimaryData] = { + extDatas.collectFirst { case extData: ExtPrimaryData => extData } + } + + def extEmData: Option[ExtEmData] = { + extDatas.collectFirst { case extData: ExtEmData => extData } + } + + def extResultData: Option[ExtResultData] = { + extDatas.collectFirst { case extData: ExtResultData => extData } + } } diff --git a/src/main/scala/edu/ie3/simona/sim/setup/SimonaExtSimSetup.scala b/src/main/scala/edu/ie3/simona/sim/setup/SimonaExtSimSetup.scala new file mode 100644 index 0000000000..3fad0bbb75 --- /dev/null +++ b/src/main/scala/edu/ie3/simona/sim/setup/SimonaExtSimSetup.scala @@ -0,0 +1,539 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.sim.setup + +import com.typesafe.config.Config +import edu.ie3.datamodel.graph.SubGridTopologyGraph +import edu.ie3.datamodel.models.input.container.{GridContainer, ThermalGrid} +import edu.ie3.datamodel.models.input.thermal.ThermalBusInput +import edu.ie3.simona.actor.SimonaActorNaming.RichActorRefFactory +import edu.ie3.simona.agent.EnvironmentRefs +import edu.ie3.simona.agent.grid.GridAgent +import edu.ie3.simona.agent.grid.GridAgentMessages.CreateGridAgent +import edu.ie3.simona.api.ExtSimAdapter +import edu.ie3.simona.api.data.em.ExtEmData +import edu.ie3.simona.api.data.primarydata.ExtPrimaryData +import edu.ie3.simona.api.data.results.ExtResultData +import edu.ie3.simona.api.data.results.ontology.ResultDataMessageFromExt +import edu.ie3.simona.api.simulation.{ExtSimAdapterData, ExtSimulation} +import edu.ie3.simona.config.{ArgsParser, RefSystemParser, SimonaConfig} +import edu.ie3.simona.event.listener.{ResultEventListener, RuntimeEventListener} +import edu.ie3.simona.event.{ResultEvent, RuntimeEvent} +import edu.ie3.simona.exceptions.agent.GridAgentInitializationException +import edu.ie3.simona.io.grid.GridProvider +import edu.ie3.simona.ontology.messages.SchedulerMessage +import edu.ie3.simona.ontology.messages.SchedulerMessage.ScheduleActivation +import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.ScheduleServiceActivation +import edu.ie3.simona.scheduler.core.Core.CoreFactory +import edu.ie3.simona.scheduler.core.RegularSchedulerCore +import edu.ie3.simona.scheduler.{ScheduleLock, Scheduler, TimeAdvancer} +import edu.ie3.simona.service.SimonaService +import edu.ie3.simona.service.em.ExtEmDataService +import edu.ie3.simona.service.em.ExtEmDataService.InitExtEmData +import edu.ie3.simona.service.primary.ExtPrimaryDataService.InitExtPrimaryData +import edu.ie3.simona.service.primary.PrimaryServiceProxy.InitPrimaryServiceProxyStateData +import edu.ie3.simona.service.primary.{ExtPrimaryDataService, PrimaryServiceProxy} +import edu.ie3.simona.service.results.ExtResultDataProvider +import edu.ie3.simona.service.results.ExtResultDataProvider.{InitExtResultData, RequestDataMessageAdapter, RequestScheduleActivationAdapter} +import edu.ie3.simona.service.weather.WeatherService +import edu.ie3.simona.service.weather.WeatherService.InitWeatherServiceStateData +import edu.ie3.simona.sim.SimonaSim +import edu.ie3.simona.util.ResultFileHierarchy +import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import edu.ie3.simona.util.TickUtil.RichZonedDateTime +import edu.ie3.util.TimeUtil +import org.apache.pekko.actor.typed.scaladsl.ActorContext +import org.apache.pekko.actor.typed.scaladsl.AskPattern._ +import org.apache.pekko.actor.typed.scaladsl.adapter.{ClassicActorRefOps, TypedActorContextOps, TypedActorRefOps} +import org.apache.pekko.actor.typed.{ActorRef, Scheduler} +import org.apache.pekko.actor.{ActorRef => ClassicRef} +import org.apache.pekko.util.{Timeout => PekkoTimeout} + +import java.time.ZonedDateTime +import java.time.temporal.ChronoUnit +import java.util.UUID +import java.util.concurrent.LinkedBlockingQueue +import scala.collection.mutable +import scala.concurrent.Await +import scala.concurrent.duration.DurationInt +import scala.jdk.CollectionConverters._ +import scala.jdk.DurationConverters._ + +/** Sample implementation to run a standalone simulation of simona configured + * with the provided [[SimonaConfig]] and [[ResultFileHierarchy]] + * + * @version 0.1 + * @since 01.07.20 + */ +abstract class SimonaExtSimSetup( + val typeSafeConfig: Config, + val simonaConfig: SimonaConfig, + val resultFileHierarchy: ResultFileHierarchy, + val runtimeEventQueue: Option[LinkedBlockingQueue[RuntimeEvent]] = None, + override val args: Array[String] +) extends SimonaSetup { + override def logOutputDir: String = resultFileHierarchy.logOutputDir + + override def gridAgents( + context: ActorContext[_], + environmentRefs: EnvironmentRefs, + resultEventListeners: Seq[ActorRef[ResultEvent]], + ): Iterable[ActorRef[GridAgent.Request]] = { + + /* get the grid */ + val subGridTopologyGraph = GridProvider + .gridFromConfig( + simonaConfig.simona.simulationName, + simonaConfig.simona.input.grid.datasource, + ) + .getSubGridTopologyGraph + val thermalGridsByThermalBus = GridProvider.getThermalGridsFromConfig( + simonaConfig.simona.input.grid.datasource + ) + + /* extract and prepare refSystem information from config */ + val configRefSystems = + RefSystemParser.parse(simonaConfig.simona.gridConfig.refSystems) + + /* Create all agents and map the sub grid id to their actor references */ + val subGridToActorRefMap = buildSubGridToActorRefMap( + subGridTopologyGraph, + context, + environmentRefs, + resultEventListeners, + ) + + val keys = ScheduleLock.multiKey( + context, + environmentRefs.scheduler, + INIT_SIM_TICK, + subGridTopologyGraph.vertexSet().size, + ) + + /* build the initialization data */ + subGridTopologyGraph + .vertexSet() + .asScala + .zip(keys) + .map { case (subGridContainer, key) => + /* Get all connections to superior and inferior sub grids */ + val subGridGates = + Set.from( + subGridTopologyGraph + .edgesOf(subGridContainer) + .asScala + .map(modifySubGridGateForThreeWindingSupport) + ) + val currentSubGrid = subGridContainer.getSubnet + val currentActorRef = subGridToActorRefMap.getOrElse( + currentSubGrid, + throw new GridAgentInitializationException( + "Was asked to setup agent for sub grid " + currentSubGrid + ", but did not found it's actor reference." + ), + ) + val thermalGrids = + getThermalGrids(subGridContainer, thermalGridsByThermalBus) + + /* build the grid agent data and check for its validity */ + val gridAgentInitData = SimonaStandaloneSetup.buildGridAgentInitData( + subGridContainer, + subGridToActorRefMap, + subGridGates, + configRefSystems, + thermalGrids, + ) + + currentActorRef ! CreateGridAgent(gridAgentInitData, key) + + currentActorRef + } + } + + override def primaryServiceProxy( + context: ActorContext[_], + scheduler: ActorRef[SchedulerMessage], + extSimSetupData: ExtSimSetupData, + ): ClassicRef = { + val simulationStart = TimeUtil.withDefaults.toZonedDateTime( + simonaConfig.simona.time.startDateTime + ) + val primaryServiceProxy = context.toClassic.simonaActorOf( + PrimaryServiceProxy.props( + scheduler.toClassic, + InitPrimaryServiceProxyStateData( + simonaConfig.simona.input.primary, + simulationStart, + extSimSetupData.extPrimaryDataService, + extSimSetupData.extPrimaryData + ), + simulationStart, + ) + ) + + scheduler ! ScheduleActivation(primaryServiceProxy.toTyped, INIT_SIM_TICK) + primaryServiceProxy + } + + override def weatherService( + context: ActorContext[_], + scheduler: ActorRef[SchedulerMessage], + ): ClassicRef = { + val weatherService = context.toClassic.simonaActorOf( + WeatherService.props( + scheduler.toClassic, + TimeUtil.withDefaults + .toZonedDateTime(simonaConfig.simona.time.startDateTime), + TimeUtil.withDefaults + .toZonedDateTime(simonaConfig.simona.time.endDateTime), + ) + ) + weatherService ! SimonaService.Create( + InitWeatherServiceStateData( + simonaConfig.simona.input.weather.datasource + ), + ScheduleLock.singleKey(context, scheduler, INIT_SIM_TICK), + ) + + weatherService + } + + override def timeAdvancer( + context: ActorContext[_], + simulation: ActorRef[SimonaSim.SimulationEnded.type], + runtimeEventListener: ActorRef[RuntimeEvent], + ): ActorRef[TimeAdvancer.Request] = { + val startDateTime = TimeUtil.withDefaults.toZonedDateTime( + simonaConfig.simona.time.startDateTime + ) + val endDateTime = TimeUtil.withDefaults.toZonedDateTime( + simonaConfig.simona.time.endDateTime + ) + + context.spawn( + TimeAdvancer( + simulation, + Some(runtimeEventListener), + simonaConfig.simona.time.schedulerReadyCheckWindow, + endDateTime.toTick(startDateTime), + ), + TimeAdvancer.getClass.getSimpleName, + ) + } + + override def scheduler( + context: ActorContext[_], + parent: ActorRef[SchedulerMessage], + coreFactory: CoreFactory = RegularSchedulerCore, + ): ActorRef[SchedulerMessage] = + context + .spawn( + Scheduler(parent, coreFactory), + s"${Scheduler.getClass.getSimpleName}_${coreFactory}_${UUID.randomUUID()}", + ) + + override def runtimeEventListener( + context: ActorContext[_] + ): ActorRef[RuntimeEventListener.Request] = + context + .spawn( + RuntimeEventListener( + simonaConfig.simona.runtime.listener, + runtimeEventQueue, + startDateTimeString = simonaConfig.simona.time.startDateTime, + ), + RuntimeEventListener.getClass.getSimpleName, + ) + + override def resultEventListener( + context: ActorContext[_], + extSimulationData: ExtSimSetupData, + ): Seq[ActorRef[ResultEventListener.Request]] = { + val extResultDataService: Option[ActorRef[ExtResultDataProvider.Request]] = + extSimulationData.extResultDataService + // append ResultEventListener as well to write raw output files + ArgsParser + .parseListenerConfigOption(simonaConfig.simona.event.listener) + .zipWithIndex + .map { case ((listenerCompanion, events), index) => + context.toClassic + .simonaActorOf( + listenerCompanion.props(events), + index.toString, + ) + .toTyped + } + .toSeq :+ context + .spawn( + ResultEventListener( + resultFileHierarchy, + extResultDataService, + ), + ResultEventListener.getClass.getSimpleName, + ) + } + + def buildSubGridToActorRefMap( + subGridTopologyGraph: SubGridTopologyGraph, + context: ActorContext[_], + environmentRefs: EnvironmentRefs, + resultEventListeners: Seq[ActorRef[ResultEvent]], + ): Map[Int, ActorRef[GridAgent.Request]] = { + subGridTopologyGraph + .vertexSet() + .asScala + .map(subGridContainer => { + val gridAgentRef = + context.spawn( + GridAgent( + environmentRefs, + simonaConfig, + resultEventListeners, + ), + subGridContainer.getSubnet.toString, + ) + subGridContainer.getSubnet -> gridAgentRef + }) + .toMap + } + + /** Get all thermal grids, that apply for the given grid container + * @param grid + * The grid container to assess + * @param thermalGridByBus + * Mapping from thermal bus to thermal grid + * @return + * A sequence of applicable thermal grids + */ + private def getThermalGrids( + grid: GridContainer, + thermalGridByBus: Map[ThermalBusInput, ThermalGrid], + ): Seq[ThermalGrid] = { + grid.getSystemParticipants.getHeatPumps.asScala + .flatten(hpInput => thermalGridByBus.get(hpInput.getThermalBus)) + .toSeq + } + + + def extSimulationSetup( + context: ActorContext[_], + rootScheduler: ActorRef[SchedulerMessage], + simScheduler: ActorRef[SchedulerMessage], + extSim: ExtSimulation + ): ExtSimSetupData = { + val extScheduler = scheduler(context, rootScheduler) + + // ExtSimAdapter + val extSimAdapterPhase1 = context.toClassic.simonaActorOf( + ExtSimAdapter.props(extScheduler.toClassic), + s"1", + ) + + val extSimAdapterPhase2 = context.toClassic.simonaActorOf( + ExtSimAdapter.props(simScheduler.toClassic), + s"2", + ) + + val extSimAdapters: Map[java.lang.Integer, ClassicRef] = Map( + 1.asInstanceOf[java.lang.Integer] -> extSimAdapterPhase1, + 2.asInstanceOf[java.lang.Integer] -> extSimAdapterPhase2 + ) + + val extSimAdapterData = new ExtSimAdapterData(extSimAdapters.asJava, args) + + val extDataServicesMap: mutable.Map[Class[_], ClassicRef] = mutable.Map.empty + val extDataListenerMap: mutable.Map[Class[_], ActorRef[ExtResultDataProvider.Request]] = mutable.Map.empty + + val dataConnections = extSim.getDataConnections + + dataConnections.asScala.foreach { + case extPrimaryData: ExtPrimaryData => + val extPrimaryDataService = extPrimaryDataSimulationSetup( + context, + extScheduler, + extSimAdapterData, + extPrimaryData + ) + extDataServicesMap += (classOf[ExtPrimaryDataService] -> extPrimaryDataService) + + + case extResultData: ExtResultData => + val extResultDataProvider = extResultDataSimulationSetup( + context, + simScheduler, + extSimAdapterData, + extResultData, + TimeUtil.withDefaults.toZonedDateTime( + simonaConfig.simona.time.startDateTime + ), + simonaConfig.simona.powerflow.resolution.get( + ChronoUnit.SECONDS + ) + ) + extDataListenerMap += (ExtResultDataProvider.getClass -> extResultDataProvider) + + + case extEmData: ExtEmData => + val extEmDataService = extEmDataSimulationSetup( + context, + extScheduler, + extSimAdapterData, + extEmData + ) + extDataServicesMap += (classOf[ExtEmDataService] -> extEmDataService) + + } + extSim.setup( + extSimAdapterData, + dataConnections + ) + new Thread(extSim, s"External simulation").start() + + ExtSimSetupData( + Iterable( + extSimAdapterData.getPhase1Adapter, + extSimAdapterData.getPhase2Adapter + ), + extDataServicesMap.toMap, + extDataListenerMap.toMap, + dataConnections.asScala.toSet, + Some(extScheduler) + ) + } + + private def extPrimaryDataSimulationSetup( + context: ActorContext[_], + extScheduler: ActorRef[SchedulerMessage], + extSimAdapterData: ExtSimAdapterData, + extPrimaryData: ExtPrimaryData + ): ClassicRef = { + val extSimAdapterPhase1 = extSimAdapterData.getPhase1Adapter + + // send init data right away, init activation is scheduled + extSimAdapterPhase1 ! ExtSimAdapter.Create( + extSimAdapterData, + 1, + ScheduleLock.singleKey(context, extScheduler, INIT_SIM_TICK), + ) + + val extPrimaryDataService = context.toClassic.simonaActorOf( + ExtPrimaryDataService.props(extScheduler.toClassic), + s"0-0", + ) + + extPrimaryData.setActorRefs( + extPrimaryDataService, + extSimAdapterPhase1 + ) + + extPrimaryDataService ! SimonaService.Create( + InitExtPrimaryData(extPrimaryData), + ScheduleLock.singleKey( + context, + extScheduler, + INIT_SIM_TICK, + ), + ) + println("... pause extPrimaryDataSimulationSetup ...") + Thread.sleep(3000) + extPrimaryDataService + } + + + private def extEmDataSimulationSetup( + context: ActorContext[_], + extScheduler: ActorRef[SchedulerMessage], + extSimAdapterData: ExtSimAdapterData, + extEmData: ExtEmData + ): ClassicRef = { + val extSimAdapterPhase1 = extSimAdapterData.getPhase1Adapter + + // send init data right away, init activation is scheduled + extSimAdapterPhase1 ! ExtSimAdapter.Create( + extSimAdapterData, + 1, + ScheduleLock.singleKey(context, extScheduler, INIT_SIM_TICK), + ) + + val extEmDataService = context.toClassic.simonaActorOf( + ExtEmDataService.props(extScheduler.toClassic), + s"0-0", + ) + + extEmData.setActorRefs( + extEmDataService, + extSimAdapterPhase1 + ) + + extEmDataService ! SimonaService.Create( + InitExtEmData(extEmData), + ScheduleLock.singleKey( + context, + extScheduler, + INIT_SIM_TICK, + ), + ) + println("... pause extEmDataSimulationSetup ...") + Thread.sleep(3000) + extEmDataService + } + + + private def extResultDataSimulationSetup( + context: ActorContext[_], + simScheduler: ActorRef[SchedulerMessage], + extSimAdapterData: ExtSimAdapterData, + extResultData: ExtResultData, + simulationStart: ZonedDateTime, + powerFlowResolution: Long + ): ActorRef[ExtResultDataProvider.Request] = { + val extResultDataProvider = { + context.spawn( + ExtResultDataProvider(simScheduler), + s"ExtResultDataProvider", + ) + } + + val timeout: PekkoTimeout = PekkoTimeout.create(5.seconds.toJava) + val scheduler2: Scheduler = context.system.scheduler + + val adapterRef = Await.result( + extResultDataProvider.ask[ActorRef[ResultDataMessageFromExt]](ref => RequestDataMessageAdapter(ref))(timeout, scheduler2), timeout.duration) + val adapterScheduleRef = Await.result( + extResultDataProvider.ask[ActorRef[ScheduleServiceActivation]](ref => RequestScheduleActivationAdapter(ref))(timeout, scheduler2), timeout.duration) + + val extSimAdapterPhase2 = extSimAdapterData.getPhase2Adapter + + extResultData.setActorRefs( + adapterRef.toClassic, + adapterScheduleRef.toClassic, + extSimAdapterPhase2 + ) + + extResultData.setSimulationData( + simulationStart, + powerFlowResolution + ) + + extResultDataProvider ! ExtResultDataProvider.Create( + InitExtResultData(extResultData), + ScheduleLock.singleKey( + context, + simScheduler, + INIT_SIM_TICK, + ), + ) + extSimAdapterPhase2 ! ExtSimAdapter.Create( + extSimAdapterData, + 2, + ScheduleLock.singleKey(context, simScheduler, INIT_SIM_TICK), + ) + println("... pause extResultDataSimulationSetup ...") + Thread.sleep(3000) + extResultDataProvider + } + +} diff --git a/src/main/scala/edu/ie3/simona/sim/setup/SimonaMosaikSetup.scala b/src/main/scala/edu/ie3/simona/sim/setup/SimonaMosaikSetup.scala new file mode 100644 index 0000000000..6bc388a60e --- /dev/null +++ b/src/main/scala/edu/ie3/simona/sim/setup/SimonaMosaikSetup.scala @@ -0,0 +1,83 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.sim.setup + +import com.typesafe.config.Config +import com.typesafe.scalalogging.LazyLogging +import edu.ie3.simona.config.SimonaConfig +import edu.ie3.simona.event.RuntimeEvent +import edu.ie3.simona.ontology.messages.SchedulerMessage +import edu.ie3.simona.util.ResultFileHierarchy +import edu.ie3.simosaik.simosaikElectrolyzer.MosaikElectrolyzerSimulation +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.typed.scaladsl.ActorContext + +import java.nio.file.Path +import java.util.concurrent.LinkedBlockingQueue + +/** Sample implementation to run a standalone simulation of simona configured + * with the provided [[SimonaConfig]] and [[ResultFileHierarchy]] + * + * @version 0.1 + * @since 01.07.20 + */ +class SimonaMosaikSetup( + override val typeSafeConfig: Config, + override val simonaConfig: SimonaConfig, + override val resultFileHierarchy: ResultFileHierarchy, + override val runtimeEventQueue: Option[LinkedBlockingQueue[RuntimeEvent]] = None, + override val args: Array[String], + mosaikIP: Option[String] = None, + mosaikMappingPath: Option[String] = None +) extends SimonaExtSimSetup( + typeSafeConfig, + simonaConfig, + resultFileHierarchy, + runtimeEventQueue, + args +) { + override def extSimulations( + context: ActorContext[_], + rootScheduler: ActorRef[SchedulerMessage], + simScheduler: ActorRef[SchedulerMessage] + ): ExtSimSetupData = { + val mosaikAddress = mosaikIP.getOrElse("127.0.0.1:5678") + val mosaikMapping = mosaikMappingPath.getOrElse(throw new RuntimeException("Cannot connect to Mosaik, because there is no mapping!")) + val mosaikExtSim = new MosaikElectrolyzerSimulation(mosaikAddress, Path.of(mosaikMapping)) + + extSimulationSetup( + context, + rootScheduler, + simScheduler, + mosaikExtSim + ) + } +} + +/** Companion object to provide [[SetupHelper]] methods for + * [[SimonaStandaloneSetup]] + */ +object SimonaMosaikSetup extends LazyLogging with SetupHelper { + + def apply( + typeSafeConfig: Config, + resultFileHierarchy: ResultFileHierarchy, + runtimeEventQueue: Option[LinkedBlockingQueue[RuntimeEvent]] = None, + mainArgs: Array[String] = Array.empty[String], + mosaikIP: Option[String] = None, + mosaikMappingPath: Option[String] = None + ): SimonaMosaikSetup = + new SimonaMosaikSetup( + typeSafeConfig, + SimonaConfig(typeSafeConfig), + resultFileHierarchy, + runtimeEventQueue, + mainArgs, + mosaikIP, + mosaikMappingPath + ) +} diff --git a/src/main/scala/edu/ie3/simona/sim/setup/SimonaOpsimSetup.scala b/src/main/scala/edu/ie3/simona/sim/setup/SimonaOpsimSetup.scala new file mode 100644 index 0000000000..ea8d361f21 --- /dev/null +++ b/src/main/scala/edu/ie3/simona/sim/setup/SimonaOpsimSetup.scala @@ -0,0 +1,86 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.sim.setup + +import com.typesafe.config.Config +import com.typesafe.scalalogging.LazyLogging +import edu.ie3.simona.config.SimonaConfig +import edu.ie3.simona.event.RuntimeEvent +import edu.ie3.simona.ontology.messages.SchedulerMessage +import edu.ie3.simona.util.ResultFileHierarchy +import edu.ie3.simopsim.simopsimEm.OpsimEmSimulation +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.typed.scaladsl.ActorContext + +import java.nio.file.Path +import java.util.concurrent.LinkedBlockingQueue + +/** Sample implementation to run a standalone simulation of simona configured + * with the provided [[SimonaConfig]] and [[ResultFileHierarchy]] + * + * @version 0.1 + * @since 01.07.20 + */ +class SimonaOpsimSetup( + override val typeSafeConfig: Config, + override val simonaConfig: SimonaConfig, + override val resultFileHierarchy: ResultFileHierarchy, + override val runtimeEventQueue: Option[LinkedBlockingQueue[RuntimeEvent]] = None, + override val args: Array[String], + opsimIP: Option[String] = None, + opsimMappingPath: Option[String] = None, +) extends SimonaExtSimSetup( + typeSafeConfig, + simonaConfig, + resultFileHierarchy, + runtimeEventQueue, + args +) { + + override def extSimulations( + context: ActorContext[_], + rootScheduler: ActorRef[SchedulerMessage], + simScheduler: ActorRef[SchedulerMessage], + ): ExtSimSetupData = { + // OpSim Simulation + val opsimAddress = opsimIP.getOrElse(throw new RuntimeException("Cannot connect to Opsim, because there is no address!")) + val opsimMapping = opsimMappingPath.getOrElse(throw new RuntimeException("Cannot connect to Opsim, because there is no mapping!")) + + val opsimSim = new OpsimEmSimulation(opsimAddress, Path.of(opsimMapping)) + + extSimulationSetup( + context, + rootScheduler, + simScheduler, + opsimSim + ) + } +} + + +/** Companion object to provide [[SetupHelper]] methods for + * [[SimonaStandaloneSetup]] + */ +object SimonaOpsimSetup extends LazyLogging with SetupHelper { + def apply( + typeSafeConfig: Config, + resultFileHierarchy: ResultFileHierarchy, + runtimeEventQueue: Option[LinkedBlockingQueue[RuntimeEvent]] = None, + mainArgs: Array[String] = Array.empty[String], + opsimIP: Option[String] = None, + opsimMapping: Option[String] = None + ): SimonaOpsimSetup = + new SimonaOpsimSetup( + typeSafeConfig, + SimonaConfig(typeSafeConfig), + resultFileHierarchy, + runtimeEventQueue, + mainArgs, + opsimIP, + opsimMapping + ) +} diff --git a/src/main/scala/edu/ie3/simona/sim/setup/SimonaSetup.scala b/src/main/scala/edu/ie3/simona/sim/setup/SimonaSetup.scala index bfb4e16cee..63db3d90bf 100644 --- a/src/main/scala/edu/ie3/simona/sim/setup/SimonaSetup.scala +++ b/src/main/scala/edu/ie3/simona/sim/setup/SimonaSetup.scala @@ -61,7 +61,8 @@ trait SimonaSetup { * A sequence of actor references to result event listeners */ def resultEventListener( - context: ActorContext[_] + context: ActorContext[_], + extSimulationData: ExtSimSetupData, ): Seq[ActorRef[ResultEventListener.Request]] /** Creates a primary service proxy. The proxy is the first instance to ask @@ -78,6 +79,7 @@ trait SimonaSetup { def primaryServiceProxy( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], + extSimulationData: ExtSimSetupData, ): ClassicRef /** Creates a weather service @@ -107,6 +109,7 @@ trait SimonaSetup { def extSimulations( context: ActorContext[_], rootScheduler: ActorRef[SchedulerMessage], + simScheduler: ActorRef[SchedulerMessage], ): ExtSimSetupData /** Creates the time advancer diff --git a/src/main/scala/edu/ie3/simona/sim/setup/SimonaSimpleExtSimulationSetup.scala b/src/main/scala/edu/ie3/simona/sim/setup/SimonaSimpleExtSimulationSetup.scala new file mode 100644 index 0000000000..18bbfca34a --- /dev/null +++ b/src/main/scala/edu/ie3/simona/sim/setup/SimonaSimpleExtSimulationSetup.scala @@ -0,0 +1,103 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.sim.setup + +import com.typesafe.config.Config +import com.typesafe.scalalogging.LazyLogging +import edu.ie3.datamodel.graph.SubGridTopologyGraph +import edu.ie3.datamodel.models.input.container.{GridContainer, ThermalGrid} +import edu.ie3.datamodel.models.input.thermal.ThermalBusInput +import edu.ie3.simona.actor.SimonaActorNaming.RichActorRefFactory +import edu.ie3.simona.agent.EnvironmentRefs +import edu.ie3.simona.agent.grid.GridAgent +import edu.ie3.simona.agent.grid.GridAgentMessages.CreateGridAgent +import edu.ie3.simona.config.{ArgsParser, RefSystemParser, SimonaConfig} +import edu.ie3.simona.event.listener.{ResultEventListener, RuntimeEventListener} +import edu.ie3.simona.event.{ResultEvent, RuntimeEvent} +import edu.ie3.simona.exceptions.agent.GridAgentInitializationException +import edu.ie3.simona.io.grid.GridProvider +import edu.ie3.simona.ontology.messages.SchedulerMessage +import edu.ie3.simona.ontology.messages.SchedulerMessage.ScheduleActivation +import edu.ie3.simona.scheduler.core.Core.CoreFactory +import edu.ie3.simona.scheduler.core.RegularSchedulerCore +import edu.ie3.simona.scheduler.{ScheduleLock, Scheduler, TimeAdvancer} +import edu.ie3.simona.service.SimonaService +import edu.ie3.simona.service.primary.PrimaryServiceProxy +import edu.ie3.simona.service.primary.PrimaryServiceProxy.InitPrimaryServiceProxyStateData +import edu.ie3.simona.service.results.ExtResultDataProvider +import edu.ie3.simona.service.weather.WeatherService +import edu.ie3.simona.service.weather.WeatherService.InitWeatherServiceStateData +import edu.ie3.simona.sim.SimonaSim +import edu.ie3.simona.util.ResultFileHierarchy +import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import edu.ie3.simona.util.TickUtil.RichZonedDateTime +import edu.ie3.simpleextsim.SimpleExtSimulationWithEm +import edu.ie3.util.TimeUtil +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.typed.scaladsl.ActorContext +import org.apache.pekko.actor.typed.scaladsl.adapter.{ClassicActorRefOps, TypedActorContextOps, TypedActorRefOps} +import org.apache.pekko.actor.{ActorRef => ClassicRef} + +import java.util.UUID +import java.util.concurrent.LinkedBlockingQueue +import scala.jdk.CollectionConverters._ + +/** Sample implementation to run a standalone simulation of simona configured + * with the provided [[SimonaConfig]] and [[ResultFileHierarchy]] + * + * @version 0.1 + * @since 01.07.20 + */ +class SimonaSimpleExtSimulationSetup( + override val typeSafeConfig: Config, + override val simonaConfig: SimonaConfig, + override val resultFileHierarchy: ResultFileHierarchy, + override val runtimeEventQueue: Option[LinkedBlockingQueue[RuntimeEvent]] = None, + override val args: Array[String], +) extends SimonaExtSimSetup( + typeSafeConfig, + simonaConfig, + resultFileHierarchy, + runtimeEventQueue, + args +) { + + override def extSimulations( + context: ActorContext[_], + rootScheduler: ActorRef[SchedulerMessage], + simScheduler: ActorRef[SchedulerMessage], + ): ExtSimSetupData = { + val simpleExtSim = new SimpleExtSimulationWithEm() + + extSimulationSetup( + context, + rootScheduler, + simScheduler, + simpleExtSim + ) + } +} + +/** Companion object to provide [[SetupHelper]] methods for + * [[SimonaStandaloneSetup]] + */ +object SimonaSimpleExtSimulationSetup extends LazyLogging with SetupHelper { + + def apply( + typeSafeConfig: Config, + resultFileHierarchy: ResultFileHierarchy, + runtimeEventQueue: Option[LinkedBlockingQueue[RuntimeEvent]] = None, + mainArgs: Array[String] = Array.empty[String], + ): SimonaSimpleExtSimulationSetup = + new SimonaSimpleExtSimulationSetup( + typeSafeConfig, + SimonaConfig(typeSafeConfig), + resultFileHierarchy, + runtimeEventQueue, + mainArgs, + ) +} diff --git a/src/main/scala/edu/ie3/simona/sim/setup/SimonaStandaloneSetup.scala b/src/main/scala/edu/ie3/simona/sim/setup/SimonaStandaloneSetup.scala index 32711a4a3d..5f8745abf0 100644 --- a/src/main/scala/edu/ie3/simona/sim/setup/SimonaStandaloneSetup.scala +++ b/src/main/scala/edu/ie3/simona/sim/setup/SimonaStandaloneSetup.scala @@ -15,10 +15,6 @@ import edu.ie3.simona.actor.SimonaActorNaming.RichActorRefFactory import edu.ie3.simona.agent.EnvironmentRefs import edu.ie3.simona.agent.grid.GridAgent import edu.ie3.simona.agent.grid.GridAgentMessages.CreateGridAgent -import edu.ie3.simona.api.ExtSimAdapter -import edu.ie3.simona.api.data.ExtData -import edu.ie3.simona.api.data.ev.{ExtEvData, ExtEvSimulation} -import edu.ie3.simona.api.simulation.ExtSimAdapterData import edu.ie3.simona.config.{ArgsParser, RefSystemParser, SimonaConfig} import edu.ie3.simona.event.listener.{ResultEventListener, RuntimeEventListener} import edu.ie3.simona.event.{ResultEvent, RuntimeEvent} @@ -30,10 +26,9 @@ import edu.ie3.simona.scheduler.core.Core.CoreFactory import edu.ie3.simona.scheduler.core.RegularSchedulerCore import edu.ie3.simona.scheduler.{ScheduleLock, Scheduler, TimeAdvancer} import edu.ie3.simona.service.SimonaService -import edu.ie3.simona.service.ev.ExtEvDataService -import edu.ie3.simona.service.ev.ExtEvDataService.InitExtEvData import edu.ie3.simona.service.primary.PrimaryServiceProxy import edu.ie3.simona.service.primary.PrimaryServiceProxy.InitPrimaryServiceProxyStateData +import edu.ie3.simona.service.results.ExtResultDataProvider import edu.ie3.simona.service.weather.WeatherService import edu.ie3.simona.service.weather.WeatherService.InitWeatherServiceStateData import edu.ie3.simona.sim.SimonaSim @@ -43,11 +38,7 @@ import edu.ie3.simona.util.TickUtil.RichZonedDateTime import edu.ie3.util.TimeUtil import org.apache.pekko.actor.typed.ActorRef import org.apache.pekko.actor.typed.scaladsl.ActorContext -import org.apache.pekko.actor.typed.scaladsl.adapter.{ - ClassicActorRefOps, - TypedActorContextOps, - TypedActorRefOps, -} +import org.apache.pekko.actor.typed.scaladsl.adapter.{ClassicActorRefOps, TypedActorContextOps, TypedActorRefOps} import org.apache.pekko.actor.{ActorRef => ClassicRef} import java.util.UUID @@ -148,6 +139,7 @@ class SimonaStandaloneSetup( override def primaryServiceProxy( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], + extSimSetupData: ExtSimSetupData, ): ClassicRef = { val simulationStart = TimeUtil.withDefaults.toZonedDateTime( simonaConfig.simona.time.startDateTime @@ -158,6 +150,8 @@ class SimonaStandaloneSetup( InitPrimaryServiceProxyStateData( simonaConfig.simona.input.primary, simulationStart, + extSimSetupData.extPrimaryDataService, + extSimSetupData.extPrimaryData ), simulationStart, ) @@ -189,6 +183,7 @@ class SimonaStandaloneSetup( weatherService } + /* override def extSimulations( context: ActorContext[_], @@ -201,7 +196,7 @@ class SimonaStandaloneSetup( if (extLinks.nonEmpty) { val extScheduler = scheduler(context, parent = rootScheduler) - val (extSimAdapters, extDataServices) = + val (extSimAdapters, extDatasAndServices) = extLinks.zipWithIndex.map { case (extLink, index) => // external simulation always needs at least an ExtSimAdapter val extSimAdapter = context.toClassic.simonaActorOf( @@ -217,9 +212,9 @@ class SimonaStandaloneSetup( ) // setup data services that belong to this external simulation - val (extData, extDataInit): ( + val (extData, extDataServiceToRef): ( Iterable[ExtData], - Iterable[(Class[_ <: SimonaService[_]], ClassicRef)], + Iterable[(Class[_], ClassicRef)], ) = extLink.getExtDataSimulations.asScala.zipWithIndex.map { case (_: ExtEvSimulation, dIndex) => @@ -239,30 +234,111 @@ class SimonaStandaloneSetup( ) (extEvData, (classOf[ExtEvDataService], extEvDataService)) + + case (extPrimaryDataSimulation: ExtPrimaryDataSimulation, dIndex) => + val extPrimaryDataService = context.toClassic.simonaActorOf( + ExtPrimaryDataService.props(extScheduler.toClassic), + s"$index-$dIndex", + ) + val extPrimaryData = new ExtPrimaryData( + extPrimaryDataService, + extSimAdapter, + extPrimaryDataSimulation.getPrimaryDataFactory, + extPrimaryDataSimulation.getPrimaryDataAssets + ) + + extPrimaryDataSimulation.setExtPrimaryData(extPrimaryData) + + extPrimaryDataService ! SimonaService.Create( + InitExtPrimaryData(extPrimaryData), + ScheduleLock.singleKey( + context, + extScheduler, + INIT_SIM_TICK, + ), + ) + + (extPrimaryData, (classOf[ExtPrimaryDataService], extPrimaryDataService)) + + case (extResultDataSimulation: ExtResultDataSimulation, dIndex) => + + val extResultDataProvider = { + context.spawn( + ExtResultDataProvider(extScheduler), + s"$index-$dIndex", + ) + } + + implicit val timeout: PekkoTimeout = PekkoTimeout.create(5.seconds.toJava) + implicit val scheduler: Scheduler = context.system.scheduler + + val adapterRef = Await.result( + extResultDataProvider.ask[ActorRef[ResultDataMessageFromExt]] (ref => RequestDataMessageAdapter(ref)), timeout.duration) + val adapterScheduleRef = Await.result( + extResultDataProvider.ask[ActorRef[ScheduleServiceActivation]] (ref => RequestScheduleActivationAdapter(ref)), timeout.duration) + + val extResultData = + new ExtResultData( + adapterRef.toClassic, + adapterScheduleRef.toClassic, + extSimAdapter, + extResultDataSimulation.getResultDataFactory, + extResultDataSimulation.getResultDataAssets + ) + + extResultDataSimulation.setExtResultData(extResultData) + + extResultDataProvider ! ExtResultDataProvider.Create( + InitExtResultData(extResultData), + ScheduleLock.singleKey( + context, + extScheduler, + INIT_SIM_TICK, + ), + ) + + ( + extResultData, + (ExtResultDataProvider.getClass, extResultDataProvider.toClassic), + ) }.unzip - extLink.getExtSimulation.setup( - extSimAdapterData, - extData.toList.asJava, - ) + extLink.getExtSimulation.setup( + extSimAdapterData, + extData.toList.asJava, + ) - // starting external simulation - new Thread(extLink.getExtSimulation, s"External simulation $index") - .start() + // starting external simulation + new Thread(extLink.getExtSimulation, s"External simulation $index") + .start() - (extSimAdapter, extDataInit) + (extSimAdapter, (extDataServiceToRef, extData)) }.unzip + val extDataServices = extDatasAndServices.map(_._1) + val extDatas = extDatasAndServices.flatMap(_._2).toSet + ExtSimSetupData( extSimAdapters, extDataServices.flatten.toMap, - Some(extScheduler), - ) - } else { - ExtSimSetupData(Iterable.empty, Map.empty, None) + extDatas, + Some(extScheduler)) + } else { + ExtSimSetupData(Iterable.empty, Map.empty, Set.empty, None) } } + */ + + + override def extSimulations( + context: ActorContext[_], + rootScheduler: ActorRef[SchedulerMessage], + simScheduler: ActorRef[SchedulerMessage], + ): ExtSimSetupData = { + ??? + } + override def timeAdvancer( context: ActorContext[_], simulation: ActorRef[SimonaSim.SimulationEnded.type], @@ -311,8 +387,11 @@ class SimonaStandaloneSetup( ) override def resultEventListener( - context: ActorContext[_] + context: ActorContext[_], + extSimulationData: ExtSimSetupData, ): Seq[ActorRef[ResultEventListener.Request]] = { + val extResultDataService: Option[ActorRef[ExtResultDataProvider.Request]] = + extSimulationData.extResultDataService // append ResultEventListener as well to write raw output files ArgsParser .parseListenerConfigOption(simonaConfig.simona.event.listener) @@ -328,7 +407,8 @@ class SimonaStandaloneSetup( .toSeq :+ context .spawn( ResultEventListener( - resultFileHierarchy + resultFileHierarchy, + extResultDataService, ), ResultEventListener.getClass.getSimpleName, ) diff --git a/src/main/scala/edu/ie3/simona/util/ReceiveDataMap.scala b/src/main/scala/edu/ie3/simona/util/ReceiveDataMap.scala index 1f7fca229e..4550f9e1de 100644 --- a/src/main/scala/edu/ie3/simona/util/ReceiveDataMap.scala +++ b/src/main/scala/edu/ie3/simona/util/ReceiveDataMap.scala @@ -41,6 +41,8 @@ final case class ReceiveDataMap[K, V]( ) } + def getExpectedKeys: Set[K] = expectedKeys + } object ReceiveDataMap { diff --git a/src/main/scala/edu/ie3/util/scala/io/GraphicDataCleaner.scala b/src/main/scala/edu/ie3/util/scala/io/GraphicDataCleaner.scala index 0e1515df69..6d44b34211 100644 --- a/src/main/scala/edu/ie3/util/scala/io/GraphicDataCleaner.scala +++ b/src/main/scala/edu/ie3/util/scala/io/GraphicDataCleaner.scala @@ -8,8 +8,8 @@ package edu.ie3.util.scala.io import edu.ie3.datamodel.io.naming.FileNamingStrategy import edu.ie3.datamodel.io.sink.CsvFileSink -import edu.ie3.datamodel.io.source.{GraphicSource, RawGridSource, TypeSource} import edu.ie3.datamodel.io.source.csv.CsvDataSource +import edu.ie3.datamodel.io.source.{GraphicSource, RawGridSource, TypeSource} import java.nio.file.Paths diff --git a/src/main/scala/edu/ie3/util/scala/io/ScalaReflectionSerde.scala b/src/main/scala/edu/ie3/util/scala/io/ScalaReflectionSerde.scala index f7d6707254..b1bd6043ef 100644 --- a/src/main/scala/edu/ie3/util/scala/io/ScalaReflectionSerde.scala +++ b/src/main/scala/edu/ie3/util/scala/io/ScalaReflectionSerde.scala @@ -7,10 +7,7 @@ package edu.ie3.util.scala.io import com.sksamuel.avro4s.RecordFormat -import io.confluent.kafka.streams.serdes.avro.{ - GenericAvroDeserializer, - GenericAvroSerializer, -} +import io.confluent.kafka.streams.serdes.avro.{GenericAvroDeserializer, GenericAvroSerializer} import org.apache.kafka.common.serialization.{Deserializer, Serializer} /** As seen at diff --git a/src/main/scala/edu/ie3/util/scala/quantities/QuantityUtil.scala b/src/main/scala/edu/ie3/util/scala/quantities/QuantityUtil.scala index 4ca6d188fb..67ceec5bd7 100644 --- a/src/main/scala/edu/ie3/util/scala/quantities/QuantityUtil.scala +++ b/src/main/scala/edu/ie3/util/scala/quantities/QuantityUtil.scala @@ -7,7 +7,6 @@ package edu.ie3.util.scala.quantities import edu.ie3.simona.exceptions.QuantityException -import edu.ie3.util.quantities.{QuantityUtil => PSQuantityUtil} import squants.time.{Hours, TimeDerivative, TimeIntegral} import squants.{Quantity, Seconds, UnitOfMeasure} import tech.units.indriya.ComparableQuantity diff --git a/src/main/scala/edu/ie3/util/scala/quantities/ReactivePower.scala b/src/main/scala/edu/ie3/util/scala/quantities/ReactivePower.scala index aaddb36edf..ebaf0f702a 100644 --- a/src/main/scala/edu/ie3/util/scala/quantities/ReactivePower.scala +++ b/src/main/scala/edu/ie3/util/scala/quantities/ReactivePower.scala @@ -6,9 +6,9 @@ package edu.ie3.util.scala.quantities +import squants._ import squants.energy._ import squants.time.{Hours, Time, TimeIntegral} -import squants._ import scala.util.Try diff --git a/src/test/scala/edu/ie3/simona/service/primary/ExtPrimaryDataServiceSpec.scala b/src/test/scala/edu/ie3/simona/service/primary/ExtPrimaryDataServiceSpec.scala new file mode 100644 index 0000000000..0b19da082c --- /dev/null +++ b/src/test/scala/edu/ie3/simona/service/primary/ExtPrimaryDataServiceSpec.scala @@ -0,0 +1,155 @@ +/* + * © 2021. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.service.primary + +import com.typesafe.config.ConfigFactory +import edu.ie3.simona.test.common.service.PrimaryDataFactoryDefault +import edu.ie3.datamodel.io.factory.timeseries.TimeBasedSimpleValueFactory +import edu.ie3.datamodel.io.naming.FileNamingStrategy +import edu.ie3.datamodel.io.source.csv.CsvTimeSeriesSource +import edu.ie3.datamodel.models.StandardUnits +import edu.ie3.datamodel.models.value.{HeatDemandValue, PValue} +import edu.ie3.simona.agent.participant.data.Data.PrimaryData.ActivePower +import edu.ie3.simona.api.data.ev.ExtEvData +import edu.ie3.simona.api.data.ev.model.EvModel +import edu.ie3.simona.api.data.ev.ontology._ +import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage +import edu.ie3.simona.api.data.primarydata.ExtPrimaryData +import edu.ie3.simona.exceptions.ServiceException +import edu.ie3.simona.ontology.messages.Activation +import edu.ie3.simona.ontology.messages.SchedulerMessage.{ + Completion, + ScheduleActivation, +} +import edu.ie3.simona.ontology.messages.services.EvMessage._ +import edu.ie3.simona.ontology.messages.services.ServiceMessage.{ + ExtPrimaryDataServiceRegistrationMessage, + WorkerRegistrationMessage, +} +import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationSuccessfulMessage +import edu.ie3.simona.ontology.messages.services.WeatherMessage.RegisterForWeatherMessage +import edu.ie3.simona.scheduler.ScheduleLock +import edu.ie3.simona.service.SimonaService +import edu.ie3.simona.service.ev.ExtEvDataService.InitExtEvData +import edu.ie3.simona.service.primary.ExtPrimaryDataService.InitExtPrimaryData +import edu.ie3.simona.service.primary.PrimaryServiceWorker.{ + CsvInitPrimaryServiceStateData, + PrimaryServiceInitializedStateData, + ProvidePrimaryDataMessage, +} +import edu.ie3.simona.service.primary.PrimaryServiceWorkerSpec.WrongInitPrimaryServiceStateData +import edu.ie3.simona.test.common.{ + EvTestData, + TestKitWithShutdown, + TestSpawnerClassic, +} +import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import edu.ie3.util.TimeUtil +import edu.ie3.util.quantities.PowerSystemUnits +import edu.ie3.util.scala.collection.immutable.SortedDistinctSeq +import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps +import org.apache.pekko.actor.{ActorRef, ActorSystem} +import org.apache.pekko.testkit.{TestActorRef, TestProbe} +import org.scalatest.wordspec.AnyWordSpecLike +import squants.energy.Kilowatts +import tech.units.indriya.quantity.Quantities + +import java.nio.file.Paths +import java.time.ZonedDateTime +import java.util.UUID +import scala.concurrent.duration.DurationInt +import scala.jdk.CollectionConverters._ +import scala.util.{Failure, Success} + +class ExtPrimaryDataServiceSpec + extends TestKitWithShutdown( + ActorSystem( + "ExtPrimaryDataServiceSpec", + ConfigFactory + .parseString(""" + |pekko.loggers = ["org.apache.pekko.testkit.TestEventListener"] + |pekko.loglevel = "INFO" + |""".stripMargin), + ) + ) + with TestSpawnerClassic { + + private val scheduler = TestProbe("scheduler") + private val extSimAdapter = TestProbe("extSimAdapter") + + private val primaryDataFactory = new PrimaryDataFactoryDefault + + private val extPrimaryData = (dataService: ActorRef) => + new ExtPrimaryData( + dataService, + extSimAdapter.ref, + primaryDataFactory, + ) + + "An uninitialized external primary data service" must { + + "send correct completion message after initialisation" in { + val primaryDataService = TestActorRef( + new ExtPrimaryDataService( + scheduler.ref + ) + ) + + val key = + ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) + scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + + scheduler.send( + primaryDataService, + SimonaService.Create( + InitExtPrimaryData(extPrimaryData(primaryDataService)), + key, + ), + ) + scheduler.expectMsg( + ScheduleActivation(primaryDataService.toTyped, INIT_SIM_TICK, Some(key)) + ) + + scheduler.send(primaryDataService, Activation(INIT_SIM_TICK)) + scheduler.expectMsg(Completion(primaryDataService.toTyped)) + } + } + + "An external primary service actor" should { + val serviceRef = + TestActorRef( + new ExtPrimaryDataService( + scheduler.ref + ) + ) + + "refuse registration for wrong registration request" in { + serviceRef ! RegisterForWeatherMessage(51.4843281, 7.4116482) + expectNoMessage() + } + + val systemParticipant: TestProbe = TestProbe("dummySystemParticipant") + "correctly register a forwarded request" in { + serviceRef ! ExtPrimaryDataServiceRegistrationMessage( + UUID.randomUUID(), + systemParticipant.ref, + ) + println("Try to register") + + /* Wait for request approval */ + systemParticipant.expectMsg( + RegistrationSuccessfulMessage(systemParticipant.ref, Some(0L)) + ) + + /* We cannot directly check, if the requesting actor is among the subscribers, therefore we ask the actor to + * provide data to all subscribed actors and check, if the subscribed probe gets one */ + scheduler.send(serviceRef, Activation(0)) + scheduler.expectMsgType[Completion] + systemParticipant.expectMsgAllClassOf(classOf[ProvidePrimaryDataMessage]) + } + } +} diff --git a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala index be522fbc9c..d5aa3bab48 100644 --- a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala +++ b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala @@ -129,6 +129,12 @@ class PrimaryServiceProxySpec private val scheduler: TestProbe = TestProbe("scheduler") + private val validExtPrimaryDataService = TestActorRef( + new ExtPrimaryDataService( + scheduler.ref + ) + ) + "Testing a primary service config" should { "lead to complaining about too much source definitions" in { val maliciousConfig = PrimaryConfig( @@ -239,6 +245,7 @@ class PrimaryServiceProxySpec InitPrimaryServiceProxyStateData( validPrimaryConfig, simulationStart, + None, ) val proxyRef: TestActorRef[PrimaryServiceProxy] = TestActorRef( new PrimaryServiceProxy(scheduler.ref, initStateData, simulationStart) @@ -260,6 +267,7 @@ class PrimaryServiceProxySpec proxy invokePrivate prepareStateData( maliciousConfig, simulationStart, + Option.empty, ) match { case Success(_) => fail("Building state data with missing config should fail") @@ -280,6 +288,7 @@ class PrimaryServiceProxySpec proxy invokePrivate prepareStateData( maliciousConfig, simulationStart, + Option.empty, ) match { case Success(_) => fail("Building state data with missing config should fail") @@ -293,6 +302,7 @@ class PrimaryServiceProxySpec proxy invokePrivate prepareStateData( validPrimaryConfig, simulationStart, + Option.empty, ) match { case Success( PrimaryServiceStateData( @@ -301,6 +311,8 @@ class PrimaryServiceProxySpec simulationStart, primaryConfig, mappingSource, + _, + _, ) ) => modelToTimeSeries shouldBe Map( @@ -338,6 +350,29 @@ class PrimaryServiceProxySpec ) } } + + "build proxy correctly when there is an external simulation" in { + proxy invokePrivate prepareStateData( + validPrimaryConfig, + simulationStart, + Some(validExtPrimaryDataService), + ) match { + case Success( + PrimaryServiceStateData( + _, + _, + _, + _, + _, + extSubscribers, + extPrimaryDataService, + ) + ) => + extPrimaryDataService should contain(validExtPrimaryDataService) + extSubscribers shouldBe Iterable.empty + } + } + } "Sending initialization information to an uninitialized actor" should { @@ -562,6 +597,8 @@ class PrimaryServiceProxySpec simulationStart, primaryConfig, mappingSource, + _, + _, ) => modelToTimeSeries shouldBe proxyStateData.modelToTimeSeries timeSeriesToSourceRef shouldBe Map( diff --git a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala index fee341c869..a5665a25e5 100644 --- a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala +++ b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala @@ -100,6 +100,7 @@ class PrimaryServiceProxySqlIT sqlParams = Some(sqlParams), ), simulationStart, + None, ) TestActorRef( diff --git a/src/test/scala/edu/ie3/simona/sim/SimonaSimSpec.scala b/src/test/scala/edu/ie3/simona/sim/SimonaSimSpec.scala index ad028070d2..704f226112 100644 --- a/src/test/scala/edu/ie3/simona/sim/SimonaSimSpec.scala +++ b/src/test/scala/edu/ie3/simona/sim/SimonaSimSpec.scala @@ -302,7 +302,8 @@ class SimonaSimSpec extends ScalaTestWithActorTestKit with UnitSpec { new MockSetup() { override def resultEventListener( - context: ActorContext[_] + context: ActorContext[_], + extSimSetupData: ExtSimSetupData, ): Seq[ActorRef[ResultEventListener.Request]] = throwTestException() } @@ -408,7 +409,8 @@ object SimonaSimSpec { ) override def resultEventListener( - context: ActorContext[_] + context: ActorContext[_], + extSimSetupData: ExtSimSetupData, ): Seq[ActorRef[ResultEventListener.Request]] = Seq( context.spawn( stoppableForwardMessage(resultEventProbe), @@ -419,6 +421,7 @@ object SimonaSimSpec { override def primaryServiceProxy( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], + extSimSetupData: ExtSimSetupData, ): ClassicRef = context.spawn(empty, uniqueName("primaryService")).toClassic diff --git a/src/test/scala/edu/ie3/simona/sim/setup/SimonaSetupSpec.scala b/src/test/scala/edu/ie3/simona/sim/setup/SimonaSetupSpec.scala index 55e7310266..2e8aef8277 100644 --- a/src/test/scala/edu/ie3/simona/sim/setup/SimonaSetupSpec.scala +++ b/src/test/scala/edu/ie3/simona/sim/setup/SimonaSetupSpec.scala @@ -42,13 +42,15 @@ class SimonaSetupSpec extends UnitSpec with SimonaSetup with SubGridGateMokka { ) override def resultEventListener( - context: ActorContext[_] + context: ActorContext[_], + extSimulationData: ExtSimSetupData, ): Seq[ActorRef[ResultEventListener.Request]] = throw new NotImplementedException("This is a dummy setup") override def primaryServiceProxy( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], + extSimSetupData: ExtSimSetupData, ): ClassicRef = throw new NotImplementedException("This is a dummy setup") override def weatherService( diff --git a/src/test/scala/edu/ie3/simona/test/common/service/PrimaryDataFactoryDefault.scala b/src/test/scala/edu/ie3/simona/test/common/service/PrimaryDataFactoryDefault.scala new file mode 100644 index 0000000000..ee50f5356d --- /dev/null +++ b/src/test/scala/edu/ie3/simona/test/common/service/PrimaryDataFactoryDefault.scala @@ -0,0 +1,18 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.test.common.service + +import edu.ie3.datamodel.models.value.Value +import edu.ie3.simona.api.data.primarydata.PrimaryDataFactory + +class PrimaryDataFactoryDefault extends PrimaryDataFactory { + + /** Should convert an object to an primary data value with a check if the + * object is primary data + */ + override def convert(entity: Any): Value = null +}