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