ocf-data-sampler 0.0.19__py3-none-any.whl → 0.0.43__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ocf-data-sampler might be problematic. Click here for more details.
- ocf_data_sampler/config/__init__.py +5 -0
- ocf_data_sampler/config/load.py +33 -0
- ocf_data_sampler/config/model.py +246 -0
- ocf_data_sampler/config/save.py +73 -0
- ocf_data_sampler/constants.py +173 -0
- ocf_data_sampler/load/load_dataset.py +55 -0
- ocf_data_sampler/load/nwp/providers/ecmwf.py +5 -2
- ocf_data_sampler/load/site.py +30 -0
- ocf_data_sampler/numpy_sample/__init__.py +8 -0
- ocf_data_sampler/numpy_sample/collate.py +75 -0
- ocf_data_sampler/numpy_sample/gsp.py +34 -0
- ocf_data_sampler/numpy_sample/nwp.py +42 -0
- ocf_data_sampler/numpy_sample/satellite.py +30 -0
- ocf_data_sampler/numpy_sample/site.py +30 -0
- ocf_data_sampler/{numpy_batch → numpy_sample}/sun_position.py +9 -10
- ocf_data_sampler/select/__init__.py +8 -1
- ocf_data_sampler/select/dropout.py +4 -3
- ocf_data_sampler/select/find_contiguous_time_periods.py +40 -75
- ocf_data_sampler/select/geospatial.py +160 -0
- ocf_data_sampler/select/location.py +62 -0
- ocf_data_sampler/select/select_spatial_slice.py +13 -16
- ocf_data_sampler/select/select_time_slice.py +24 -33
- ocf_data_sampler/select/spatial_slice_for_dataset.py +53 -0
- ocf_data_sampler/select/time_slice_for_dataset.py +125 -0
- ocf_data_sampler/torch_datasets/__init__.py +2 -1
- ocf_data_sampler/torch_datasets/process_and_combine.py +131 -0
- ocf_data_sampler/torch_datasets/pvnet_uk_regional.py +11 -425
- ocf_data_sampler/torch_datasets/site.py +405 -0
- ocf_data_sampler/torch_datasets/valid_time_periods.py +116 -0
- ocf_data_sampler/utils.py +10 -0
- ocf_data_sampler-0.0.43.dist-info/METADATA +154 -0
- ocf_data_sampler-0.0.43.dist-info/RECORD +71 -0
- {ocf_data_sampler-0.0.19.dist-info → ocf_data_sampler-0.0.43.dist-info}/WHEEL +1 -1
- {ocf_data_sampler-0.0.19.dist-info → ocf_data_sampler-0.0.43.dist-info}/top_level.txt +1 -0
- scripts/refactor_site.py +50 -0
- tests/config/test_config.py +161 -0
- tests/config/test_save.py +37 -0
- tests/conftest.py +86 -1
- tests/load/test_load_gsp.py +15 -0
- tests/load/test_load_nwp.py +21 -0
- tests/load/test_load_satellite.py +17 -0
- tests/load/test_load_sites.py +14 -0
- tests/numpy_sample/test_collate.py +26 -0
- tests/numpy_sample/test_gsp.py +38 -0
- tests/numpy_sample/test_nwp.py +52 -0
- tests/numpy_sample/test_satellite.py +40 -0
- tests/numpy_sample/test_sun_position.py +81 -0
- tests/select/test_dropout.py +75 -0
- tests/select/test_fill_time_periods.py +28 -0
- tests/select/test_find_contiguous_time_periods.py +202 -0
- tests/select/test_location.py +67 -0
- tests/select/test_select_spatial_slice.py +154 -0
- tests/select/test_select_time_slice.py +272 -0
- tests/torch_datasets/conftest.py +18 -0
- tests/torch_datasets/test_process_and_combine.py +126 -0
- tests/torch_datasets/test_pvnet_uk_regional.py +59 -0
- tests/torch_datasets/test_site.py +129 -0
- ocf_data_sampler/numpy_batch/__init__.py +0 -7
- ocf_data_sampler/numpy_batch/gsp.py +0 -20
- ocf_data_sampler/numpy_batch/nwp.py +0 -33
- ocf_data_sampler/numpy_batch/satellite.py +0 -23
- ocf_data_sampler-0.0.19.dist-info/METADATA +0 -22
- ocf_data_sampler-0.0.19.dist-info/RECORD +0 -32
- {ocf_data_sampler-0.0.19.dist-info → ocf_data_sampler-0.0.43.dist-info}/LICENSE +0 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: ocf_data_sampler
|
|
3
|
+
Version: 0.0.43
|
|
4
|
+
Summary: Sample from weather data for renewable energy prediction
|
|
5
|
+
Author: James Fulton, Peter Dudfield, and the Open Climate Fix team
|
|
6
|
+
Author-email: info@openclimatefix.org
|
|
7
|
+
Maintainer: Open Climate Fix Ltd
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2023 Open Climate Fix
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
|
|
30
|
+
Project-URL: homepage, https://github.com/openclimatefix
|
|
31
|
+
Project-URL: repository, https://github.com/openclimatefix/ocf-data-sampler
|
|
32
|
+
Keywords: weather data,renewable energy prediction,sample weather data
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
35
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
36
|
+
Requires-Python: >=3.8
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
License-File: LICENSE
|
|
39
|
+
Requires-Dist: torch
|
|
40
|
+
Requires-Dist: numpy
|
|
41
|
+
Requires-Dist: pandas
|
|
42
|
+
Requires-Dist: xarray
|
|
43
|
+
Requires-Dist: zarr==2.18.3
|
|
44
|
+
Requires-Dist: dask
|
|
45
|
+
Requires-Dist: ocf_blosc2
|
|
46
|
+
Requires-Dist: pvlib
|
|
47
|
+
Requires-Dist: pydantic
|
|
48
|
+
Requires-Dist: pyproj
|
|
49
|
+
Requires-Dist: pathy
|
|
50
|
+
Requires-Dist: pyaml_env
|
|
51
|
+
Requires-Dist: pyresample
|
|
52
|
+
Provides-Extra: docs
|
|
53
|
+
Requires-Dist: mkdocs>=1.2; extra == "docs"
|
|
54
|
+
Requires-Dist: mkdocs-material>=8.0; extra == "docs"
|
|
55
|
+
|
|
56
|
+
# ocf-data-sampler
|
|
57
|
+
|
|
58
|
+
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
59
|
+
[](#contributors-)
|
|
60
|
+
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
61
|
+
|
|
62
|
+
[](https://github.com/openclimatefix/ocf-data-sampler/tags)
|
|
63
|
+
[](https://github.com/openclimatefix#how-easy-is-it-to-get-involved)
|
|
64
|
+
|
|
65
|
+
**ocf-data-sampler** contains all the tools needed to create samples and feed them to our models, such as [PVNet](https://github.com/openclimatefix/PVNet/). The data we work with—typically energy data, satellite imagery, and numerical weather predictions (NWPs)—is usually too heavy to do this on the fly, so that's where this repo comes in: handling steps like opening the data, selecting the right samples, normalising and reshaping, and saving to and reading from disk.
|
|
66
|
+
|
|
67
|
+
We are currently migrating to this repo from [ocf_datapipes](https://github.com/openclimatefix/ocf_datapipes/), which performs the same functions but is built around `PyTorch DataPipes`, which are quite cumbersome to work with and are no longer maintained by PyTorch. **ocf-data-sampler** uses `PyTorch Datasets`, and we've taken the opportunity to make the code much cleaner and more manageable.
|
|
68
|
+
|
|
69
|
+
> [!Note]
|
|
70
|
+
> This repository is still in development and does not yet have the full
|
|
71
|
+
> functionality of its predecessor, [ocf_datapipes](https://github.com/openclimatefix/ocf_datapipes/).
|
|
72
|
+
> It might not be ready for use out of the box! We would really appreciate any help to let us make the transition faster.
|
|
73
|
+
|
|
74
|
+
## Documentation
|
|
75
|
+
|
|
76
|
+
**ocf-data-sampler** doesn't have external documentation _yet_; you can read a bit about how our torch datasets work in the README [here](ocf_data_sampler/torch_datasets/README.md).
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
## FAQ
|
|
80
|
+
|
|
81
|
+
If you have any questions about this or any other of our repos, don't hesitate to hop to our [Discussions Page](https://github.com/orgs/openclimatefix/discussions)!
|
|
82
|
+
|
|
83
|
+
### How does ocf-data-sampler deal with data sources that use different projections (e.g. some are in latitude-longitude, and some in OSGB)?
|
|
84
|
+
|
|
85
|
+
When creating samples, we make a spatial crop of a preset size centred around a point of interest (POI, usually a solar or wind farm). The size of the crop is set not in miles or kilometres, but in 'pixels', which would be different for different data sources, depending on their spatial resolution, projections they use, and where the POI is. For example, a latitude-longitude source with a 1° resolution will have pixel sizes corresponding to very different 'surface' distances (that you might measure in, e.g., kilometres) from a source with 0.1° resolution. The pixel size will even be different for the same source depending on how close the POI is to the equator!
|
|
86
|
+
|
|
87
|
+
Instead of trying to accommodate for all these differences and make all the sources use the same spatial grid, we translate the POI's position into the corresponding coordinate system and select the crop using the source's original grid. This 'snapshot' is then passed to the model with no additional information on what specific coordinates it represents; instead, since the size is always the same and the POI is always in the centre, the model gets consistent information on the measurements at a location near the POI and how it affects the target, without any explicit knowledge of where that location is in coordinate system terms.
|
|
88
|
+
|
|
89
|
+
## Development
|
|
90
|
+
|
|
91
|
+
You can install **ocf-data-sampler** for development as follows:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
pip install git+https://github.com/openclimatefix/ocf-data-sampler.git
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Running the test suite
|
|
98
|
+
|
|
99
|
+
The tests in this project use `pytest`. Once you have it installed, you can run it from the project's directory:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
cd ocf-data-sampler
|
|
103
|
+
pytest
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Contributing and community
|
|
107
|
+
|
|
108
|
+
[](https://github.com/openclimatefix/ocf-data-sampler/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc)
|
|
109
|
+
|
|
110
|
+
- PR's are welcome! See the [Organisation Profile](https://github.com/openclimatefix) for details on contributing
|
|
111
|
+
- Find out about our other projects in the [OCF Meta Repo](https://github.com/openclimatefix/ocf-meta-repo)
|
|
112
|
+
- Check out the [OCF blog](https://openclimatefix.org/blog) for updates
|
|
113
|
+
- Follow OCF on [LinkedIn](https://uk.linkedin.com/company/open-climate-fix)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
## Contributors
|
|
117
|
+
|
|
118
|
+
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
|
119
|
+
|
|
120
|
+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
121
|
+
<!-- prettier-ignore-start -->
|
|
122
|
+
<!-- markdownlint-disable -->
|
|
123
|
+
<table>
|
|
124
|
+
<tbody>
|
|
125
|
+
<tr>
|
|
126
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dfulu"><img src="https://avatars.githubusercontent.com/u/41546094?v=4?s=100" width="100px;" alt="James Fulton"/><br /><sub><b>James Fulton</b></sub></a><br /><a href="https://github.com/openclimatefix/ocf-data-sampler/commits?author=dfulu" title="Code">💻</a></td>
|
|
127
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AUdaltsova"><img src="https://avatars.githubusercontent.com/u/43303448?v=4?s=100" width="100px;" alt="Alexandra Udaltsova"/><br /><sub><b>Alexandra Udaltsova</b></sub></a><br /><a href="https://github.com/openclimatefix/ocf-data-sampler/commits?author=AUdaltsova" title="Code">💻</a></td>
|
|
128
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Sukh-P"><img src="https://avatars.githubusercontent.com/u/42407101?v=4?s=100" width="100px;" alt="Sukhil Patel"/><br /><sub><b>Sukhil Patel</b></sub></a><br /><a href="https://github.com/openclimatefix/ocf-data-sampler/commits?author=Sukh-P" title="Code">💻</a></td>
|
|
129
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/peterdudfield"><img src="https://avatars.githubusercontent.com/u/34686298?v=4?s=100" width="100px;" alt="Peter Dudfield"/><br /><sub><b>Peter Dudfield</b></sub></a><br /><a href="https://github.com/openclimatefix/ocf-data-sampler/commits?author=peterdudfield" title="Code">💻</a></td>
|
|
130
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VikramsDataScience"><img src="https://avatars.githubusercontent.com/u/45002417?v=4?s=100" width="100px;" alt="Vikram Pande"/><br /><sub><b>Vikram Pande</b></sub></a><br /><a href="https://github.com/openclimatefix/ocf-data-sampler/commits?author=VikramsDataScience" title="Code">💻</a></td>
|
|
131
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SophiaLi20"><img src="https://avatars.githubusercontent.com/u/163532536?v=4?s=100" width="100px;" alt="Unnati Bhardwaj"/><br /><sub><b>Unnati Bhardwaj</b></sub></a><br /><a href="https://github.com/openclimatefix/ocf-data-sampler/commits?author=SophiaLi20" title="Documentation">📖</a></td>
|
|
132
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/alirashidAR"><img src="https://avatars.githubusercontent.com/u/110668489?v=4?s=100" width="100px;" alt="Ali Rashid"/><br /><sub><b>Ali Rashid</b></sub></a><br /><a href="https://github.com/openclimatefix/ocf-data-sampler/commits?author=alirashidAR" title="Code">💻</a></td>
|
|
133
|
+
</tr>
|
|
134
|
+
<tr>
|
|
135
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/felix-e-h-p"><img src="https://avatars.githubusercontent.com/u/137530077?v=4?s=100" width="100px;" alt="Felix"/><br /><sub><b>Felix</b></sub></a><br /><a href="https://github.com/openclimatefix/ocf-data-sampler/commits?author=felix-e-h-p" title="Code">💻</a></td>
|
|
136
|
+
<td align="center" valign="top" width="14.28%"><a href="https://timothyajaniportfolio-b6v3zq29k-timthegreat.vercel.app/"><img src="https://avatars.githubusercontent.com/u/60073728?v=4?s=100" width="100px;" alt="Ajani Timothy"/><br /><sub><b>Ajani Timothy</b></sub></a><br /><a href="https://github.com/openclimatefix/ocf-data-sampler/commits?author=Tim1119" title="Code">💻</a></td>
|
|
137
|
+
<td align="center" valign="top" width="14.28%"><a href="https://rupeshmangalam.vercel.app/"><img src="https://avatars.githubusercontent.com/u/91172425?v=4?s=100" width="100px;" alt="Rupesh Mangalam"/><br /><sub><b>Rupesh Mangalam</b></sub></a><br /><a href="https://github.com/openclimatefix/ocf-data-sampler/commits?author=RupeshMangalam21" title="Code">💻</a></td>
|
|
138
|
+
</tr>
|
|
139
|
+
</tbody>
|
|
140
|
+
</table>
|
|
141
|
+
|
|
142
|
+
<!-- markdownlint-restore -->
|
|
143
|
+
<!-- prettier-ignore-end -->
|
|
144
|
+
|
|
145
|
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
146
|
+
|
|
147
|
+
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
*Part of the [Open Climate Fix](https://github.com/orgs/openclimatefix/people) community.*
|
|
152
|
+
|
|
153
|
+
[](https://openclimatefix.org)
|
|
154
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
ocf_data_sampler/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
2
|
+
ocf_data_sampler/constants.py,sha256=G2VfkE_-veq_0hNBQQOQCtCsfC37O5-QG9mJWEmln5s,4153
|
|
3
|
+
ocf_data_sampler/utils.py,sha256=rKA0BHAyAG4f90zEcgxp25EEYrXS-aOVNzttZ6Mzv2k,250
|
|
4
|
+
ocf_data_sampler/config/__init__.py,sha256=YXnAkgHViHB26hSsjiv32b6EbpG-A1kKTkARJf0_RkY,212
|
|
5
|
+
ocf_data_sampler/config/load.py,sha256=4f7vPHAIAmd-55tPxoIzn7F_TI_ue4NxkDcLPoVWl0g,943
|
|
6
|
+
ocf_data_sampler/config/model.py,sha256=sXmh7IadwXDT-7lxEl5_b3vjovZgZYR77EXy4GHaf4w,7276
|
|
7
|
+
ocf_data_sampler/config/save.py,sha256=JhPyX1DJAW-mi3GfkDF4nlrEXNt-yfX9ibBy8CZ6ENI,2464
|
|
8
|
+
ocf_data_sampler/data/uk_gsp_locations.csv,sha256=RSh7DRh55E3n8lVAaWXGTaXXHevZZtI58td4d4DhGos,10415772
|
|
9
|
+
ocf_data_sampler/load/__init__.py,sha256=MjgfxilTzyz1RYFoBEeAXmE9hyjknLvdmlHPmlAoiQY,44
|
|
10
|
+
ocf_data_sampler/load/gsp.py,sha256=Gcr1JVUOPKhFRDCSHtfPDjxx0BtyyEhXrZvGEKLPJ5I,759
|
|
11
|
+
ocf_data_sampler/load/load_dataset.py,sha256=Ua3RaUg4PIYJkD9BKqTfN8IWUbezbhThJGgEkd9PcaE,1587
|
|
12
|
+
ocf_data_sampler/load/satellite.py,sha256=3KlA1fx4SwxdzM-jC1WRaONXO0D6m0WxORnEnwUnZrA,2967
|
|
13
|
+
ocf_data_sampler/load/site.py,sha256=P83uz01WBDzoZajdOH0m8FQt4-buKDlUk19N548KqhA,1086
|
|
14
|
+
ocf_data_sampler/load/utils.py,sha256=EQGvVWlGMoSOdbDYuMfVAa0v6wmAOPmHIAemdrTB5v4,1406
|
|
15
|
+
ocf_data_sampler/load/nwp/__init__.py,sha256=SmcrnbygO5xtCKmGR4wtHrj-HI7nOAvnAtfuvRufBGQ,25
|
|
16
|
+
ocf_data_sampler/load/nwp/nwp.py,sha256=O4QnajEZem8BvBgTcYYDBhRhgqPYuJkolHmpMRmrXEA,610
|
|
17
|
+
ocf_data_sampler/load/nwp/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
+
ocf_data_sampler/load/nwp/providers/ecmwf.py,sha256=2iR1Iy542lo51rC6XFLV-3pbUE68dWjlHa6TVJzx3ac,1280
|
|
19
|
+
ocf_data_sampler/load/nwp/providers/ukv.py,sha256=79Bm7q-K_GJPYMy62SUIZbRWRF4-tIaB1dYPEgLD9vo,1207
|
|
20
|
+
ocf_data_sampler/load/nwp/providers/utils.py,sha256=Sy2exG1wpXLLhMXYdsfR-DZMR3txG1_bBmBdchlc-yA,848
|
|
21
|
+
ocf_data_sampler/numpy_sample/__init__.py,sha256=jWvN4BDYAgoFkdGBxjNrYioZdZNVbIcP4RsNGJCEGm0,345
|
|
22
|
+
ocf_data_sampler/numpy_sample/collate.py,sha256=y8QFUhskaAfOMP22aVkexwyGAwLHbNE-q1pOZ6txWKA,2227
|
|
23
|
+
ocf_data_sampler/numpy_sample/gsp.py,sha256=4ZckEN7S82UY36e9z6rp5DTp10SAn_cNISBNilpOADw,1008
|
|
24
|
+
ocf_data_sampler/numpy_sample/nwp.py,sha256=eEIRXP09wY99Vq-ItnfQ6U9AY1vJPLYKfUOc83V6ICo,1302
|
|
25
|
+
ocf_data_sampler/numpy_sample/satellite.py,sha256=WYG9_ryOk3RWHWjgcMjIaU-YahEhTXz2xN0rQm-_TTQ,914
|
|
26
|
+
ocf_data_sampler/numpy_sample/site.py,sha256=E2MQKkgUXikbIlKYU4ueNCPoBYJC-vnkbrQ_IwP2hqw,792
|
|
27
|
+
ocf_data_sampler/numpy_sample/sun_position.py,sha256=UklhucCxCT6GMlAhCWL6c4cfWrdc1cWgegrYaqUoHOY,1611
|
|
28
|
+
ocf_data_sampler/select/__init__.py,sha256=E4AJulEbO2K-o0UlG1fgaEteuf_1ZFjHTvrotXSb4YU,332
|
|
29
|
+
ocf_data_sampler/select/dropout.py,sha256=HCx5Wzk8Oh2Z9vV94Jy-ALJsHtGduwvMaQOleQXp5z0,1142
|
|
30
|
+
ocf_data_sampler/select/fill_time_periods.py,sha256=iTtMjIPFYG5xtUYYedAFBLjTWWUa7t7WQ0-yksWf0-E,440
|
|
31
|
+
ocf_data_sampler/select/find_contiguous_time_periods.py,sha256=q7IaNfX95A3z9XHqbhgtkZ4Js1gn5K9Qyp6DVLbsL-Q,11093
|
|
32
|
+
ocf_data_sampler/select/geospatial.py,sha256=4xL-9y674jjoaXeqE52NHCHVfknciE4OEGsZtn9DvP4,4911
|
|
33
|
+
ocf_data_sampler/select/location.py,sha256=26Y5ZjfFngShBwXieuWSoOA-RLaRzci4TTmcDk3Wg7U,2015
|
|
34
|
+
ocf_data_sampler/select/select_spatial_slice.py,sha256=WNxwur9Q5oetvogATw8-hNejDuEwrXHzuZIovFDjNJA,11488
|
|
35
|
+
ocf_data_sampler/select/select_time_slice.py,sha256=D5P_cSvnv8Qs49K5au7lPxDr9U_VmDn42s5leMzHt0k,6122
|
|
36
|
+
ocf_data_sampler/select/spatial_slice_for_dataset.py,sha256=3tRrMBXr7s4CnClbVSIq7hpls3H4Y3qYTDwswcxCCCE,1763
|
|
37
|
+
ocf_data_sampler/select/time_slice_for_dataset.py,sha256=LMw8KnOCKnPjD0m4UubAWERpaiQtzRKkI2cSh5a0A-M,4335
|
|
38
|
+
ocf_data_sampler/torch_datasets/__init__.py,sha256=nJUa2KzVa84ZoM0PT2AbDz26ennmAYc7M7WJVfypPMs,85
|
|
39
|
+
ocf_data_sampler/torch_datasets/process_and_combine.py,sha256=ygRBf70Jd6turmwLrv0Fsxo_Ge-54N5S2NUntyRxtJk,4305
|
|
40
|
+
ocf_data_sampler/torch_datasets/pvnet_uk_regional.py,sha256=QRFqbdfNchVWj4y70n-rJdFvFGvQj-WpZLdFqWjnOTw,5543
|
|
41
|
+
ocf_data_sampler/torch_datasets/site.py,sha256=2fN2tw5tCXoOkh8vzRWWm_5FNGglGwJInTanJgV4Xuo,14455
|
|
42
|
+
ocf_data_sampler/torch_datasets/valid_time_periods.py,sha256=Qo65qUHtle_bW5tLTYr7empHTRv-lpjvfx_6GNJj3Xg,4371
|
|
43
|
+
scripts/refactor_site.py,sha256=asZ27hQ4IyXgCCUaFJqcz1ObBNcV2W3ywqHBpSXA_fc,1728
|
|
44
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
|
+
tests/conftest.py,sha256=68hH-HPdHPLvLrtYJU8bjfkdGKbhPfNveLKvUs6_Lr0,7970
|
|
46
|
+
tests/config/test_config.py,sha256=eaye_F7-el4tTP4n2vRME8qlV0b2jaKUX4HhgOUpa7E,5203
|
|
47
|
+
tests/config/test_save.py,sha256=rA_XVxP1pOxB--5Ebujz4T5o-VbcrCbg2VSlSq2iI0o,1318
|
|
48
|
+
tests/load/test_load_gsp.py,sha256=aT_nqaSXmUTcdHzuTT7AmXJr3R31k4OEN-Fv3eLxlQE,424
|
|
49
|
+
tests/load/test_load_nwp.py,sha256=3qyyDkB1q9t3tyAwogfotNrxqUOpXXimco1CImoEWGg,753
|
|
50
|
+
tests/load/test_load_satellite.py,sha256=STX5AqqmOAgUgE9R1xyq_sM3P1b8NKdGjO-hDhayfxM,524
|
|
51
|
+
tests/load/test_load_sites.py,sha256=T9lSEnGPI8FQISudVYHHNTHeplNS62Vrx48jaZ6J_Jo,364
|
|
52
|
+
tests/numpy_sample/test_collate.py,sha256=oWVNRR0LyF0iqaxjsq6hPMmkSGIyvGVlAM6q2rqvXqQ,840
|
|
53
|
+
tests/numpy_sample/test_gsp.py,sha256=FLlq4SlJ-9cSRAepf4_ksA6PsUVKegnKEAc5pUojCJ0,1458
|
|
54
|
+
tests/numpy_sample/test_nwp.py,sha256=yf4u7mAU0E3FQ4xAH6YjuHuHBzzFoXjHSFNkOVJUdSM,1455
|
|
55
|
+
tests/numpy_sample/test_satellite.py,sha256=cCqtn5See-uSNfh89COGTUQNuFm6sIZ8QmBVHsuUeRI,1189
|
|
56
|
+
tests/numpy_sample/test_sun_position.py,sha256=_ENYzsNBVPdNXf--FI-UUFqw2u5w7_zqw6LcENU2uZM,2504
|
|
57
|
+
tests/select/test_dropout.py,sha256=kiycl7RxAQYMCZJlokmx6Da5h_oBpSs8Is8pmSW4gOU,2413
|
|
58
|
+
tests/select/test_fill_time_periods.py,sha256=o59f2YRe5b0vJrG3B0aYZkYeHnpNk4s6EJxdXZluNQg,907
|
|
59
|
+
tests/select/test_find_contiguous_time_periods.py,sha256=kOga_V7er5We7ewMARXaKdM3agOhsvZYx8inXtUn1PM,5976
|
|
60
|
+
tests/select/test_location.py,sha256=_WZk2FPYeJ-nIfCJS6Sp_yaVEEo7m31DmMFoZzgyCts,2712
|
|
61
|
+
tests/select/test_select_spatial_slice.py,sha256=7EX9b6g-pMdACQx3yefjs5do2s-Rho2UmKevV4oglsU,5147
|
|
62
|
+
tests/select/test_select_time_slice.py,sha256=K1EJR5TwZa9dJf_YTEHxGtvs398iy1xS2lr1BgJZkoo,9603
|
|
63
|
+
tests/torch_datasets/conftest.py,sha256=eRCzHE7cxS4AoskExkCGFDBeqItktAYNAdkfpMoFCeE,629
|
|
64
|
+
tests/torch_datasets/test_process_and_combine.py,sha256=mbjQdqzLhox-U2sc1Ec68xLz95b3XOyPa7WchgxUM88,4256
|
|
65
|
+
tests/torch_datasets/test_pvnet_uk_regional.py,sha256=dLY861PMyQ_buTksP8d0UXzfKsZ_CFNgceSYVGXRIRs,2134
|
|
66
|
+
tests/torch_datasets/test_site.py,sha256=TSmdpD0OFid6e8eRgeB5FGxglUN1L2t4cIuMTfjA7jE,4539
|
|
67
|
+
ocf_data_sampler-0.0.43.dist-info/LICENSE,sha256=F-Q3UFCR-BECSocV55BFDpn4YKxve9PKrm-lTt6o_Tg,1073
|
|
68
|
+
ocf_data_sampler-0.0.43.dist-info/METADATA,sha256=pqYvFJO9iGZnsMneHiF0WobuYrSpfxG_Cw701uBi480,11431
|
|
69
|
+
ocf_data_sampler-0.0.43.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
70
|
+
ocf_data_sampler-0.0.43.dist-info/top_level.txt,sha256=Faob6N6cFdPc5eUpCTYcXgCaNhi4XLLteUL5W5ayYmg,31
|
|
71
|
+
ocf_data_sampler-0.0.43.dist-info/RECORD,,
|
scripts/refactor_site.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
""" Helper functions for refactoring legacy site data """
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def legacy_format(data_ds, metadata_df):
|
|
5
|
+
"""This formats old legacy data to the new format.
|
|
6
|
+
|
|
7
|
+
1. This renames the columns in the metadata
|
|
8
|
+
2. Re-formats the site data from data variables named by the site_id to
|
|
9
|
+
a data array with a site_id dimension. Also adds capacity_kwp to the dataset as a time series for each site_id
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
if "system_id" in metadata_df.columns:
|
|
13
|
+
metadata_df["site_id"] = metadata_df["system_id"]
|
|
14
|
+
|
|
15
|
+
if "capacity_megawatts" in metadata_df.columns:
|
|
16
|
+
metadata_df["capacity_kwp"] = metadata_df["capacity_megawatts"] * 1000
|
|
17
|
+
|
|
18
|
+
# only site data has the site_id as data variables.
|
|
19
|
+
# We want to join them all together and create another coordinate called site_id
|
|
20
|
+
if "0" in data_ds:
|
|
21
|
+
gen_df = data_ds.to_dataframe()
|
|
22
|
+
gen_da = xr.DataArray(
|
|
23
|
+
data=gen_df.values,
|
|
24
|
+
coords=(
|
|
25
|
+
("time_utc", gen_df.index.values),
|
|
26
|
+
("site_id", metadata_df["site_id"]),
|
|
27
|
+
),
|
|
28
|
+
name="generation_kw",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
capacity_df = gen_df
|
|
32
|
+
for col in capacity_df.columns:
|
|
33
|
+
capacity_df[col] = metadata_df[metadata_df["site_id"].astype(str) == col][
|
|
34
|
+
"capacity_kwp"
|
|
35
|
+
].iloc[0]
|
|
36
|
+
capacity_da = xr.DataArray(
|
|
37
|
+
data=capacity_df.values,
|
|
38
|
+
coords=(
|
|
39
|
+
("time_utc", gen_df.index.values),
|
|
40
|
+
("site_id", metadata_df["site_id"]),
|
|
41
|
+
),
|
|
42
|
+
name="capacity_kwp",
|
|
43
|
+
)
|
|
44
|
+
data_ds = xr.Dataset(
|
|
45
|
+
{
|
|
46
|
+
"generation_kw": gen_da,
|
|
47
|
+
"capacity_kwp": capacity_da,
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
return data_ds
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import tempfile
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from pydantic import ValidationError
|
|
5
|
+
|
|
6
|
+
from ocf_data_sampler.config import (
|
|
7
|
+
load_yaml_configuration,
|
|
8
|
+
Configuration,
|
|
9
|
+
save_yaml_configuration
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_default_configuration():
|
|
14
|
+
"""Test default pydantic class"""
|
|
15
|
+
|
|
16
|
+
_ = Configuration()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_load_yaml_configuration(test_config_filename):
|
|
20
|
+
"""
|
|
21
|
+
Test that yaml loading works for 'test_config.yaml'
|
|
22
|
+
and fails for an empty .yaml file
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# check we get an error if loading a file with no config
|
|
26
|
+
with tempfile.NamedTemporaryFile(suffix=".yaml") as fp:
|
|
27
|
+
filename = fp.name
|
|
28
|
+
|
|
29
|
+
# check that temp file can't be loaded
|
|
30
|
+
with pytest.raises(TypeError):
|
|
31
|
+
_ = load_yaml_configuration(filename)
|
|
32
|
+
|
|
33
|
+
# test can load test_config.yaml
|
|
34
|
+
config = load_yaml_configuration(test_config_filename)
|
|
35
|
+
|
|
36
|
+
assert isinstance(config, Configuration)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_yaml_save(test_config_filename):
|
|
40
|
+
"""
|
|
41
|
+
Check configuration can be saved to a .yaml file
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
test_config = load_yaml_configuration(test_config_filename)
|
|
45
|
+
|
|
46
|
+
with tempfile.NamedTemporaryFile(suffix=".yaml") as fp:
|
|
47
|
+
filename = fp.name
|
|
48
|
+
|
|
49
|
+
# save default config to file
|
|
50
|
+
save_yaml_configuration(test_config, filename)
|
|
51
|
+
|
|
52
|
+
# check the file can be loaded back
|
|
53
|
+
tmp_config = load_yaml_configuration(filename)
|
|
54
|
+
|
|
55
|
+
# check loaded configuration is the same as the one passed to save
|
|
56
|
+
assert test_config == tmp_config
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_extra_field_error():
|
|
60
|
+
"""
|
|
61
|
+
Check an extra parameters in config causes error
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
configuration = Configuration()
|
|
65
|
+
configuration_dict = configuration.model_dump()
|
|
66
|
+
configuration_dict["extra_field"] = "extra_value"
|
|
67
|
+
with pytest.raises(ValidationError, match="Extra inputs are not permitted"):
|
|
68
|
+
_ = Configuration(**configuration_dict)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_incorrect_interval_start_minutes(test_config_filename):
|
|
72
|
+
"""
|
|
73
|
+
Check a history length not divisible by time resolution causes error
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
configuration = load_yaml_configuration(test_config_filename)
|
|
77
|
+
|
|
78
|
+
configuration.input_data.nwp['ukv'].interval_start_minutes = -1111
|
|
79
|
+
with pytest.raises(
|
|
80
|
+
ValueError,
|
|
81
|
+
match="interval_start_minutes must be divisible by time_resolution_minutes"
|
|
82
|
+
):
|
|
83
|
+
_ = Configuration(**configuration.model_dump())
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_incorrect_interval_end_minutes(test_config_filename):
|
|
87
|
+
"""
|
|
88
|
+
Check a forecast length not divisible by time resolution causes error
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
configuration = load_yaml_configuration(test_config_filename)
|
|
92
|
+
|
|
93
|
+
configuration.input_data.nwp['ukv'].interval_end_minutes = 1111
|
|
94
|
+
with pytest.raises(
|
|
95
|
+
ValueError,
|
|
96
|
+
match="interval_end_minutes must be divisible by time_resolution_minutes"
|
|
97
|
+
):
|
|
98
|
+
_ = Configuration(**configuration.model_dump())
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_incorrect_nwp_provider(test_config_filename):
|
|
102
|
+
"""
|
|
103
|
+
Check an unexpected nwp provider causes error
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
configuration = load_yaml_configuration(test_config_filename)
|
|
107
|
+
|
|
108
|
+
configuration.input_data.nwp['ukv'].provider = "unexpected_provider"
|
|
109
|
+
with pytest.raises(Exception, match="NWP provider"):
|
|
110
|
+
_ = Configuration(**configuration.model_dump())
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_incorrect_dropout(test_config_filename):
|
|
114
|
+
"""
|
|
115
|
+
Check a dropout timedelta over 0 causes error and 0 doesn't
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
configuration = load_yaml_configuration(test_config_filename)
|
|
119
|
+
|
|
120
|
+
# check a positive number is not allowed
|
|
121
|
+
configuration.input_data.nwp['ukv'].dropout_timedeltas_minutes = [120]
|
|
122
|
+
with pytest.raises(Exception, match="Dropout timedeltas must be negative"):
|
|
123
|
+
_ = Configuration(**configuration.model_dump())
|
|
124
|
+
|
|
125
|
+
# check 0 is allowed
|
|
126
|
+
configuration.input_data.nwp['ukv'].dropout_timedeltas_minutes = [0]
|
|
127
|
+
_ = Configuration(**configuration.model_dump())
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_incorrect_dropout_fraction(test_config_filename):
|
|
131
|
+
"""
|
|
132
|
+
Check dropout fraction outside of range causes error
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
configuration = load_yaml_configuration(test_config_filename)
|
|
136
|
+
|
|
137
|
+
configuration.input_data.nwp['ukv'].dropout_fraction= 1.1
|
|
138
|
+
|
|
139
|
+
with pytest.raises(ValidationError, match="Input should be less than or equal to 1"):
|
|
140
|
+
_ = Configuration(**configuration.model_dump())
|
|
141
|
+
|
|
142
|
+
configuration.input_data.nwp['ukv'].dropout_fraction= -0.1
|
|
143
|
+
with pytest.raises(ValidationError, match="Input should be greater than or equal to 0"):
|
|
144
|
+
_ = Configuration(**configuration.model_dump())
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_inconsistent_dropout_use(test_config_filename):
|
|
148
|
+
"""
|
|
149
|
+
Check dropout fraction outside of range causes error
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
configuration = load_yaml_configuration(test_config_filename)
|
|
153
|
+
configuration.input_data.satellite.dropout_fraction= 1.0
|
|
154
|
+
configuration.input_data.satellite.dropout_timedeltas_minutes = None
|
|
155
|
+
|
|
156
|
+
with pytest.raises(ValueError, match="To dropout fraction > 0 requires a list of dropout timedeltas"):
|
|
157
|
+
_ = Configuration(**configuration.model_dump())
|
|
158
|
+
configuration.input_data.satellite.dropout_fraction= 0.0
|
|
159
|
+
configuration.input_data.satellite.dropout_timedeltas_minutes = [-120, -60]
|
|
160
|
+
with pytest.raises(ValueError, match="To use dropout timedeltas dropout fraction should be > 0"):
|
|
161
|
+
_ = Configuration(**configuration.model_dump())
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Tests for configuration saving functionality."""
|
|
2
|
+
import pytest
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import tempfile
|
|
5
|
+
import yaml
|
|
6
|
+
|
|
7
|
+
from ocf_data_sampler.config import Configuration, save_yaml_configuration
|
|
8
|
+
|
|
9
|
+
@pytest.fixture
|
|
10
|
+
def temp_dir():
|
|
11
|
+
"""Create a temporary directory."""
|
|
12
|
+
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
13
|
+
yield Path(tmpdirname)
|
|
14
|
+
|
|
15
|
+
def test_save_yaml_configuration_basic(temp_dir):
|
|
16
|
+
"""Test basic configuration saving functionality."""
|
|
17
|
+
config = Configuration()
|
|
18
|
+
filepath = temp_dir / "config.yaml"
|
|
19
|
+
result = save_yaml_configuration(config, filepath)
|
|
20
|
+
|
|
21
|
+
assert filepath.exists()
|
|
22
|
+
with open(filepath) as f:
|
|
23
|
+
loaded_yaml = yaml.safe_load(f)
|
|
24
|
+
assert isinstance(loaded_yaml, dict)
|
|
25
|
+
|
|
26
|
+
def test_save_yaml_configuration_none_filename():
|
|
27
|
+
"""Test that None filename raises ValueError."""
|
|
28
|
+
config = Configuration()
|
|
29
|
+
with pytest.raises(ValueError, match="filename cannot be None"):
|
|
30
|
+
save_yaml_configuration(config, None)
|
|
31
|
+
|
|
32
|
+
def test_save_yaml_configuration_invalid_directory(temp_dir):
|
|
33
|
+
"""Test handling of invalid directory paths."""
|
|
34
|
+
config = Configuration()
|
|
35
|
+
invalid_path = (temp_dir / "nonexistent" / "config.yaml").resolve()
|
|
36
|
+
with pytest.raises(ValueError, match="Directory does not exist"):
|
|
37
|
+
save_yaml_configuration(config, invalid_path)
|
tests/conftest.py
CHANGED
|
@@ -6,11 +6,19 @@ import pytest
|
|
|
6
6
|
import xarray as xr
|
|
7
7
|
import tempfile
|
|
8
8
|
|
|
9
|
+
from ocf_data_sampler.config.model import Site
|
|
10
|
+
from ocf_data_sampler.config import load_yaml_configuration, save_yaml_configuration
|
|
11
|
+
|
|
12
|
+
_top_test_directory = os.path.dirname(os.path.realpath(__file__))
|
|
13
|
+
|
|
14
|
+
@pytest.fixture()
|
|
15
|
+
def test_config_filename():
|
|
16
|
+
return f"{_top_test_directory}/test_data/configs/test_config.yaml"
|
|
9
17
|
|
|
10
18
|
|
|
11
19
|
@pytest.fixture(scope="session")
|
|
12
20
|
def config_filename():
|
|
13
|
-
return f"{os.path.dirname(os.path.abspath(__file__))}/test_data/pvnet_test_config.yaml"
|
|
21
|
+
return f"{os.path.dirname(os.path.abspath(__file__))}/test_data/configs/pvnet_test_config.yaml"
|
|
14
22
|
|
|
15
23
|
|
|
16
24
|
@pytest.fixture(scope="session")
|
|
@@ -192,6 +200,68 @@ def ds_uk_gsp():
|
|
|
192
200
|
})
|
|
193
201
|
|
|
194
202
|
|
|
203
|
+
@pytest.fixture(scope="session")
|
|
204
|
+
def data_sites() -> Site:
|
|
205
|
+
"""
|
|
206
|
+
Make fake data for sites
|
|
207
|
+
Returns: filename for netcdf file, and csv metadata
|
|
208
|
+
"""
|
|
209
|
+
times = pd.date_range("2023-01-01 00:00", "2023-01-02 00:00", freq="30min")
|
|
210
|
+
site_ids = list(range(0,10))
|
|
211
|
+
capacity_kwp_1d = np.array([0.1,1.1,4,6,8,9,15,2,3,4])
|
|
212
|
+
# these are quite specific for the fake satellite data
|
|
213
|
+
longitude = np.arange(-4, -3, 0.1)
|
|
214
|
+
latitude = np.arange(51, 52, 0.1)
|
|
215
|
+
|
|
216
|
+
generation = np.random.uniform(0, 200, size=(len(times), len(site_ids))).astype(np.float32)
|
|
217
|
+
|
|
218
|
+
# repeat capacity in new dims len(times) times
|
|
219
|
+
capacity_kwp = (np.tile(capacity_kwp_1d, len(times))).reshape(len(times),10)
|
|
220
|
+
|
|
221
|
+
coords = (
|
|
222
|
+
("time_utc", times),
|
|
223
|
+
("site_id", site_ids),
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
da_cap = xr.DataArray(
|
|
227
|
+
capacity_kwp,
|
|
228
|
+
coords=coords,
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
da_gen = xr.DataArray(
|
|
232
|
+
generation,
|
|
233
|
+
coords=coords,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# metadata
|
|
237
|
+
meta_df = pd.DataFrame(columns=[], data = [])
|
|
238
|
+
meta_df['site_id'] = site_ids
|
|
239
|
+
meta_df['capacity_kwp'] = capacity_kwp_1d
|
|
240
|
+
meta_df['longitude'] = longitude
|
|
241
|
+
meta_df['latitude'] = latitude
|
|
242
|
+
|
|
243
|
+
generation = xr.Dataset({
|
|
244
|
+
"capacity_kwp": da_cap,
|
|
245
|
+
"generation_kw": da_gen,
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
249
|
+
filename = tmpdir + "/sites.netcdf"
|
|
250
|
+
filename_csv = tmpdir + "/sites_metadata.csv"
|
|
251
|
+
generation.to_netcdf(filename)
|
|
252
|
+
meta_df.to_csv(filename_csv)
|
|
253
|
+
|
|
254
|
+
site = Site(
|
|
255
|
+
file_path=filename,
|
|
256
|
+
metadata_file_path=filename_csv,
|
|
257
|
+
interval_start_minutes=-30,
|
|
258
|
+
interval_end_minutes=60,
|
|
259
|
+
time_resolution_minutes=30,
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
yield site
|
|
263
|
+
|
|
264
|
+
|
|
195
265
|
@pytest.fixture(scope="session")
|
|
196
266
|
def uk_gsp_zarr_path(ds_uk_gsp):
|
|
197
267
|
|
|
@@ -200,3 +270,18 @@ def uk_gsp_zarr_path(ds_uk_gsp):
|
|
|
200
270
|
ds_uk_gsp.to_zarr(filename)
|
|
201
271
|
yield filename
|
|
202
272
|
|
|
273
|
+
|
|
274
|
+
@pytest.fixture()
|
|
275
|
+
def pvnet_config_filename(
|
|
276
|
+
tmp_path, config_filename, nwp_ukv_zarr_path, uk_gsp_zarr_path, sat_zarr_path
|
|
277
|
+
):
|
|
278
|
+
|
|
279
|
+
# adjust config to point to the zarr file
|
|
280
|
+
config = load_yaml_configuration(config_filename)
|
|
281
|
+
config.input_data.nwp["ukv"].zarr_path = nwp_ukv_zarr_path
|
|
282
|
+
config.input_data.satellite.zarr_path = sat_zarr_path
|
|
283
|
+
config.input_data.gsp.zarr_path = uk_gsp_zarr_path
|
|
284
|
+
|
|
285
|
+
filename = f"{tmp_path}/configuration.yaml"
|
|
286
|
+
save_yaml_configuration(config, filename)
|
|
287
|
+
return filename
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from ocf_data_sampler.load.gsp import open_gsp
|
|
2
|
+
import xarray as xr
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_open_gsp(uk_gsp_zarr_path):
|
|
6
|
+
da = open_gsp(uk_gsp_zarr_path)
|
|
7
|
+
|
|
8
|
+
assert isinstance(da, xr.DataArray)
|
|
9
|
+
assert da.dims == ("time_utc", "gsp_id")
|
|
10
|
+
|
|
11
|
+
assert "nominal_capacity_mwp" in da.coords
|
|
12
|
+
assert "effective_capacity_mwp" in da.coords
|
|
13
|
+
assert "x_osgb" in da.coords
|
|
14
|
+
assert "y_osgb" in da.coords
|
|
15
|
+
assert da.shape == (49, 318)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from xarray import DataArray
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from ocf_data_sampler.load.nwp import open_nwp
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_load_ukv(nwp_ukv_zarr_path):
|
|
9
|
+
da = open_nwp(zarr_path=nwp_ukv_zarr_path, provider="ukv")
|
|
10
|
+
assert isinstance(da, DataArray)
|
|
11
|
+
assert da.dims == ("init_time_utc", "step", "channel", "x_osgb", "y_osgb")
|
|
12
|
+
assert da.shape == (24 * 7, 11, 4, 50, 100)
|
|
13
|
+
assert np.issubdtype(da.dtype, np.number)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_load_ecmwf(nwp_ecmwf_zarr_path):
|
|
17
|
+
da = open_nwp(zarr_path=nwp_ecmwf_zarr_path, provider="ecmwf")
|
|
18
|
+
assert isinstance(da, DataArray)
|
|
19
|
+
assert da.dims == ("init_time_utc", "step", "channel", "longitude", "latitude")
|
|
20
|
+
assert da.shape == (24 * 7, 15, 3, 15, 12)
|
|
21
|
+
assert np.issubdtype(da.dtype, np.number)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from ocf_data_sampler.load.satellite import open_sat_data
|
|
2
|
+
import xarray as xr
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_open_satellite(sat_zarr_path):
|
|
7
|
+
da = open_sat_data(zarr_path=sat_zarr_path)
|
|
8
|
+
|
|
9
|
+
assert isinstance(da, xr.DataArray)
|
|
10
|
+
assert da.dims == ("time_utc", "channel", "x_geostationary", "y_geostationary")
|
|
11
|
+
# 576 is 2 days of data at 5 minutes intervals, 12 * 24 * 2
|
|
12
|
+
# There are 11 channels
|
|
13
|
+
# There are 49 x 20 pixels
|
|
14
|
+
assert da.shape == (576, 11, 49, 20)
|
|
15
|
+
assert np.issubdtype(da.dtype, np.number)
|
|
16
|
+
|
|
17
|
+
|