3232
3333# Dictionary mapping time steps to CAMS time step format
3434TIME_STEPS_MAP = {'1min' : 'PT01M' , '15min' : 'PT15M' , '1h' : 'PT01H' ,
35- '1d' : 'P01D' , '1M ' : 'P01M' }
35+ '1d' : 'P01D' , '1MS ' : 'P01M' }
3636
3737TIME_STEPS_IN_HOURS = {'1min' : 1 / 60 , '15min' : 15 / 60 , '1h' : 1 , '1d' : 24 }
3838
3939SUMMATION_PERIOD_TO_TIME_STEP = {'0 year 0 month 0 day 0 h 1 min 0 s' : '1min' ,
4040 '0 year 0 month 0 day 0 h 15 min 0 s' : '15min' , # noqa
4141 '0 year 0 month 0 day 1 h 0 min 0 s' : '1h' ,
4242 '0 year 0 month 1 day 0 h 0 min 0 s' : '1d' ,
43- '0 year 1 month 0 day 0 h 0 min 0 s' : '1M ' }
43+ '0 year 1 month 0 day 0 h 0 min 0 s' : '1MS ' }
4444
4545
4646def get_cams (latitude , longitude , start , end , email , identifier = 'mcclear' ,
4747 altitude = None , time_step = '1h' , time_ref = 'UT' , verbose = False ,
48- integrated = False , label = None , map_variables = True ,
48+ integrated = False , map_variables = True ,
4949 server = URL , timeout = 30 ):
5050 """Retrieve irradiance and clear-sky time series from CAMS.
5151
@@ -79,7 +79,7 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
7979 altitude: float, optional
8080 Altitude in meters. If not specified, then the altitude is determined
8181 from the NASA SRTM database
82- time_step: str, {'1min', '15min', '1h', '1d', '1M '}, default: '1h'
82+ time_step: str, {'1min', '15min', '1h', '1d', '1MS '}, default: '1h'
8383 Time step of the time series, either 1 minute, 15 minute, hourly,
8484 daily, or monthly.
8585 time_ref: str, {'UT', 'TST'}, default: 'UT'
@@ -90,9 +90,6 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
9090 integrated: boolean, default False
9191 Whether to return radiation parameters as integrated values (Wh/m^2)
9292 or as average irradiance values (W/m^2) (pvlib preferred units)
93- label : {'right', 'left'}, optional
94- Which bin edge label to label time-step with. The default is 'left' for
95- all time steps except for '1M' which has a default of 'right'.
9693 map_variables: bool, default: True
9794 When true, renames columns of the DataFrame to pvlib variable names
9895 where applicable. See variable :const:`VARIABLE_MAP`.
@@ -120,7 +117,7 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
120117 ======================== ====== =========================================
121118 **Mapped field names are returned when the map_variables argument is True**
122119 ---------------------------------------------------------------------------
123- Observation period str Beginning/end of time period
120+ Observation period str Start of time period
124121 TOA, ghi_extra float Horizontal radiation at top of atmosphere
125122 Clear sky GHI, ghi_clear float Clear sky global radiation on horizontal
126123 Clear sky BHI, bhi_clear float Clear sky beam radiation on horizontal
@@ -231,12 +228,12 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
231228 # Successful requests returns a csv data file
232229 else :
233230 fbuf = io .StringIO (res .content .decode ('utf-8' ))
234- data , metadata = parse_cams (fbuf , integrated = integrated , label = label ,
231+ data , metadata = parse_cams (fbuf , integrated = integrated ,
235232 map_variables = map_variables )
236233 return data , metadata
237234
238235
239- def parse_cams (fbuf , integrated = False , label = None , map_variables = True ):
236+ def parse_cams (fbuf , integrated = False , map_variables = True ):
240237 """
241238 Parse a file-like buffer with data in the format of a CAMS Radiation or
242239 McClear file. The CAMS solar radiation services are described in [1]_.
@@ -248,9 +245,6 @@ def parse_cams(fbuf, integrated=False, label=None, map_variables=True):
248245 integrated: boolean, default False
249246 Whether to return radiation parameters as integrated values (Wh/m^2)
250247 or as average irradiance values (W/m^2) (pvlib preferred units)
251- label : {'right', 'left'}, optional
252- Which bin edge label to label time-step with. The default is 'left' for
253- all time steps except for '1M' which has a default of 'right'.
254248 map_variables: bool, default: True
255249 When true, renames columns of the Dataframe to pvlib variable names
256250 where applicable. See variable :const:`VARIABLE_MAP`.
@@ -262,6 +256,10 @@ def parse_cams(fbuf, integrated=False, label=None, map_variables=True):
262256 metadata: dict
263257 Metadata available in the file.
264258
259+ Notes
260+ -----
261+ The index timestamps correspond to the start/left of the interval.
262+
265263 See Also
266264 --------
267265 pvlib.iotools.read_cams, pvlib.iotools.get_cams
@@ -301,26 +299,17 @@ def parse_cams(fbuf, integrated=False, label=None, map_variables=True):
301299 obs_period = data ['Observation period' ].str .split ('/' )
302300
303301 # Set index as the start observation time (left) and localize to UTC
304- if (label == 'left' ) | ((label is None ) & (time_step != '1M' )):
305- data .index = pd .to_datetime (obs_period .str [0 ], utc = True )
306- # Set index as the stop observation time (right) and localize to UTC
307- # default label for monthly data is 'right' following Pandas' convention
308- elif (label == 'right' ) | ((label is None ) & (time_step == '1M' )):
309- data .index = pd .to_datetime (obs_period .str [1 ], utc = True )
310-
311- # For time_steps '1d' and '1M', drop timezone and round to nearest midnight
312- if (time_step == '1d' ) | (time_step == '1M' ):
302+ data .index = pd .to_datetime (obs_period .str [0 ], utc = True )
303+
304+ # For time_steps '1d' and '1MS' drop timezone and round to nearest midnight
305+ if (time_step == '1d' ) | time_step .endswith ('MS' ): # noqa
313306 data .index = pd .DatetimeIndex (data .index .date )
314- # For monthly data with 'right' label, the index should be the last
315- # date of the month and not the first date of the following month
316- if (time_step == '1M' ) & (label != 'left' ):
317- data .index = data .index - pd .Timedelta (days = 1 )
318307
319308 if not integrated : # Convert radiation values from Wh/m2 to W/m2
320309 integrated_cols = [c for c in CAMS_INTEGRATED_COLUMNS
321310 if c in data .columns ]
322311
323- if time_step == '1M' :
312+ if time_step . endswith ( 'MS' ) :
324313 time_delta = (pd .to_datetime (obs_period .str [1 ])
325314 - pd .to_datetime (obs_period .str [0 ]))
326315 hours = time_delta .dt .total_seconds ()/ 60 / 60
@@ -336,7 +325,7 @@ def parse_cams(fbuf, integrated=False, label=None, map_variables=True):
336325 return data , metadata
337326
338327
339- def read_cams (filename , integrated = False , label = None , map_variables = True ):
328+ def read_cams (filename , integrated = False , map_variables = True ):
340329 """
341330 Read a CAMS Radiation or McClear file into a pandas DataFrame.
342331
@@ -349,9 +338,6 @@ def read_cams(filename, integrated=False, label=None, map_variables=True):
349338 integrated: boolean, default False
350339 Whether to return radiation parameters as integrated values (Wh/m^2)
351340 or as average irradiance values (W/m^2) (pvlib preferred units)
352- label : {'right', 'left}, optional
353- Which bin edge label to label time-step with. The default is 'left' for
354- all time steps except for '1M' which has a default of 'right'.
355341 map_variables: bool, default: True
356342 When true, renames columns of the Dataframe to pvlib variable names
357343 where applicable. See variable :const:`VARIABLE_MAP`.
@@ -368,11 +354,15 @@ def read_cams(filename, integrated=False, label=None, map_variables=True):
368354 --------
369355 pvlib.iotools.parse_cams, pvlib.iotools.get_cams
370356
357+ Notes
358+ -----
359+ The index timestamps correspond to the start/left of the interval.
360+
371361 References
372362 ----------
373363 .. [1] `CAMS solar radiation documentation
374364 <https://atmosphere.copernicus.eu/solar-radiation>`_
375365 """
376366 with open (str (filename ), 'r' ) as fbuf :
377- content = parse_cams (fbuf , integrated , label , map_variables )
367+ content = parse_cams (fbuf , integrated , map_variables )
378368 return content
0 commit comments