EOPS Example¶
This example demonstrates a simple EOPS model simulation. The system is not a realistic example but rather contains debug data used during the development of EOPS features.
For instance, the exogenous price series consists of values like 0, 10, 20, etc., making it easy to validate that the exogenous price data is correctly written to the expected files.
Since this is a debug setup, no in-depth analysis of input and output data is provided. However, there are still several interesting features worth discussing.
### Setting Up an EOPS Simulation To start an EOPS simulation, two flags in the global settings must be configured:
`model_type`: “EOPS”
`simulation_type`: “Serial”
Validation¶
Additionally, the input data must adhere to several rules. To ensure correctness, a thorough validation is performed using the validate_model() function.
The following list summarized the validation rules:
The model must contain one and only one area.
Neither DC nor AC lines are allowed.
A main price series must be present, but secondary price series are not allowed.
A valid detailed hydro system is required, meaning at least one reservoir and one plant must be included.
Aggregated hydro and batteries are not allowed.
Spill and curtailment series must be set.
Market steps of type ts-spot for both purchase and sale must be set.
Other types of market steps are optional but not required.
Loads are optional
Wind and solar series are theoretically possible, but their real-world use is rare. - They are therefore restricted in the first version, but may be included later.
Market calibration areas are not allowed
Runtime enviroment¶
The runtime enviroment is only avtivated if the modeltype is set to be EOPS.
Input File¶
All system details are specified in the eops.json file below.
Expand to see full JSON listing.
1{
2 "$schema": "https://gitlab.sintef.no/energy/ltm/pyltmapi/-/raw/main/model.schema.json",
3 "model": {
4 "global_settings": {
5 "name": "eops_test",
6 "output_path": "testout_EOPS/",
7 "delete_output_dir": false,
8 "generate_output_dir": true,
9 "model_type": "EOPS",
10 "simulation_type": "parallel",
11 "simulation_period": {
12 "timestamps": [
13 "2024-W20",
14 "2026-W20"
15 ]
16 },
17 "historical_period": {
18 "timestamps": [
19 "1979-01-01T00:00:00Z",
20 "1989-01-01T00:00:00Z"
21 ],
22 "scenarios": [
23 [
24 1,
25 0
26 ]
27 ],
28 "unit": "ON/OFF"
29 },
30 "max_iterations": 40,
31 "precision": 0.001,
32 "timesteps_per_week": 7,
33 "default_spill_cost": 0.01,
34 "default_load_penalty": 445.0,
35 "currency": "EUR"
36 },
37 "loads": [
38 {
39 "#comment": "Gruppe 16",
40 "name": "FLAT",
41 "capacity": {
42 "timestamps": [
43 "2024-01-01T00:00:00Z"
44 ],
45 "scenarios": [
46 [
47 7
48 ]
49 ]
50 }
51 },
52 {
53 "#comment": "Gruppe 16",
54 "name": "FLAT2",
55 "capacity": {
56 "timestamps": [
57 "2024-01-01T00:00:00Z"
58 ],
59 "scenarios": [
60 [
61 7
62 ]
63 ]
64 }
65 }
66 ],
67 "market_steps": [
68 {
69 "name": "ts_spot_purchase",
70 "capacity": {
71 "timestamps": [
72 "2023-01-02T00:00:00Z"
73 ],
74 "scenarios": [
75 [
76 10.0
77 ]
78 ]
79 }
80 },
81 {
82 "name": "ts_spot_sale",
83 "capacity": {
84 "timestamps": [
85 "2023-01-02T00:00:00Z"
86 ],
87 "scenarios": [
88 [
89 -20.0
90 ]
91 ]
92 }
93 }
94 ],
95 "inflow_series": [
96 {
97 "name": "small",
98 "series": {
99 "timestamps": [
100 "1900-01-01T00:00:00Z"
101 ],
102 "scenarios": [
103 [
104 0.001
105 ]
106 ]
107 }
108 },
109 {
110 "name": "constant",
111 "series": {
112 "timestamps": [
113 "1900-01-01T00:00:00Z"
114 ],
115 "scenarios": [
116 [
117 1.0
118 ]
119 ]
120 }
121 }
122 ],
123 "reservoirs": [
124 {
125 "name": "LABRO",
126 "average_regulated_inflow": 6.359381359381359,
127 "degree_of_regulation": 4,
128 "initial_volume": 50,
129 "max_discharge": 30,
130 "reference_curve": {
131 "timestamps": [
132 "2024-04-22T00:00:00Z",
133 "2024-06-03T00:00:00Z",
134 "2024-12-30T00:00:00Z"
135 ],
136 "scenarios": [
137 [
138 95.01,
139 0.0,
140 95.0
141 ]
142 ]
143 },
144 "regulated_inflow": {
145 "#comment": "Refers to unregulated inflow label",
146 "timestamps": [
147 "0001-01-01T00:00:00Z"
148 ],
149 "scenarios": [
150 [
151 37.5954019
152 ]
153 ]
154 },
155 "gross_head": 40.0,
156 "tailrace_elevation": 1030,
157 "volume_curve": {
158 "x": [
159 1050,
160 1100
161 ],
162 "y": [
163 0,
164 100
165 ]
166 }
167 },
168 {
169 "name": "VITTINGFOSS",
170 "average_regulated_inflow": 6.359381359381359,
171 "degree_of_regulation": 4,
172 "initial_volume": 50,
173 "max_discharge": 30,
174 "reference_curve": {
175 "timestamps": [
176 "2024-04-22T00:00:00Z",
177 "2024-06-03T00:00:00Z",
178 "2024-12-30T00:00:00Z"
179 ],
180 "scenarios": [
181 [
182 95.01,
183 0.0,
184 95.0
185 ]
186 ]
187 },
188 "regulated_inflow": {
189 "#comment": "Refers to unregulated inflow label",
190 "timestamps": [
191 "0001-01-01T00:00:00Z"
192 ],
193 "scenarios": [
194 [
195 37.5954019
196 ]
197 ]
198 },
199 "gross_head": 40.0,
200 "tailrace_elevation": 1030,
201 "volume_curve": {
202 "x": [
203 1050,
204 1100
205 ],
206 "y": [
207 0,
208 100
209 ]
210 }
211 },
212 {
213 "name": "STORFALL",
214 "average_regulated_inflow": 6.359381359381359,
215 "degree_of_regulation": 4,
216 "initial_volume": 50,
217 "max_discharge": 30,
218 "reference_curve": {
219 "timestamps": [
220 "2024-04-22T00:00:00Z",
221 "2024-06-03T00:00:00Z",
222 "2024-12-30T00:00:00Z"
223 ],
224 "scenarios": [
225 [
226 95.01,
227 0.0,
228 95.0
229 ]
230 ]
231 },
232 "regulated_inflow": {
233 "#comment": "Refers to unregulated inflow label",
234 "timestamps": [
235 "0001-01-01T00:00:00Z"
236 ],
237 "scenarios": [
238 [
239 37.5954019
240 ]
241 ]
242 },
243 "gross_head": 40.0,
244 "tailrace_elevation": 1030,
245 "volume_curve": {
246 "x": [
247 1050,
248 1100
249 ],
250 "y": [
251 0,
252 100
253 ]
254 }
255 },
256 {
257 "name": "BLASJO",
258 "average_regulated_inflow": 6.359381359381359,
259 "degree_of_regulation": 4,
260 "initial_volume": 50,
261 "max_discharge": 30,
262 "reference_curve": {
263 "timestamps": [
264 "2024-04-22T00:00:00Z",
265 "2024-06-03T00:00:00Z",
266 "2024-12-30T00:00:00Z"
267 ],
268 "scenarios": [
269 [
270 95.01,
271 0.0,
272 95.0
273 ]
274 ]
275 },
276 "regulated_inflow": {
277 "#comment": "Refers to unregulated inflow label",
278 "timestamps": [
279 "0001-01-01T00:00:00Z"
280 ],
281 "scenarios": [
282 [
283 37.5954019
284 ]
285 ]
286 },
287 "gross_head": 40.0,
288 "tailrace_elevation": 1030,
289 "volume_curve": {
290 "x": [
291 1050,
292 1100
293 ],
294 "y": [
295 0,
296 100
297 ]
298 }
299 },
300 {
301 "name": "mid1",
302 "degree_of_regulation": 3,
303 "regulated_inflow_name": "constant",
304 "average_regulated_inflow": 1,
305 "max_discharge": 50,
306 "reference_curve": {
307 "timestamps": [
308 "2024-W15",
309 "2024-W30",
310 "2024-W47"
311 ],
312 "scenarios": [
313 [
314 50,
315 250,
316 450
317 ]
318 ]
319 },
320 "initial_volume": 300,
321 "volume_curve": {
322 "x": [
323 1000,
324 1050
325 ],
326 "y": [
327 0,
328 500
329 ]
330 },
331 "tailrace_elevation": 50.0,
332 "gross_head": 100.0
333 },
334 {
335 "name": "mid2",
336 "degree_of_regulation": 3,
337 "regulated_inflow_name": "constant",
338 "average_regulated_inflow": 2,
339 "max_discharge": 50,
340 "reference_curve": {
341 "timestamps": [
342 "2024-W15",
343 "2024-W30",
344 "2024-W47"
345 ],
346 "scenarios": [
347 [
348 50,
349 250,
350 450
351 ]
352 ]
353 },
354 "initial_volume": 250,
355 "volume_curve": {
356 "x": [
357 1000,
358 1050
359 ],
360 "y": [
361 0,
362 500
363 ]
364 },
365 "tailrace_elevation": 50.0,
366 "gross_head": 100.0
367 },
368 {
369 "name": "mid3",
370 "degree_of_regulation": 3,
371 "regulated_inflow_name": "constant",
372 "average_regulated_inflow": 3,
373 "max_discharge": 50,
374 "reference_curve": {
375 "timestamps": [
376 "2024-W15",
377 "2024-W30",
378 "2024-W47"
379 ],
380 "scenarios": [
381 [
382 50,
383 250,
384 450
385 ]
386 ]
387 },
388 "initial_volume": 450,
389 "volume_curve": {
390 "x": [
391 1000,
392 1050
393 ],
394 "y": [
395 0,
396 500
397 ]
398 },
399 "tailrace_elevation": 50.0,
400 "gross_head": 100.0
401 },
402 {
403 "name": "coupl_mid1",
404 "degree_of_regulation": 3,
405 "regulated_inflow_name": "constant",
406 "average_regulated_inflow": 1,
407 "max_discharge": 50,
408 "reference_curve": {
409 "timestamps": [
410 "2024-W15",
411 "2024-W30",
412 "2024-W47"
413 ],
414 "scenarios": [
415 [
416 50,
417 250,
418 450
419 ]
420 ]
421 },
422 "initial_volume": 300,
423 "tailrace_elevation": 50.0,
424 "volume_curve": {
425 "x": [
426 1000,
427 1050
428 ],
429 "y": [
430 0,
431 500
432 ]
433 },
434 "gross_head": 900
435 },
436 {
437 "name": "coupl_mid2",
438 "degree_of_regulation": 3,
439 "regulated_inflow_name": "constant",
440 "average_regulated_inflow": 2,
441 "max_discharge": 50,
442 "reference_curve": {
443 "timestamps": [
444 "2024-W15",
445 "2024-W30",
446 "2024-W47"
447 ],
448 "scenarios": [
449 [
450 50,
451 250,
452 450
453 ]
454 ]
455 },
456 "initial_volume": 250,
457 "volume_curve": {
458 "x": [
459 1000,
460 1050
461 ],
462 "y": [
463 0,
464 500
465 ]
466 },
467 "gross_head": 900
468 },
469 {
470 "name": "coupl_mid3",
471 "degree_of_regulation": 3,
472 "regulated_inflow_name": "constant",
473 "average_regulated_inflow": 3,
474 "max_discharge": 50,
475 "reference_curve": {
476 "timestamps": [
477 "2024-W15",
478 "2024-W30",
479 "2024-W47"
480 ],
481 "scenarios": [
482 [
483 50,
484 250,
485 450
486 ]
487 ]
488 },
489 "initial_volume": 450,
490 "volume_curve": {
491 "x": [
492 1000,
493 1050
494 ],
495 "y": [
496 0,
497 500
498 ]
499 },
500 "gross_head": 900
501 }
502 ],
503 "hydraulic_couplings": [
504 {
505 "name": "coupling_200",
506 "max_flow": 100
507 },
508 {
509 "name": "plant_coupling_100"
510 }
511 ],
512 "plants": [
513 {
514 "name": "LABRO_plant",
515 "average_energy_equivalent": 0.12,
516 "discharge_energy_equivalent": {
517 "timestamps": [
518 "2023-01-02T00:00:00Z"
519 ],
520 "scenarios": [
521 [
522 0.12
523 ]
524 ]
525 },
526 "pq_curves": {
527 "2024-01-01T00:00:00Z": {
528 "y": [
529 0.0,
530 9.89
531 ],
532 "x": [
533 0.0,
534 24.6
535 ]
536 }
537 },
538 "average_unregulated_inflow": 0.6359381359,
539 "unregulated_inflow": {
540 "#comment": "Refers to unregulated inflow label",
541 "timestamps": [
542 "0001-01-01T00:00:00Z"
543 ],
544 "scenarios": [
545 [
546 37.5954019
547 ]
548 ]
549 }
550 },
551 {
552 "name": "VITTINGFOSS_plant",
553 "average_energy_equivalent": 0.12,
554 "discharge_energy_equivalent": {
555 "timestamps": [
556 "2023-01-02T00:00:00Z"
557 ],
558 "scenarios": [
559 [
560 0.12
561 ]
562 ]
563 },
564 "pq_curves": {
565 "2024-01-01T00:00:00Z": {
566 "y": [
567 0.0,
568 9.89
569 ],
570 "x": [
571 0.0,
572 24.6
573 ]
574 }
575 },
576 "average_unregulated_inflow": 0.635938135938136,
577 "unregulated_inflow": {
578 "#comment": "Refers to unregulated inflow label",
579 "timestamps": [
580 "0001-01-01T00:00:00Z"
581 ],
582 "scenarios": [
583 [
584 37.5954019
585 ]
586 ]
587 }
588 },
589 {
590 "name": "STORFALL_plant",
591 "average_energy_equivalent": 0.12,
592 "discharge_energy_equivalent": {
593 "timestamps": [
594 "2023-01-02T00:00:00Z"
595 ],
596 "scenarios": [
597 [
598 0.12
599 ]
600 ]
601 },
602 "pq_curves": {
603 "2024-01-01T00:00:00Z": {
604 "y": [
605 0.0,
606 9.89
607 ],
608 "x": [
609 0.0,
610 24.6
611 ]
612 }
613 },
614 "average_unregulated_inflow": 0.635938135938136,
615 "unregulated_inflow": {
616 "#comment": "Refers to unregulated inflow label",
617 "timestamps": [
618 "0001-01-01T00:00:00Z"
619 ],
620 "scenarios": [
621 [
622 37.5954019
623 ]
624 ]
625 }
626 },
627 {
628 "name": "BLASJO_plant",
629 "average_energy_equivalent": 0.12,
630 "discharge_energy_equivalent": {
631 "timestamps": [
632 "2023-01-02T00:00:00Z"
633 ],
634 "scenarios": [
635 [
636 0.12
637 ]
638 ]
639 },
640 "pq_curves": {
641 "2024-01-01T00:00:00Z": {
642 "y": [
643 0.0,
644 9.89
645 ],
646 "x": [
647 0.0,
648 24.6
649 ]
650 }
651 },
652 "average_unregulated_inflow": 0.635938135938136,
653 "unregulated_inflow": {
654 "#comment": "Refers to unregulated inflow label",
655 "timestamps": [
656 "0001-01-01T00:00:00Z"
657 ],
658 "scenarios": [
659 [
660 37.5954019
661 ]
662 ]
663 }
664 },
665 {
666 "name": "plant_mid1",
667 "ownership": 100,
668 "average_energy_equivalent": 3.0,
669 "discharge_energy_equivalent": {
670 "timestamps": [
671 "2023-01-02T00:00:00Z"
672 ],
673 "scenarios": [
674 [
675 3.03
676 ]
677 ]
678 },
679 "pq_curves": {
680 "2023-01-02T00:00:00Z": {
681 "x": [
682 0.0,
683 70.00
684 ],
685 "y": [
686 0.0,
687 300.0
688 ]
689 }
690 },
691 "unregulated_inflow_name": "small",
692 "average_unregulated_inflow": 0.0
693 },
694 {
695 "name": "plant_mid2",
696 "ownership": 100,
697 "average_energy_equivalent": 3.0,
698 "discharge_energy_equivalent": {
699 "timestamps": [
700 "2023-01-02T00:00:00Z"
701 ],
702 "scenarios": [
703 [
704 3.03
705 ]
706 ]
707 },
708 "pq_curves": {
709 "2023-01-02T00:00:00Z": {
710 "x": [
711 0.0,
712 70.00
713 ],
714 "y": [
715 0.0,
716 300.0
717 ]
718 }
719 },
720 "unregulated_inflow_name": "small",
721 "average_unregulated_inflow": 0.0
722 },
723 {
724 "name": "plant_mid3",
725 "ownership": 100,
726 "average_energy_equivalent": 3.0,
727 "discharge_energy_equivalent": {
728 "timestamps": [
729 "2023-01-02T00:00:00Z"
730 ],
731 "scenarios": [
732 [
733 3.03
734 ]
735 ]
736 },
737 "pq_curves": {
738 "2023-01-02T00:00:00Z": {
739 "x": [
740 0.0,
741 70.00
742 ],
743 "y": [
744 0.0,
745 300.0
746 ]
747 }
748 },
749 "unregulated_inflow_name": "small",
750 "average_unregulated_inflow": 0.0
751 },
752 {
753 "name": "coupl_plant",
754 "ownership": 100,
755 "average_energy_equivalent": 3.0,
756 "discharge_energy_equivalent": {
757 "timestamps": [
758 "2023-01-02T00:00:00Z"
759 ],
760 "scenarios": [
761 [
762 3.03
763 ]
764 ]
765 },
766 "pq_curves": {
767 "2023-01-02T00:00:00Z": {
768 "x": [
769 0.0,
770 70.00
771 ],
772 "y": [
773 0.0,
774 300.0
775 ]
776 }
777 },
778 "unregulated_inflow_name": "small",
779 "average_unregulated_inflow": 0.0,
780 "min_bypass_curve": {
781 "timestamps": [
782 "2024-W01",
783 "2024-W10",
784 "2024-W20",
785 "2024-W40",
786 "2024-W41"
787 ],
788 "scenarios": [
789 [
790 0,
791 1,
792 10,
793 50,
794 0
795 ]
796 ]
797 }
798 }
799 ],
800 "areas": [
801 {
802 "name": "numedal"
803 }
804 ],
805 "price_series_main": [
806 {
807 "name": "HOVEDPRISREKKE.csv",
808 "series": {
809 "timestamps": [
810 "2024-01-01T00:00:00Z",
811 "2024-01-08T00:00:00Z",
812 "2024-01-15T00:00:00Z",
813 "2024-01-22T00:00:00Z",
814 "2024-01-29T00:00:00Z",
815 "2024-02-05T00:00:00Z",
816 "2024-02-12T00:00:00Z",
817 "2024-02-19T00:00:00Z",
818 "2024-02-26T00:00:00Z",
819 "2024-03-04T00:00:00Z"
820 ],
821 "scenarios": [
822 [
823 0.0,
824 10.0,
825 20.0,
826 30.0,
827 40.0,
828 50.0,
829 60.0,
830 70.0,
831 80.0,
832 90.0
833 ],
834 [
835 1.0,
836 11.0,
837 21.0,
838 31.0,
839 41.0,
840 51.0,
841 61.0,
842 71.0,
843 81.0,
844 91.0
845 ],
846 [
847 2.0,
848 12.0,
849 22.0,
850 32.0,
851 42.0,
852 52.0,
853 62.0,
854 72.0,
855 82.0,
856 92.0
857 ],
858 [
859 3.0,
860 13.0,
861 23.0,
862 33.0,
863 43.0,
864 53.0,
865 63.0,
866 73.0,
867 83.0,
868 93.0
869 ],
870 [
871 4.0,
872 14.0,
873 24.0,
874 34.0,
875 44.0,
876 54.0,
877 64.0,
878 74.0,
879 84.0,
880 94.0
881 ],
882 [
883 5.0,
884 15.0,
885 25.0,
886 35.0,
887 45.0,
888 55.0,
889 65.0,
890 75.0,
891 85.0,
892 95.0
893 ],
894 [
895 6.0,
896 16.0,
897 26.0,
898 36.0,
899 46.0,
900 56.0,
901 66.0,
902 76.0,
903 86.0,
904 96.0
905 ],
906 [
907 7.0,
908 17.0,
909 27.0,
910 37.0,
911 47.0,
912 57.0,
913 67.0,
914 77.0,
915 87.0,
916 97.0
917 ],
918 [
919 8.0,
920 18.0,
921 28.0,
922 38.0,
923 48.0,
924 58.0,
925 68.0,
926 78.0,
927 88.0,
928 98.0
929 ],
930 [
931 9.0,
932 19.0,
933 29.0,
934 39.0,
935 49.0,
936 59.0,
937 69.0,
938 79.0,
939 89.0,
940 99.0
941 ]
942 ]
943 }
944 }
945 ],
946 "connections": [
947 {
948 "from": "FLAT",
949 "to": "numedal"
950 },
951 {
952 "from": "FLAT2",
953 "to": "numedal"
954 },
955 {
956 "from": "VITTINGFOSS",
957 "to": "numedal"
958 },
959 {
960 "from": "VITTINGFOSS",
961 "to": "VITTINGFOSS_plant"
962 },
963 {
964 "from": "LABRO",
965 "to": "numedal"
966 },
967 {
968 "from": "LABRO",
969 "to": "LABRO_plant"
970 },
971 {
972 "from": "STORFALL",
973 "to": "numedal"
974 },
975 {
976 "from": "STORFALL",
977 "to": "STORFALL_plant"
978 },
979 {
980 "from": "BLASJO",
981 "to": "numedal"
982 },
983 {
984 "from": "BLASJO",
985 "to": "BLASJO_plant"
986 },
987 {
988 "from": "ts_spot_purchase",
989 "to": "numedal"
990 },
991 {
992 "from": "ts_spot_sale",
993 "to": "numedal"
994 },
995 {
996 "from": "mid1",
997 "to": "plant_mid1"
998 },
999 {
1000 "from": "mid2",
1001 "to": "plant_mid2"
1002 },
1003 {
1004 "from": "mid3",
1005 "to": "plant_mid3"
1006 },
1007 {
1008 "from": "plant_mid1",
1009 "to": "plant_coupling_100"
1010 },
1011 {
1012 "from": "plant_mid2",
1013 "to": "plant_coupling_100"
1014 },
1015 {
1016 "from": "plant_mid3",
1017 "to": "plant_coupling_100"
1018 },
1019 {
1020 "from": "mid1",
1021 "to": "numedal"
1022 },
1023 {
1024 "from": "coupl_mid1",
1025 "to": "numedal"
1026 },
1027 {
1028 "from": "coupl_mid1",
1029 "to": "coupling_200"
1030 },
1031 {
1032 "from": "coupl_mid2",
1033 "to": "coupling_200"
1034 },
1035 {
1036 "from": "coupl_mid3",
1037 "to": "coupling_200"
1038 },
1039 {
1040 "from": "coupl_mid3",
1041 "to": "coupl_plant"
1042 }
1043 ]
1044 }
1045}
Results¶
The link below provides access to a static Jupyter notebook where the LTM-API has been executed using the eops.json file as input. The notebook includes the results from the EOPS model presented through a series of figures.
Additionally, you can download the input model file here: