├── CITATION
├── Excel
├── Ninja Automator.vb
├── Ninja Automator.xlsm
├── README.md
└── ninja_automator.vb
├── LICENSE
├── R
├── example.r
├── ninja_automator.r
├── renewables.ninja.solar.farms.csv
├── renewables.ninja.wind.farms.csv
└── renewables.ninja.wind.output.csv
└── README.md
/CITATION:
--------------------------------------------------------------------------------
1 | To reference the Renewables.ninja in publications, please cite both of the following papers:
2 |
3 | S Pfenninger and I Staffell, 2016. Long-term patterns of European PV output using 30 years of validated hourly reanalysis and satellite data. Energy, 114, 1251-1265. https://dx.doi.org/10.1016/j.energy.2016.08.060
4 |
5 | I Staffell and S Pfenninger, 2016. Using bias-corrected reanalysis to simulate current and future wind power output. Energy, 114, 1224–1239. https://dx.doi.org/10.1016/j.energy.2016.08.068
6 |
--------------------------------------------------------------------------------
/Excel/Ninja Automator.vb:
--------------------------------------------------------------------------------
1 | '
2 | '
3 | ' BSD 3-Clause License
4 | ' Copyright (c) 2018, Iain Staffell
5 | ' All rights reserved.
6 | ' See license text at the bottom of this script..
7 | '
8 | '
9 | ' MENU:
10 | '
11 | ' * Bansenshukai()
12 | '
13 | ' Run solar PV simulation and download results into the active worksheet
14 | '
15 | ' Requires the following named ranges to exist (defined at worksheet or workbook level)
16 | ' - for model inputs:
17 | ' TOKEN, DATASET, YEAR, LON, LAT, CAPACITY, AGGREGATION, SYSTEM_LOSS, TRACKING, TILT, AZIMUTH
18 | ' - for writing model results:
19 | ' OUTPUT
20 | '
21 | '
22 | '
23 | ' * Shoninki()
24 | '
25 | ' Run wind simulation and download results into the active worksheet
26 | '
27 | ' Requires the following named ranges to exist (defined at worksheet or workbook level)
28 | ' - for model inputs:
29 | ' TOKEN, DATASET, YEAR, LON, LAT, CAPACITY, AGGREGATION, HEIGHT, TURBINE
30 | ' - for writing model results:
31 | ' OUTPUT
32 | '
33 | '
34 | '
35 | ' * Ninpiden(Url, Par, Tok)
36 | '
37 | ' Background function to communicate with the renewables.ninja API
38 | ' Takes three parameters:
39 | ' Url = the base address of the API model
40 | ' Par = a string containing the parameters to pass to the model
41 | ' Tok = the string containing the user token
42 | ' Returns an array of strings (the rows of CSV data)
43 | '
44 | '
45 |
46 |
47 | ' DOWNLOAD SOLAR DATA
48 | Sub Bansenshukai()
49 |
50 |
51 |
52 | '''
53 | ''' READ IN PARAMETERS
54 | '''
55 |
56 | Tok = Range("TOKEN")
57 | dataset = Range("DATASET")
58 | date_from = Range("YEAR") & "-01-01"
59 | date_to = Range("YEAR") & "-12-31"
60 | lon = Range("LON")
61 | lat = Range("LAT")
62 | capacity = Range("CAPACITY")
63 | aggregat = Range("AGGREGATION")
64 |
65 | loss = Range("SYSTEM_LOSS")
66 | track = Range("TRACKING")
67 | tilt = Range("TILT")
68 | azimuth = Range("AZIMUTH")
69 |
70 |
71 |
72 | '''
73 | ''' BUILD THE REQUEST URL
74 | '''
75 |
76 | Url = "https://www.renewables.ninja/api/data/pv?"
77 |
78 | Par = "lat=" & lat & "&lon=" & lon & "&date_from=" & date_from & "&date_to=" & date_to & _
79 | "&dataset=" & dataset & "&capacity=" & capacity & "&system_loss=" & loss / 100 & _
80 | "&tracking=" & track & "&tilt=" & tilt & "&azim=" & azimuth & "&format=csv"
81 |
82 | If (aggregat <> "hour") Then Par = Par & "&mean=" & aggregat
83 |
84 |
85 | ' set a warning that we're updating
86 | Call UpdateMessage
87 |
88 |
89 |
90 | '''
91 | ''' RUN API SIMULATION & DOWNLOAD DATA
92 | '''
93 |
94 | csv = Ninpiden(Url, Par, Tok)
95 |
96 |
97 |
98 | '''
99 | ''' PASTE INTO SPREADSHEET
100 | '''
101 |
102 | If Not (IsEmpty(csv)) Then
103 |
104 | ' spit it into the workbook
105 | Range("OUTPUT").Offset(1).Select
106 | Range(ActiveCell, ActiveCell.Offset(UBound(csv))).Value = Application.Transpose(csv)
107 |
108 | ' set a clear signal
109 | Call CompleteMessage(Url, Par)
110 |
111 | End If
112 |
113 | End Sub
114 |
115 |
116 |
117 |
118 | ' DOWNLOAD WIND DATA
119 | Sub Shoninki()
120 |
121 |
122 |
123 | '''
124 | ''' READ IN PARAMETERS
125 | '''
126 |
127 | Tok = Range("TOKEN")
128 | dataset = Range("DATASET")
129 | date_from = Range("YEAR") & "-01-01"
130 | date_to = Range("YEAR") & "-12-31"
131 | lon = Range("LON")
132 | lat = Range("LAT")
133 | capacity = Range("CAPACITY")
134 | aggregat = Range("AGGREGATION")
135 |
136 | Height = Range("HEIGHT")
137 | turbine = Range("TURBINE")
138 |
139 |
140 |
141 | '''
142 | ''' BUILD THE REQUEST URL
143 | '''
144 |
145 | Url = "https://www.renewables.ninja/api/data/wind?"
146 |
147 | Par = "lat=" & lat & "&lon=" & lon & "&date_from=" & date_from & "&date_to=" & date_to & _
148 | "&dataset=" & dataset & "&capacity=" & capacity & "&height=" & Height & _
149 | "&turbine=" & turbine & "&format=csv"
150 |
151 | If (aggregat <> "hour") Then Par = Par & "&mean=" & aggregat
152 |
153 |
154 | ' set a warning that we're updating
155 | Call UpdateMessage
156 |
157 |
158 |
159 | '''
160 | ''' RUN API SIMULATION & DOWNLOAD DATA
161 | '''
162 |
163 | csv = Ninpiden(Url, Par, Tok)
164 |
165 |
166 |
167 | '''
168 | ''' PASTE INTO SPREADSHEET
169 | '''
170 |
171 | If Not (IsEmpty(csv)) Then
172 |
173 | ' spit it into the workbook
174 | Range("OUTPUT").Offset(1).Select
175 | Range(ActiveCell, ActiveCell.Offset(UBound(csv))).Value = Application.Transpose(csv)
176 |
177 | ' set a clear signal
178 | Call CompleteMessage(Url, Par)
179 |
180 | End If
181 |
182 | End Sub
183 |
184 |
185 |
186 |
187 |
188 | ' DOWNLOADER COMPONENT
189 | Function Ninpiden(Url As Variant, Par As Variant, Tok As Variant) As Variant
190 |
191 |
192 |
193 | '''
194 | ''' DOWNLOAD DATA
195 | '''
196 |
197 | Set httpObject = CreateObject("MSXML2.XMLHTTP")
198 |
199 | With httpObject
200 |
201 | .Open "GET", Url & Par, False
202 | .setRequestHeader "Authorization", "Token " & Tok
203 | .send (Par)
204 |
205 |
206 | ' wait until data has been downloaded
207 | Do While 1
208 | If .readyState = 4 Then Exit Do
209 | DoEvents
210 | Loop
211 |
212 | ' check if we were successful
213 | If .Status <> 200 Then
214 | MsgBox ("Something went wrong, you got HTTP Status " & .Status & _
215 | Chr(10) & Chr(10) & .responseText)
216 | Exit Function
217 | End If
218 |
219 | ' return the resulting code
220 | csv = .responseText
221 |
222 | End With
223 |
224 |
225 | ' split the csv into rows
226 | Ninpiden = Split(csv, Chr(10))
227 |
228 |
229 | End Function
230 |
231 |
232 |
233 | ' UX BABY
234 | Function UpdateMessage()
235 |
236 | Range("OUTPUT").Select
237 |
238 | With Range(Selection, Selection.Offset(0, 1))
239 | .Interior.ThemeColor = xlThemeColorAccent2
240 | .Interior.TintAndShade = 0.7
241 | .Range("A1").Value = "Simulation running!"
242 | .Range("B1").Value = ""
243 | End With
244 |
245 | End Function
246 |
247 |
248 | Function CompleteMessage(Url As Variant, Par As Variant)
249 |
250 | Range("OUTPUT").Select
251 |
252 | With Range(Selection, Selection.Offset(0, 1))
253 | .Interior.ThemeColor = xlThemeColorAccent3
254 | .Interior.TintAndShade = 0.9
255 | .Range("A1").Value = "Complete:"
256 | .Range("B1").Value = Url & Par
257 | End With
258 |
259 | End Function
260 |
261 |
262 | '
263 | '
264 | ' BSD 3-Clause License
265 | ' Copyright (c) 2019, Iain Staffell
266 | ' All rights reserved.
267 | '
268 | '
269 | ' Redistribution and use in source and binary forms, with or without
270 | ' modification, are permitted provided that the following conditions are met:
271 | '
272 | ' * Redistributions of source code must retain the above copyright notice, this
273 | ' list of conditions and the following disclaimer.
274 | '
275 | ' * Redistributions in binary form must reproduce the above copyright notice,
276 | ' this list of conditions and the following disclaimer in the documentation
277 | ' and/or other materials provided with the distribution.
278 | '
279 | ' * Neither the name of the copyright holder nor the names of its
280 | ' contributors may be used to endorse or promote products derived from
281 | ' this software without specific prior written permission.
282 | '
283 | ' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
284 | ' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
285 | ' IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
286 | ' DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
287 | ' FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
288 | ' DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
289 | ' SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
290 | ' CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
291 | ' OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
292 | ' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
293 | '
294 | '
295 |
296 |
297 |
--------------------------------------------------------------------------------
/Excel/Ninja Automator.xlsm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/renewables-ninja/ninja_automator/9dc443416278f8b76f7c7bd145bc3db4d73ec039/Excel/Ninja Automator.xlsm
--------------------------------------------------------------------------------
/Excel/README.md:
--------------------------------------------------------------------------------
1 | ## Ninja Automator Excel Interface
2 |
3 | This provides a VBA routine to run simulations via the Renewables.ninja API and deliver results into a spreadsheet. Usage should be self explanatory, read the INFO worksheet to begin.
4 |
5 | The Excel worksheet provides an example implementation, which allows the user to choose model parameters, and download data as either hourly values, daily averages or monthly averages.
6 |
7 | Tested on [Excel](https://products.office.com/en-gb/excel) 2010, 2013 and 2016 on Windows 7 and 10.
8 |
9 | Requires VBA Macros to be enabled.
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Excel/ninja_automator.vb:
--------------------------------------------------------------------------------
1 | '
2 | '
3 | ' BSD 3-Clause License
4 | ' Copyright (c) 2018, Iain Staffell
5 | ' All rights reserved.
6 | ' See license text at the bottom of this script..
7 | '
8 | '
9 | ' MENU:
10 | '
11 | ' * Bansenshukai()
12 | '
13 | ' Run solar PV simulation and download results into the active worksheet
14 | '
15 | ' Requires the following named ranges to exist (defined at worksheet or workbook level)
16 | ' - for model inputs:
17 | ' TOKEN, DATASET, YEAR, LON, LAT, CAPACITY, AGGREGATION, SYSTEM_LOSS, TRACKING, TILT, AZIMUTH
18 | ' - for writing model results:
19 | ' OUTPUT
20 | '
21 | '
22 | '
23 | ' * Shoninki()
24 | '
25 | ' Run wind simulation and download results into the active worksheet
26 | '
27 | ' Requires the following named ranges to exist (defined at worksheet or workbook level)
28 | ' - for model inputs:
29 | ' TOKEN, DATASET, YEAR, LON, LAT, CAPACITY, AGGREGATION, HEIGHT, TURBINE
30 | ' - for writing model results:
31 | ' OUTPUT
32 | '
33 | '
34 | '
35 | ' * Ninpiden(Url, Par, Tok)
36 | '
37 | ' Background function to communicate with the renewables.ninja API
38 | ' Takes three parameters:
39 | ' Url = the base address of the API model
40 | ' Par = a string containing the parameters to pass to the model
41 | ' Tok = the string containing the user token
42 | ' Returns an array of strings (the rows of CSV data)
43 | '
44 | '
45 |
46 |
47 | ' DOWNLOAD SOLAR DAILY DATA
48 | Sub Bansenshukai()
49 |
50 |
51 |
52 | '''
53 | ''' READ IN PARAMETERS
54 | '''
55 |
56 | Tok = Range("TOKEN")
57 | dataset = Range("DATASET")
58 | date_from = Range("YEAR") & "-01-01"
59 | date_to = Range("YEAR") & "-12-31"
60 | lon = Range("LON")
61 | lat = Range("LAT")
62 | capacity = Range("CAPACITY")
63 | aggregat = Range("AGGREGATION")
64 |
65 | loss = Range("SYSTEM_LOSS")
66 | track = Range("TRACKING")
67 | tilt = Range("TILT")
68 | azimuth = Range("AZIMUTH")
69 |
70 |
71 |
72 | '''
73 | ''' BUILD THE REQUEST URL
74 | '''
75 |
76 | Url = "https://www.renewables.ninja/api/data/pv?"
77 |
78 | Par = "lat=" & lat & "&lon=" & lon & "&date_from=" & date_from & "&date_to=" & date_to & _
79 | "&dataset=" & dataset & "&capacity=" & capacity & "&system_loss=" & loss & _
80 | "&tracking=" & track & "&tilt=" & tilt & "&azim=" & azimuth & "&format=csv"
81 |
82 | If (aggregat <> "hour") Then Par = Par & "&mean=" & aggregat
83 |
84 |
85 | ' set a warning that we're updating
86 | Range("OUTPUT").Select
87 | With Range(Selection, Selection.Offset(0, 1)).Interior
88 | .ThemeColor = xlThemeColorAccent2
89 | .TintAndShade = 0.7
90 | End With
91 |
92 |
93 |
94 | '''
95 | ''' RUN API SIMULATION & DOWNLOAD DATA
96 | '''
97 |
98 | csv = Ninpiden(Url, Par, Tok)
99 |
100 |
101 |
102 | '''
103 | ''' PASTE INTO SPREADSHEET
104 | '''
105 |
106 | If Not (IsEmpty(csv)) Then
107 |
108 | ' spit it into the workbook
109 | Range("OUTPUT").Offset(1).Select
110 | Range(ActiveCell, ActiveCell.Offset(UBound(csv))).Value = Application.Transpose(csv)
111 |
112 | ' set a clear signal
113 | Range("OUTPUT").Select
114 | With Range(Selection, Selection.Offset(0, 1)).Interior
115 | .ThemeColor = xlThemeColorAccent3
116 | .TintAndShade = 0.9
117 | End With
118 |
119 | End If
120 |
121 | End Sub
122 |
123 |
124 |
125 |
126 | ' DOWNLOAD WIND DAILY DATA
127 | Sub Shoninki()
128 |
129 |
130 |
131 | '''
132 | ''' READ IN PARAMETERS
133 | '''
134 |
135 | Tok = Range("TOKEN")
136 | dataset = Range("DATASET")
137 | date_from = Range("YEAR") & "-01-01"
138 | date_to = Range("YEAR") & "-12-31"
139 | lon = Range("LON")
140 | lat = Range("LAT")
141 | capacity = Range("CAPACITY")
142 | aggregat = Range("AGGREGATION")
143 |
144 | Height = Range("HEIGHT")
145 | turbine = Range("TURBINE")
146 |
147 |
148 |
149 | '''
150 | ''' BUILD THE REQUEST URL
151 | '''
152 |
153 | Url = "https://www.renewables.ninja/api/data/wind?"
154 |
155 | Par = "lat=" & lat & "&lon=" & lon & "&date_from=" & date_from & "&date_to=" & date_to & _
156 | "&dataset=" & dataset & "&capacity=" & capacity & "&height=" & Height & _
157 | "&turbine=" & turbine & "&format=csv"
158 |
159 | If (aggregat <> "hour") Then Par = Par & "&mean=" & aggregat
160 |
161 |
162 |
163 | ' set a warning that we're updating
164 | Range("OUTPUT").Select
165 | With Range(Selection, Selection.Offset(0, 1)).Interior
166 | .ThemeColor = xlThemeColorAccent2
167 | .TintAndShade = 0.7
168 | End With
169 |
170 |
171 |
172 | '''
173 | ''' RUN API SIMULATION & DOWNLOAD DATA
174 | '''
175 |
176 | csv = Ninpiden(Url, Par, Tok)
177 |
178 |
179 |
180 | '''
181 | ''' PASTE INTO SPREADSHEET
182 | '''
183 |
184 | If Not (IsEmpty(csv)) Then
185 |
186 | ' spit it into the workbook
187 | Range("OUTPUT").Offset(1).Select
188 | Range(ActiveCell, ActiveCell.Offset(UBound(csv))).Value = Application.Transpose(csv)
189 |
190 | ' set a clear signal
191 | Range("OUTPUT").Select
192 | With Range(Selection, Selection.Offset(0, 1)).Interior
193 | .ThemeColor = xlThemeColorAccent3
194 | .TintAndShade = 0.9
195 | End With
196 |
197 | End If
198 |
199 | End Sub
200 |
201 |
202 |
203 |
204 |
205 | ' DOWNLOADER COMPONENT
206 | Function Ninpiden(Url As Variant, Par As Variant, Tok As Variant) As Variant
207 |
208 |
209 |
210 | '''
211 | ''' DOWNLOAD DATA
212 | '''
213 |
214 | Set httpObject = CreateObject("MSXML2.XMLHTTP")
215 |
216 | With httpObject
217 |
218 | .Open "GET", Url & Par, False
219 | .setRequestHeader "Authorization", "Token " & Tok
220 | .send (Par)
221 |
222 |
223 | ' wait until data has been downloaded
224 | Do While 1
225 | If .readyState = 4 Then Exit Do
226 | DoEvents
227 | Loop
228 |
229 | ' check if we were successful
230 | If .Status <> 200 Then
231 | MsgBox ("Something went wrong, you got HTTP Status " & .Status)
232 | Exit Function
233 | End If
234 |
235 | ' return the resulting code
236 | csv = .responseText
237 |
238 | End With
239 |
240 |
241 | ' split the csv into rows
242 | Ninpiden = Split(csv, Chr(10))
243 |
244 |
245 | End Function
246 |
247 |
248 |
249 |
250 |
251 | '
252 | '
253 | ' BSD 3-Clause License
254 | ' Copyright (c) 2018, Iain Staffell
255 | ' All rights reserved.
256 | '
257 | '
258 | ' Redistribution and use in source and binary forms, with or without
259 | ' modification, are permitted provided that the following conditions are met:
260 | '
261 | ' * Redistributions of source code must retain the above copyright notice, this
262 | ' list of conditions and the following disclaimer.
263 | '
264 | ' * Redistributions in binary form must reproduce the above copyright notice,
265 | ' this list of conditions and the following disclaimer in the documentation
266 | ' and/or other materials provided with the distribution.
267 | '
268 | ' * Neither the name of the copyright holder nor the names of its
269 | ' contributors may be used to endorse or promote products derived from
270 | ' this software without specific prior written permission.
271 | '
272 | ' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
273 | ' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
274 | ' IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
275 | ' DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
276 | ' FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
277 | ' DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
278 | ' SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
279 | ' CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
280 | ' OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
281 | ' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282 | '
283 | '
284 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 | Copyright (c) 2012-2017, Iain Staffell
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | * Neither the name of the copyright holder nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/R/example.r:
--------------------------------------------------------------------------------
1 | ###########################
2 | #### ###
3 | #### ###
4 | ## ## RENEWABLES.NINJA
5 | ##### WEBSITE AUTOMATOR
6 | ##
7 | #
8 | # simple instructions:
9 | # change any file paths in this script from './path/to/' to the directory where you saved the R and CSV files
10 | # change the token string to match that from your user account
11 | # run through the five simple examples below
12 | #
13 |
14 |
15 |
16 |
17 | #####
18 | ## ## MODEL SETUP
19 | #####
20 |
21 | # pre-requisites
22 | library(curl)
23 | source('./path/to/ninja_automator.r')
24 |
25 | # insert your API authorisation token here
26 | token = 'deadbeef0decafbeef0beeffacade0beefedbabe'
27 |
28 | # establish your authorisation
29 | h = new_handle()
30 | handle_setheaders(h, 'Authorization'=paste('Token ', token))
31 |
32 |
33 |
34 |
35 |
36 | #####
37 | ## ## DOWNLOAD RENEWABLE TIME SERIES DATA FOR A SINGLE LOCATION
38 | #####
39 |
40 | # EXAMPLE 1 ::: look at a very tall wind turbine on top of iain's house
41 | # optional args are (for example): from='2014-01-01', to='2014-12-31', dataset='merra2', capacity=1, height=60, turbine='Vestas+V80+2000'
42 | w = ninja_get_wind(lat=51.5, lon=0, height=30)
43 | plot(w$time, w$output, type='l', col='blue')
44 |
45 |
46 | # EXAMPLE 2 ::: or the solar panels facing south-east on stefan's house
47 | # optional args are (for example): from='2014-01-01', to='2014-12-31', dataset='merra2', capacity=1, system_loss=10, tracking=0, tilt=35, azim=180
48 | s = ninja_get_solar(47.5, 8.5, tilt=15, azim=135)
49 | lines(s$time, s$output, col='goldenrod')
50 |
51 |
52 |
53 |
54 |
55 | #####
56 | ## ## DOWNLOAD RENEWABLE TIME SERIES DATA FOR MULTIPLE LOCATIONS
57 | #####
58 |
59 | # EXAMPLE 3 ::: look at wind farms in each of the UK's capitals
60 | # args are the same as for ninja_get_wind - either pass a single values or vectors of values
61 | lat = c(51.5, 56, 51.5, 54.6)
62 | lon = c(0, -3.2, -3.2, -5.9)
63 | turbine = c('Vestas+V80+2000', 'Enercon+E66+1800', 'Siemens+SWT+2.3+93', 'GE+1.5sl')
64 | y = ninja_aggregate_wind(lat, lon, turbine=turbine)
65 |
66 | # how does the hourly data look?
67 | dev.new(width=20)
68 | plot(y$time, y$outputV1, type='l', col='#0E60BA')
69 | lines(y$time, y$outputV2, col='#C80028')
70 | lines(y$time, y$outputV3, col='#2E8C39')
71 | lines(y$time, y$outputV4, col='#FFCF01')
72 |
73 | # how do they correlate?
74 | dev.new()
75 | plot(y[ , -1], pch='.')
76 |
77 | # what about the daily averages?
78 | yd = aggregate(y, by=list(as.Date(y$time)), mean)
79 | dev.new(width=20)
80 | plot(yd$time, yd$outputV1, type='l', col='#0E60BA')
81 | lines(yd$time, yd$outputV2, col='#C80028')
82 | lines(yd$time, yd$outputV3, col='#2E8C39')
83 | lines(yd$time, yd$outputV4, col='#FFCF01')
84 |
85 |
86 |
87 |
88 |
89 | #####
90 | ## ## DOWNLOAD RENEWABLE TIME SERIES DATA FOR MULTIPLE LOCATIONS
91 | ## ## USING CSV FILES FOR DATA INPUT AND OUTPUT
92 | #####
93 |
94 | # EXAMPLE 4 :::: read a set of wind farms from CSV - save their outputs to CSV
95 | # this is the same as example 3 - the UK capital cities
96 | # your csv must have a strict structure: one row per farm, colums = lat, lon, from, to, dataset, capacity, height, turbine - and optionally name (all lowercase!)
97 |
98 | farms = read.csv('./path/to/renewables.ninja.wind.farms.csv', stringsAsFactors=FALSE)
99 |
100 | z = ninja_aggregate_wind(farms$lat, farms$lon, farms$from[1], farms$to[1], farms$dataset, farms$capacity, farms$height, farms$turbine)
101 |
102 | write.csv(z, './path/to/renewables.ninja.wind.output.csv', row.names=FALSE)
103 |
104 |
105 |
106 | # EXAMPLE 5 :::: read a set of solar farms from CSV - save their outputs to CSV
107 | # this is the ten largest US cities - and uses the 'name' column to identify our farms
108 | # your csv must have a strict structure: one row per farm, colums = lat, lon, from, to, dataset, capacity, system_loss, tracking, tilt, azim - and optionally name (all lowercase!)
109 |
110 | farms = read.csv('./path/to/renewables.ninja.solar.farms.csv', stringsAsFactors=FALSE)
111 |
112 | z = ninja_aggregate_solar(farms$lat, farms$lon, farms$from[1], farms$to[1], farms$dataset, farms$capacity, farms$system_loss, farms$tracking, farms$tilt, farms$azim, name=farms$name)
113 |
114 | write.csv(z, './path/to/renewables.ninja.solar.output.csv', row.names=FALSE)
115 |
116 | # how productive are these places
117 | colMeans(z[ , -1]) / farms$capacity
118 |
119 |
120 |
121 |
122 | # now you know the way of the ninja
123 | # use your power wisely
124 | # fight bravely
125 |
--------------------------------------------------------------------------------
/R/ninja_automator.r:
--------------------------------------------------------------------------------
1 | ##################################################################
2 | # #
3 | # BSD 3-Clause License #
4 | # Copyright (C) 2012-2020 Iain Staffell #
5 | # All rights reserved. #
6 | # #
7 | ##################################################################
8 | #### ###
9 | #### ###
10 | ## ## RENEWABLES.NINJA
11 | ##### WEBSITE AUTOMATOR
12 | ##
13 | #
14 | #
15 | # MAIN USER FUNCTIONS:
16 | #
17 | # these contact the renewables.ninja API, perform your simulation
18 | # and then return the results as a dataframe. each function
19 | # requires the latitude and longitude, and optionally takes other
20 | # parameters that you can pass to the API such as wind turbine model
21 | # of solar panel orientation.
22 | #
23 | #
24 | # run a simulation for a single wind or solar farm
25 | # returns a dataframe of timestamps and output values
26 | # ninja_get_wind = function(lat, lon, ...)
27 | # ninja_get_solar = function(lat, lon, ...)
28 | #
29 | # run simulations for a set of wind or solar farms
30 | # returns a dataframe of timestamps and output values for each farm
31 | # ninja_aggregate_wind = function(lat, lon, ...)
32 | # ninja_aggregate_solar = function(lat, lon, ...)
33 | #
34 | #
35 | #
36 | # OTHER BACKGROUND FUNCTIONS:
37 | #
38 | # a list holding data about your api requests
39 | # used to keep track of your usage limits
40 | # apilog$...
41 | #
42 | # background functions to build URLs to access the API
43 | # ninja_build_wind_url = function(lat, lon, ...)
44 | # ninja_build_solar_url = function(lat, lon, ...)
45 | #
46 | # background functions to download and process ninja simulations
47 | # ninja_get_url = function(url)
48 | # ninja_aggregate_urls = function(urls)
49 | #
50 | # background functions that do other stuff
51 | # cat_flush(...)
52 | # format_date(...)
53 | #
54 | #
55 |
56 |
57 |
58 | #####
59 | ## ## PRE-REQUISITES
60 | #####
61 |
62 | library(curl)
63 |
64 |
65 |
66 |
67 |
68 | #####
69 | ## ## FUNCTIONS TO BUILD THE URL FOR API REQUESTS
70 | #####
71 |
72 | # example wind url: https://www.renewables.ninja/api/data/wind?&lat=-37.23&lon=143.05&date_from=2014-01-01&date_to=2014-02-28&capacity=240&dataset=merra2&height=83&turbine=Vestas+V80+2000&format=csv
73 | ninja_build_wind_url = function(lat, lon, from='2014-01-01', to='2014-12-31', dataset='merra2', capacity=1, height=60, turbine='Vestas+V80+2000', raw='false', format='csv')
74 | {
75 | from = format_date(from)
76 | to = format_date(to)
77 | paste0('https://www.renewables.ninja/api/data/wind?&lat=', lat, '&lon=', lon, '&date_from=', from, '&date_to=', to, '&capacity=', capacity, '&dataset=', dataset, '&height=', height, '&turbine=', turbine, '&raw=', raw, '&format=', format)
78 | }
79 |
80 |
81 | # example solar url: https://www.renewables.ninja/api/data/pv?lat=45&lon=22&date_from=2014-01-01&date_to=2014-01-31&dataset=merra2&capacity=1&system_loss=0.1&tracking=0&tilt=35&azim=180&raw=false&format=csv
82 | ninja_build_solar_url = function(lat, lon, from='2014-01-01', to='2014-12-31', dataset='merra2', capacity=1, system_loss=0.1, tracking=0, tilt=35, azim=180, raw='false', format='csv')
83 | {
84 | from = format_date(from)
85 | to = format_date(to)
86 | paste0('https://www.renewables.ninja/api/data/pv?lat=', lat, '&lon=', lon, '&date_from=', from, '&date_to=', to, '&capacity=', capacity, '&dataset=', dataset, '&system_loss=', system_loss, '&tracking=', tracking, '&tilt=', tilt, '&azim=', azim, '&raw=', raw, '&format=', format)
87 | }
88 |
89 |
90 |
91 |
92 |
93 | #####
94 | ## ## FUNCTIONS TO DOWNLOAD A SINGLE REQUEST FROM THE API
95 | #####
96 |
97 | # download wind or solar power output for a given location
98 | #
99 | # pass 'lat' and 'lon', and optionally other api variables
100 | #
101 | # returns a data frame with timestamp and power output
102 | # zero error checking :(
103 | #
104 | ninja_get_wind = function(lat, lon, from='2014-01-01', to='2014-12-31', dataset='merra2', capacity=1, height=60, turbine='Vestas+V80+2000', raw='false')
105 | {
106 | url = ninja_build_wind_url(lat, lon, from, to, dataset, capacity, height, turbine, raw, 'csv')
107 | ninja_get_url(url)
108 | }
109 |
110 |
111 | ninja_get_solar = function(lat, lon, from='2014-01-01', to='2014-12-31', dataset='merra2', capacity=1, system_loss=0.1, tracking=0, tilt=35, azim=180, raw='false')
112 | {
113 | url = ninja_build_solar_url(lat, lon, from, to, dataset, capacity, system_loss, tracking, tilt, azim, raw, 'csv')
114 | ninja_get_url(url)
115 | }
116 |
117 |
118 |
119 | # behind the scenes - this function contacts the ninja API
120 | # converts the CSV returned by the ninja into a data.frame
121 | #
122 | # it also trackes when you made previous server requests
123 | # to ensure you don't exceed your API rate limits
124 | #
125 | ninja_get_url = function(url)
126 | {
127 | # first - check we aren't exceeding our rate limits
128 | apilog$enforce_rate_limits()
129 |
130 | # make a note of when we made this request
131 | apilog$request_time <<- c(Sys.time(), apilog$request_time)
132 |
133 | # grab the data as csv
134 | req = curl(url, handle=h)
135 | csv = read.csv(req, skip=3, stringsAsFactors=FALSE)
136 |
137 | # convert the time column to POSIX
138 | csv[ , 1] = as.POSIXct(csv[ , 1], format="%Y-%m-%d %H:%M")
139 |
140 | # return
141 | csv
142 | }
143 |
144 |
145 |
146 | # here's the global object we use to track api requests
147 | apilog = list()
148 |
149 | # burst speed - how many seconds between individual requests
150 | apilog$burst_speed = 10
151 |
152 | # hourly_limit - how many requests can be made per hour
153 | apilog$hourly_limit = 50
154 |
155 | # a function to ensure we stick within these limits
156 | apilog$enforce_rate_limits = function()
157 | {
158 | # first - check we aren't exceeding our rate limit
159 | if (length(apilog$request_time) >= apilog$hourly_limit)
160 | {
161 | repeat
162 | {
163 | # get the time since our 50th request
164 | elapsed = difftime(Sys.time(), apilog$request_time[apilog$hourly_limit], units='secs')
165 |
166 | # we are safe to continue
167 | if (elapsed > 3600) break
168 |
169 | # approach iain with money to buy a bigger server if you want this rate increasing :)
170 | cat_flush('The ninja API is limited to', apilog$hourly_limit, 'requests per hour: waiting', 5 * ceiling((3600-elapsed)/5), 'seconds to proceed...')
171 | Sys.sleep(5)
172 | }
173 |
174 | cat_flush()
175 |
176 | }
177 |
178 | # second - check we aren't exceeding the burst limit
179 | elapsed = difftime(Sys.time(), apilog$request_time[1], units='secs')
180 | if (elapsed < apilog$burst_speed)
181 | {
182 | Sys.sleep( apilog$burst_speed - elapsed )
183 | }
184 | }
185 |
186 | # a vector saying when we made requests
187 | apilog$request_time = Sys.time()
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 | #####
196 | ## ## FUNCTIONS TO DOWNLOAD AND AGGREGATE MULTIPLE REQUESTS FROM THE API
197 | #####
198 |
199 | # download wind or solar power output for multiple locations
200 | #
201 | # pass 'lat' and 'lon' as vectors, optionally 'from' and 'to' as single strings, optionally other api variables either as single strings or vectors
202 | # optionally pass the 'name' to assign each output time series (column names in the returned data)
203 | #
204 | # returns a data frame with timestamp and power output
205 | # limited error checking :|
206 | #
207 | ninja_aggregate_wind = function(lat, lon, from='2014-01-01', to='2014-12-31', dataset='merra2', capacity=1, height=60, turbine='Vestas+V80+2000', name=NULL)
208 | {
209 | # check our coordinates are of the same length
210 | if (length(lat) != length(lon))
211 | stop("Error in ninja_aggregate_wind: lat and lon should be vectors of the same length!\n")
212 |
213 | # check we only want one time span
214 | if (length(from) != 1 | length(to) != 1)
215 | stop("Error in ninja_aggregate_wind: from and to should be a single date only!\n")
216 |
217 | # check our other parameters are either single values or one value per coordinate
218 | length_parms = c(length(dataset), length(capacity), length(height), length(turbine))
219 | if (!all( length_parms %in% c(1, length(lat)) ))
220 | stop("Error in ninja_aggregate_wind: farm parameters should either be single values or vectors of the same length as lat and lon!\n")
221 |
222 | # convert all our parameters to api request urls
223 | urls = ninja_build_wind_url(lat, lon, from, to, dataset, capacity, height, turbine)
224 |
225 | # do the magic
226 | ninja_aggregate_urls(urls, name)
227 | }
228 |
229 |
230 | ninja_aggregate_solar = function(lat, lon, from='2014-01-01', to='2014-12-31', dataset='merra2', capacity=1, system_loss=0.1, tracking=0, tilt=35, azim=180, name=NULL)
231 | {
232 | # check our coordinates are of the same length
233 | if (length(lat) != length(lon))
234 | stop("Error in ninja_aggregate_solar: lat and lon should be vectors of the same length!\n")
235 |
236 | # check we only want one time span
237 | if (length(from) != 1 | length(to) != 1)
238 | stop("Error in ninja_aggregate_solar: from and to should be a single date only!\n")
239 |
240 | # check our other parameters are either single values or one value per coordinate
241 | length_parms = c(length(dataset), length(capacity), length(system_loss), length(tracking), length(tilt), length(azim))
242 | if (!all( length_parms %in% c(1, length(lat)) ))
243 | stop("Error in ninja_aggregate_solar: farm parameters should either be single values or vectors of the same length as lat and lon!\n")
244 |
245 | # convert all our parameters to api request urls
246 | urls = ninja_build_solar_url(lat, lon, from, to, dataset, capacity, system_loss, tracking, tilt, azim)
247 |
248 | # do the magic
249 | ninja_aggregate_urls(urls, name)
250 | }
251 |
252 |
253 | ninja_aggregate_urls = function(urls, name=NULL)
254 | {
255 | n = length(urls)
256 |
257 | # if we are passing names for our farms - check there's the right number of them
258 | if (!is.null(name))
259 | if (length(name) != n)
260 | stop("Error in ninja_aggregate_urls: name should be a vector the same length as urls / lat and lon!\n")
261 |
262 |
263 | # run through each farm
264 | for (i in 1:n)
265 | {
266 | # i call this UX
267 | cat_flush("Downloading farm", i, "of", n)
268 |
269 | # grab the data for this farm
270 | this_farm = ninja_get_url(urls[i])
271 |
272 | # aggregate our data together
273 | if (i == 1)
274 | all_farms = data.frame(V1=this_farm[ , 2])
275 |
276 | if (i > 1)
277 | all_farms[ , i] = this_farm[ , 2]
278 |
279 | }
280 |
281 | # bind the timestamps onto the aggregated data
282 | all_farms = cbind(this_farm[ , 1], all_farms, stringsAsFactors=FALSE)
283 | colnames(all_farms)[1] = colnames(this_farm)[1]
284 |
285 | # assign names to the output columns
286 | if (!is.null(name))
287 | {
288 | colnames(all_farms)[-1] = make.names(name)
289 | } else {
290 | colnames(all_farms)[-1] = paste0('output', colnames(all_farms)[-1])
291 | }
292 |
293 | # more UX!
294 | cat_flush("Downloaded", n, "farms...\n")
295 |
296 | # return
297 | all_farms
298 | }
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 | #####
307 | ## ## GENERICS
308 | #####
309 |
310 | # console - clear line and flush line
311 | cat_flush = function(...)
312 | {
313 | cat("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b")
314 | cat("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b")
315 | cat("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b")
316 | cat("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b")
317 | cat(...)
318 | flush.console()
319 | }
320 |
321 | # convert unknown date formats into standard posix
322 | # this is overkill, but it allows us to handle 2014-12-31 format
323 | # that the ninja expects plus 31/12/2014 that Excel defaults to
324 | #
325 | # @x - a vector of character dates/datetimes
326 | #
327 | # derived from Cole Beck's "Handling date-times in R" http://biostat.mc.vanderbilt.edu/wiki/pub/Main/ColeBeck/datestimes.pdf
328 | #
329 | format_date = function(x)
330 | {
331 | x1 = x
332 |
333 | # replace blanks with NA and remove
334 | x1[x1 == ""] = NA
335 | x1 = x1[!is.na(x1)]
336 | if (length(x1) == 0)
337 | return(NA)
338 |
339 | # if it's already a time variable, set it to character
340 | if ("POSIXt" %in% class(x1[1]))
341 | x1 = as.character(x1)
342 |
343 | dateTimes = do.call(rbind, strsplit(x1, " "))
344 |
345 | for (i in ncol(dateTimes))
346 | dateTimes[dateTimes[, i] == "NA"] = NA
347 |
348 | # assume the time part can be found with a colon
349 | timePart = which(apply(dateTimes, MARGIN=2, FUN=function(i) { any(grepl(":", i)) } ))
350 |
351 | # everything not in the timePart should be in the datePart
352 | datePart = setdiff(seq(ncol(dateTimes)), timePart)
353 |
354 | # should have 0 or 1 timeParts and exactly one dateParts
355 | if (length(timePart) > 1 || length(datePart) != 1)
356 | stop("Error in format_date: cannot parse your time variable")
357 |
358 | timeFormat = NA
359 |
360 | if (length(timePart))
361 | {
362 | # find maximum number of colons in the timePart column
363 | ncolons = max(nchar(gsub("[^:]", "", na.omit(dateTimes[, timePart]))))
364 |
365 | if (ncolons == 1) {
366 | timeFormat = "%H:%M"
367 | } else if (ncolons == 2) {
368 | timeFormat = "%H:%M:%S"
369 | } else stop("Error in format_date: timePart should have 1 or 2 colons")
370 | }
371 |
372 | # remove all non-numeric values
373 | dates = gsub("[^0-9]", "", na.omit(dateTimes[, datePart]))
374 |
375 | # sep is any non-numeric value found, hopefully / or -
376 | sep = unique(na.omit(substr(gsub("[0-9]", "", dateTimes[, datePart]), 1, 1)))
377 | if (length(sep) > 1)
378 | stop("Error in format_date: too many seperators in datePart")
379 |
380 | # maximum number of characters found in the date part
381 | dlen = max(nchar(dates))
382 | dateFormat = NA
383 |
384 | # when six, expect the century to be omitted
385 | if (dlen == 6)
386 | {
387 | if (sum(is.na(as.Date(dates, format = "%y%m%d"))) == 0) {
388 | dateFormat = paste("%y", "%m", "%d", sep = sep)
389 | } else if (sum(is.na(as.Date(dates, format = "%d%m%y"))) == 0) {
390 | dateFormat = paste("%d", "%m", "%y", sep = sep)
391 | } else stop("Error in format_date: datePart format [six characters] is inconsistent")
392 |
393 | } else if (dlen == 8) {
394 |
395 | if (sum(is.na(as.Date(dates, format = "%Y%m%d"))) == 0) {
396 | dateFormat = paste("%Y", "%m", "%d", sep = sep)
397 | } else if (sum(is.na(as.Date(dates, format = "%d%m%Y"))) == 0) {
398 | dateFormat = paste("%d", "%m", "%Y", sep = sep)
399 | } else stop("Error in format_date: datePart format [eight characters] is inconsistent")
400 |
401 | } else {
402 |
403 | stop(sprintf("Error in format_date: datePart has unusual length: %s", dlen))
404 | }
405 |
406 | if (is.na(timeFormat))
407 | {
408 | format = dateFormat
409 | } else if (timePart == 1) {
410 | format = paste(timeFormat, dateFormat)
411 | } else if (timePart == 2) {
412 | format = paste(dateFormat, timeFormat)
413 | } else stop("Error in format_date: cannot parse your time variable")
414 |
415 | x = as.POSIXlt(x, format=format)
416 | return(format(x))
417 | }
418 |
419 |
--------------------------------------------------------------------------------
/R/renewables.ninja.solar.farms.csv:
--------------------------------------------------------------------------------
1 | name,lat,lon,from,to,dataset,capacity,system_loss,tracking,tilt,azim
2 | New York,40.7,-73.9,2014-01-01,2014-12-31,merra2,8550,0.1,0,40.7,176
3 | Los Angeles,34.0,-118.4,2014-01-01,2014-12-31,merra2,3971,0.1,0,34.0,166
4 | Chicago,41.8,-87.7,2014-01-01,2014-12-31,merra2,2720,0.1,0,41.8,226
5 | Houston,29.8,-95.4,2014-01-01,2014-12-31,merra2,2296,0.1,0,29.8,171
6 | Philadelphia,40.0,-75.1,2014-01-01,2014-12-31,merra2,1567,0.1,0,40.0,162
7 | Phoenix,33.6,-112.1,2014-01-01,2014-12-31,merra2,1563,0.1,0,33.6,204
8 | San Antonio,29.5,-98.5,2014-01-01,2014-12-31,merra2,1469,0.1,0,29.5,173
9 | San Diego,32.8,-117.1,2014-01-01,2014-12-31,merra2,1394,0.1,0,32.8,190
10 | Dallas,32.8,-96.8,2014-01-01,2014-12-31,merra2,1300,0.1,0,32.8,150
11 | San Jose,37.3,-121.8,2014-01-01,2014-12-31,merra2,1026,0.1,0,37.3,183
12 |
--------------------------------------------------------------------------------
/R/renewables.ninja.wind.farms.csv:
--------------------------------------------------------------------------------
1 | name,lat,lon,from,to,dataset,capacity,height,turbine
2 | London,51.5,0,01/01/2014,31/12/2014,merra2,150,60,Vestas+V80+2000
3 | Edinburgh,56,-3.2,01/01/2014,31/12/2014,merra2,200,40,Enercon+E66+1800
4 | Cardiff,51.5,-3.2,01/01/2014,31/12/2014,merra2,50,80,Siemens+SWT+2.3+93
5 | Belfast,54.6,-5.9,01/01/2014,31/12/2014,merra2,100,50,GE+1.5sl
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The Ninja Automator
2 |
3 | This is a multi-langugage tool to scrape data from the [Renewables.ninja](https://www.renewables.ninja/) website. It allows you to download wind and solar output data for multiple locations more easily.
4 |
5 | Currently there are implementations in Excel and R, with a Python version under development.
6 |
7 |
8 | ## Ninja Automator Excel VBA
9 |
10 | You can download the [Ninja Excel Interface here](https://github.com/renewables-ninja/ninja_automator/raw/master/Excel/Ninja%20Automator.xlsm).
11 |
12 | This provides a VBA routine to run simulations via the Renewables.ninja API and deliver results into a spreadsheet. Usage should be self explanatory, read the INFO worksheet to begin.
13 |
14 | The Excel worksheet provides an example implementation, which allows the user to choose model parameters, and download data as either hourly values, daily averages or monthly averages.
15 |
16 | Tested on [Excel](https://products.office.com/en-gb/excel) 2010, 2013 and 2016 on Windows 7 and 10.
17 |
18 | Requires VBA Macros to be enabled.
19 |
20 |
21 |
22 |
23 | ## Ninja Automator R
24 |
25 | This provides a set of worked examples that contact the renewables.ninja API, perform your simulation and return the results as a data.frame. Multiple simulations can be performed by either supplying vectors of input parameters or by reading them in from a CSV file.
26 |
27 |
28 | ### REQUIREMENTS & SETUP
29 |
30 | [R](https://www.r-project.org/) or [MRO](https://mran.revolutionanalytics.com/open/) version 3+, with the `curl` library.
31 |
32 | Download the files from the /R subfolder and you are ready to go.
33 |
34 | Inside `example.r` edit the path names and your API token.
35 |
36 |
37 | ### USAGE INSTRUCTIONS
38 |
39 | `ninja_automator.r` provides the background functions for communicating with the Renewables.ninja API. Each function requires the latitude and longitude, and optionally takes other parameters that you can pass to the API such as wind turbine model or solar panel orientation.
40 |
41 | `example.r` provides a set of five ready-made examples that walk you through running a single simulation, aggregating many simulations together, and reading inputs/output files to fully automate the ninja.
42 |
43 | The functions `ninja_get_wind(lat, lon, ...)` and `ninja_get_solar(lat, lon, ...)` run a simulation for a single wind or solar farm by passing input parameters. They will yield a 2-column dataframe containing timestamp and output. You can expect each to take around 5-10 seconds to complete, due to the time needed to contact the server, the simulation to run, etc.
44 |
45 | The functions `ninja_aggregate_wind(lat, lon, ...)` and `ninja_aggregate_solar(lat, lon, ...)` run simulations for multiple wind or solar farms by passing vectors of input data. These will yield a multi-column dataframe containing timestamp and the output of each farm as a sepearate column. You can expect the function to take around 10 seconds per farm being simulated.
46 |
47 | All the functions keep track of the number of simulations you have run, and will pause when necessary to prevent you from exceeding the hourly API limits. If you'd like it to be faster, contact us via the Renewables.ninja [forum](https://community.renewables.ninja/) or [email](https://www.renewables.ninja/about).
48 |
49 | `renewables.ninja.solar.farms.csv` and `renewables.ninja.wind.farms.csv` are example input files that can be fed into the automator to download a group of farms. `renewables.ninja.wind.output.csv` is an example of the data that will be returned by `ninja_aggregate_wind`.
50 |
51 |
52 |
53 |
54 | ## LICENSE
55 | BSD 3-Clause License
56 |
57 | Copyright (C) 2016-2018 Iain Staffell
58 |
59 | All rights reserved.
60 |
61 | See `LICENSE` for more detail.
62 |
63 |
64 |
65 | ## CREDITS & CONTACT
66 |
67 | The R automator is developed by Iain Staffell. You can try emailing me at contact@renewables.ninja.
68 |
69 | This is part of the [Renewables.ninja](https://renewables.ninja) project, developed by Stefan Pfenninger and Iain Staffell. Use the [contacts page](https://www.renewables.ninja/about) there.
70 |
71 |
72 | ### Citation
73 |
74 | I Staffell and S Pfenninger, 2016. Using bias-corrected reanalysis to simulate current and future wind power output. *Energy*, 114, 1224–1239. [doi: 10.1016/j.energy.2016.08.068](https://dx.doi.org/10.1016/j.energy.2016.08.068)
75 |
76 | S Pfenninger and I Staffell, 2016. Long-term patterns of European PV output using 30 years of validated hourly reanalysis and satellite data. Energy, 114, 1251-1265. [doi: 10.1016/j.energy.2016.08.060](https://dx.doi.org/10.1016/j.energy.2016.08.060)
77 |
--------------------------------------------------------------------------------