py-ewr 2.2.3__tar.gz → 2.2.5__tar.gz

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.
Files changed (32) hide show
  1. {py_ewr-2.2.3 → py_ewr-2.2.5}/PKG-INFO +4 -4
  2. {py_ewr-2.2.3 → py_ewr-2.2.5}/README.md +3 -3
  3. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/data_inputs.py +24 -0
  4. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/evaluate_EWRs.py +39 -15
  5. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/observed_handling.py +8 -9
  6. py_ewr-2.2.5/py_ewr/parameter_metadata/ewr2obj.csv +40590 -0
  7. py_ewr-2.2.5/py_ewr/parameter_metadata/obj2target.csv +8962 -0
  8. py_ewr-2.2.5/py_ewr/parameter_metadata/obj2yrtarget.csv +106 -0
  9. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/scenario_handling.py +36 -2
  10. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/summarise_results.py +38 -3
  11. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr.egg-info/PKG-INFO +4 -4
  12. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr.egg-info/SOURCES.txt +3 -0
  13. {py_ewr-2.2.3 → py_ewr-2.2.5}/setup.py +1 -1
  14. {py_ewr-2.2.3 → py_ewr-2.2.5}/tests/test_evaluate_ewr_rest.py +1287 -204
  15. {py_ewr-2.2.3 → py_ewr-2.2.5}/tests/test_evaluate_ewrs.py +22 -22
  16. {py_ewr-2.2.3 → py_ewr-2.2.5}/tests/test_observed_handling.py +1 -1
  17. {py_ewr-2.2.3 → py_ewr-2.2.5}/tests/test_scenario_handling.py +35 -1
  18. {py_ewr-2.2.3 → py_ewr-2.2.5}/LICENSE +0 -0
  19. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/__init__.py +0 -0
  20. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/io.py +0 -0
  21. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/model_metadata/SiteID_MDBA.csv +0 -0
  22. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/model_metadata/SiteID_NSW.csv +0 -0
  23. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/model_metadata/iqqm_stations.csv +0 -0
  24. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/parameter_metadata/ewr_calc_config.json +0 -0
  25. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr/parameter_metadata/parameter_sheet.csv +0 -0
  26. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr.egg-info/dependency_links.txt +0 -0
  27. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr.egg-info/requires.txt +0 -0
  28. {py_ewr-2.2.3 → py_ewr-2.2.5}/py_ewr.egg-info/top_level.txt +0 -0
  29. {py_ewr-2.2.3 → py_ewr-2.2.5}/pyproject.toml +0 -0
  30. {py_ewr-2.2.3 → py_ewr-2.2.5}/setup.cfg +0 -0
  31. {py_ewr-2.2.3 → py_ewr-2.2.5}/tests/test_data_inputs.py +0 -0
  32. {py_ewr-2.2.3 → py_ewr-2.2.5}/tests/test_summarise_results.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py_ewr
3
- Version: 2.2.3
3
+ Version: 2.2.5
4
4
  Summary: Environmental Water Requirement calculator
5
5
  Home-page: https://github.com/MDBAuth/EWR_tool
6
6
  Author: Martin Job
@@ -34,14 +34,14 @@ Requires-Dist: numpy<2
34
34
  [![PyPI](https://img.shields.io/pypi/v/py-ewr)](https://pypi.org/project/py-ewr/)
35
35
  [![DOI](https://zenodo.org/badge/342122359.svg)](https://zenodo.org/badge/latestdoi/342122359)
36
36
 
37
- ### **EWR tool version 2.2.3 README**
37
+ ### **EWR tool version 2.2.5 README**
38
38
 
39
- ### **Notes on recent version update**
39
+ ### **Notes on recent version updates**
40
+ - ten thousand year handling - this has been brought back online.
40
41
  - Remove TQDM loading bars
41
42
  - Handle duplicate sites in MDBA siteID file - where a duplicate exists, the first match is used and the rest are skipped over
42
43
  - Adding new model format handling - 'IQQM - netcdf'
43
44
  - Standard time-series handling added - each column needs a gauge, followed by and underscore, followed by either flow or level (e.g. 409025_flow). This handling also has missing date filling - so any missing dates will be filled with NaN values in all columns.
44
- - ten thousand year handling - This has been briefly taken offline for this version.
45
45
  - bug fixes: spells of length equal to the minimum required spell length were getting filtered out of the successful events table and successful interevents table, fixed misclassification of some gauges to flow, level, and lake level categories
46
46
  - New EWRs: New Qld EWRs - SF_FD and BF_FD used to look into the FD EWRs in closer detail.
47
47
 
@@ -3,14 +3,14 @@
3
3
  [![PyPI](https://img.shields.io/pypi/v/py-ewr)](https://pypi.org/project/py-ewr/)
4
4
  [![DOI](https://zenodo.org/badge/342122359.svg)](https://zenodo.org/badge/latestdoi/342122359)
5
5
 
6
- ### **EWR tool version 2.2.3 README**
6
+ ### **EWR tool version 2.2.5 README**
7
7
 
8
- ### **Notes on recent version update**
8
+ ### **Notes on recent version updates**
9
+ - ten thousand year handling - this has been brought back online.
9
10
  - Remove TQDM loading bars
10
11
  - Handle duplicate sites in MDBA siteID file - where a duplicate exists, the first match is used and the rest are skipped over
11
12
  - Adding new model format handling - 'IQQM - netcdf'
12
13
  - Standard time-series handling added - each column needs a gauge, followed by and underscore, followed by either flow or level (e.g. 409025_flow). This handling also has missing date filling - so any missing dates will be filled with NaN values in all columns.
13
- - ten thousand year handling - This has been briefly taken offline for this version.
14
14
  - bug fixes: spells of length equal to the minimum required spell length were getting filtered out of the successful events table and successful interevents table, fixed misclassification of some gauges to flow, level, and lake level categories
15
15
  - New EWRs: New Qld EWRs - SF_FD and BF_FD used to look into the FD EWRs in closer detail.
16
16
 
@@ -416,3 +416,27 @@ def get_scenario_gauges(gauge_results: dict) -> list:
416
416
  for gauge in scenario.keys():
417
417
  scenario_gauges.append(gauge)
418
418
  return list(set(scenario_gauges))
419
+
420
+
421
+ def gauge_groups(parameter_sheet: pd.DataFrame) -> dict:
422
+ '''
423
+ Returns a dictionary of flow, level, and lake level gauges based on the parameter sheet and some hard coding of other EWRs
424
+
425
+ Args:
426
+ parameter_sheet (pd.DataFrame): input parameter sheet
427
+
428
+ Returns:
429
+ dict: keys as flow, level, and lake level gauges, values as the list of gauges
430
+ '''
431
+
432
+ # Hard coded gauges for the CLLMM EWRs
433
+ hard_code_levels = ['A4260527', 'A4260524', 'A4260633', 'A4261209', 'A4261165']
434
+ hard_code_lake_levels = ['A4261133', 'A4260574', 'A4260575']
435
+
436
+ flow_gauges = set(parameter_sheet[parameter_sheet['GaugeType'] == 'F']['Gauge']) + set(parameter_sheet['Multigauge'])
437
+ level_gauges = set(parameter_sheet[parameter_sheet['GaugeType'] == 'L']['Gauge']) + set(parameter_sheet['WeirpoolGauge']) + set(hard_code_levels)
438
+ lake_level_gauges = set(parameter_sheet[parameter_sheet['GaugeType'] == 'LL']['Gauge'])+set(hard_code_lake_levels)
439
+
440
+ return flow_gauges, level_gauges, lake_level_gauges
441
+
442
+ # def gauges_to_measurand()
@@ -446,9 +446,18 @@ def get_index_date(date_index:Any)-> datetime.date:
446
446
  if type(date_index) == pd._libs.tslibs.timestamps.Timestamp:
447
447
  return date_index.date()
448
448
  if type(date_index) == pd._libs.tslibs.period.Period:
449
- return date_index.to_timestamp().date()
450
- else:
449
+ date_index_str = date_index.strftime('%Y-%m-%d')
450
+ # For dates between the years 100 and 999 we need to add a 0 onto the date string so strptime doesnt break
451
+ if ((int(date_index_str.split('-')[0]) >= 100) and (int(date_index_str.split('-')[0]) < 1000)):
452
+ date_index_str = '0' + date_index_str
453
+ n = datetime.datetime.strptime(date_index_str, '%Y-%m-%d').date()
454
+ return n
455
+ if type(date_index) == str:
456
+ n = datetime.datetime.strptime(date_index, '%Y-%m-%d').date()
457
+ return n
458
+ if type(date_index) == datetime.date:
451
459
  return date_index
460
+ # return date_index #TODO: should this break? i.e. we arent expecting other date formats
452
461
 
453
462
  #----------------------------------- EWR handling functions --------------------------------------#
454
463
 
@@ -1958,7 +1967,8 @@ def water_stability_check(EWR_info:Dict, iteration:int, flows:List, all_events:D
1958
1967
  if levels_are_stable:
1959
1968
  # record event opportunity for the next n days for the total period of (EggDaysSpell)+ larvae (LarvaeDaysSpell)
1960
1969
  # if the last day of the event is not over the last day of the event window
1961
- iteration_date = flow_date.to_timestamp().date()
1970
+ iteration_date = get_index_date(flow_date)
1971
+ # iteration_date = flow_date.date()#flow_date.to_timestamp().date()
1962
1972
  last_day_window = get_last_day_of_window(iteration_date, EWR_info['end_month'])
1963
1973
  event_size = EWR_info['eggs_days_spell'] + EWR_info['larvae_days_spell']
1964
1974
  if is_date_in_window(iteration_date, last_day_window, event_size):
@@ -1995,7 +2005,8 @@ def water_stability_level_check(EWR_info:Dict, iteration:int, all_events:Dict, w
1995
2005
  if levels_are_stable:
1996
2006
  # record event opportunity for the next n days for the total period of (EggDaysSpell)+ larvae (LarvaeDaysSpell)
1997
2007
  # if the last day of the event is not over the last day of the event window
1998
- iteration_date = flow_date.to_timestamp().date()
2008
+ iteration_date = get_index_date(flow_date)
2009
+ # iteration_date = flow_date.date()#flow_date.to_timestamp().date()
1999
2010
  last_day_window = get_last_day_of_window(iteration_date, EWR_info['end_month'])
2000
2011
  event_size = EWR_info['eggs_days_spell'] + EWR_info['larvae_days_spell']
2001
2012
  if is_date_in_window(iteration_date, last_day_window, event_size):
@@ -2604,7 +2615,7 @@ def lower_lakes_level_check(EWR_info: dict, levels: pd.Series, event: list, all_
2604
2615
  #------------------------------------ Calculation functions --------------------------------------#
2605
2616
 
2606
2617
 
2607
- def create_water_stability_event(flow_date: pd.Period, flows:List, iteration: int, EWR_info:dict)->List:
2618
+ def create_water_stability_event(flow_date: pd.Timestamp, flows:List, iteration: int, EWR_info:dict)->List:#pd.Period
2608
2619
  """create overlapping event that meets an achievement for fish recruitment water stability
2609
2620
 
2610
2621
  Args:
@@ -2617,7 +2628,8 @@ def create_water_stability_event(flow_date: pd.Period, flows:List, iteration: in
2617
2628
  """
2618
2629
  event_size = EWR_info['eggs_days_spell'] + EWR_info['larvae_days_spell']
2619
2630
  event_flows = flows[iteration: iteration + event_size]
2620
- start_event_date = flow_date.to_timestamp().date()
2631
+ start_event_date = get_index_date(flow_date)
2632
+ # start_event_date = flow_date.date()#flow_date.to_timestamp().date()
2621
2633
  event_dates = [ start_event_date + timedelta(i) for i in range(event_size)]
2622
2634
 
2623
2635
  return [(d, flow) for d, flow in zip(event_dates, event_flows)]
@@ -3800,6 +3812,7 @@ def nest_calc_percent_trigger(EWR_info:Dict, flows:List, water_years:List, dates
3800
3812
  Returns:
3801
3813
  tuple: final output with the calculation of volume all_events, durations
3802
3814
  """
3815
+ #TODO can we clean up the flow_date and iteration_date parts
3803
3816
  event = []
3804
3817
  total_event = 0
3805
3818
  all_events = construct_event_dict(water_years)
@@ -3807,19 +3820,25 @@ def nest_calc_percent_trigger(EWR_info:Dict, flows:List, water_years:List, dates
3807
3820
  gap_track = 0
3808
3821
  for i, flow in enumerate(flows[:-1]):
3809
3822
  flow_date = dates[i]
3823
+ iteration_date = get_index_date(flow_date)
3810
3824
  flow_percent_change = calc_flow_percent_change(i, flows)
3811
3825
  trigger_day = date(dates[i].year,EWR_info["trigger_month"], EWR_info["trigger_day"])
3812
3826
  cut_date = calc_nest_cut_date(EWR_info, i, dates)
3813
- is_in_trigger_window = dates[i].to_timestamp().date() >= trigger_day \
3814
- and dates[i].to_timestamp().date() <= trigger_day + timedelta(days=14)
3827
+ is_in_trigger_window = iteration_date >= trigger_day \
3828
+ and iteration_date <= trigger_day + timedelta(days=14) #.to_timestamp() .to_timestamp()
3829
+ # is_in_trigger_window = dates[i].date() >= trigger_day \
3830
+ # and dates[i].date() <= trigger_day + timedelta(days=14) #.to_timestamp() .to_timestamp()
3815
3831
  iteration_no_event = 0
3816
3832
 
3817
3833
  ## if there IS an ongoing event check if we are on the trigger season window
3818
3834
  # if yes then check the current flow
3819
3835
  if total_event > 0:
3820
- if (dates[i].to_timestamp().date() >= trigger_day) and (dates[i].to_timestamp().date() <= cut_date):
3836
+ if (iteration_date >= trigger_day) and (iteration_date <= cut_date):
3821
3837
  event, all_events, gap_track, total_event, iteration_no_event = nest_flow_check(EWR_info, i, flow, event, all_events,
3822
- gap_track, water_years, total_event, flow_date, flow_percent_change, iteration_no_event)
3838
+ gap_track, water_years, total_event, flow_date, flow_percent_change, iteration_no_event) #.to_timestamp() .to_timestamp()
3839
+ # if (dates[i].date() >= trigger_day) and (dates[i].date() <= cut_date):
3840
+ # event, all_events, gap_track, total_event, iteration_no_event = nest_flow_check(EWR_info, i, flow, event, all_events,
3841
+ # gap_track, water_years, total_event, flow_date, flow_percent_change, iteration_no_event) #.to_timestamp() .to_timestamp()
3823
3842
 
3824
3843
  # this path will only be executed if an event extends beyond the cut date
3825
3844
  else:
@@ -3840,18 +3859,23 @@ def nest_calc_percent_trigger(EWR_info:Dict, flows:List, water_years:List, dates
3840
3859
 
3841
3860
  # Check final iteration in the flow timeseries, saving any ongoing events/event gaps to their spots in the dictionaries:
3842
3861
  # reset all variable to last flow
3843
- flow_date = dates[-1].to_timestamp().date()
3862
+
3863
+ # flow_date = dates[-1].date()#.to_timestamp()
3864
+ flow_date = dates[-1]
3865
+ iteration_date = get_index_date(dates[-1])
3844
3866
  flow_percent_change = calc_flow_percent_change(-1, flows)
3845
3867
  trigger_day = date(dates[-1].year,EWR_info["trigger_month"], EWR_info["trigger_day"])
3846
3868
  cut_date = calc_nest_cut_date(EWR_info, -1, dates)
3847
- is_in_trigger_window = dates[-1].to_timestamp().date() >= trigger_day - timedelta(days=7) \
3848
- and dates[-1].to_timestamp().date() <= trigger_day + timedelta(days=7)
3869
+ is_in_trigger_window = iteration_date >= trigger_day - timedelta(days=7) \
3870
+ and iteration_date <= trigger_day + timedelta(days=7) #.to_timestamp() .to_timestamp()
3871
+ # is_in_trigger_window = dates[-1].date() >= trigger_day - timedelta(days=7) \
3872
+ # and dates[-1].date() <= trigger_day + timedelta(days=7) #.to_timestamp() .to_timestamp()
3849
3873
  iteration_no_event = 0
3850
3874
 
3851
3875
  if total_event > 0:
3852
3876
 
3853
- if (flow_date >= trigger_day ) \
3854
- and (flow_date <= cut_date):
3877
+ if (iteration_date >= trigger_day ) \
3878
+ and (iteration_date <= cut_date): # Was flow_date instead of iteration date in both instances
3855
3879
  event, all_events, gap_track, total_event, iteration_no_event = nest_flow_check(EWR_info, -1, flows[-1], event, all_events,
3856
3880
  gap_track, water_years, total_event, flow_date, flow_percent_change, iteration_no_event)
3857
3881
 
@@ -35,7 +35,6 @@ def categorise_gauges(gauges: list, ewr_table_path:str = None) -> tuple:
35
35
  if gauge in gauges:
36
36
  level_gauges.append(gauge)
37
37
  lake_level_gauges_to_add = EWR_TABLE[EWR_TABLE['GaugeType']=='LL']['Gauge'].to_list()
38
- # print(lake_level_gauges_to_add)
39
38
  for gauge in lake_level_gauges_to_add:
40
39
  if gauge in gauges:
41
40
  lake_level_gauges.append(gauge)
@@ -130,7 +129,7 @@ def observed_cleaner(input_df: pd.DataFrame, dates: dict) -> pd.DataFrame:
130
129
  start_date = datetime(dates['start_date'].year, dates['start_date'].month, dates['start_date'].day)
131
130
  end_date = datetime(dates['end_date'].year, dates['end_date'].month, dates['end_date'].day)
132
131
 
133
- df_index = pd.date_range(start=start_date,end=end_date - timedelta(days=1)).to_period()
132
+ df_index = pd.date_range(start=start_date,end=end_date - timedelta(days=1))#.to_period()
134
133
  gauge_data_df = pd.DataFrame()
135
134
  gauge_data_df['Date'] = df_index
136
135
  gauge_data_df = gauge_data_df.set_index('Date')
@@ -139,7 +138,7 @@ def observed_cleaner(input_df: pd.DataFrame, dates: dict) -> pd.DataFrame:
139
138
 
140
139
 
141
140
  input_df['Date'] = pd.to_datetime(input_df['DATETIME'], format = '%Y-%m-%d')
142
- input_df['Date'] = input_df['Date'].apply(lambda x: x.to_period(freq='D'))
141
+ # input_df['Date'] = input_df['Date'].apply(lambda x: x.to_period(freq='D'))
143
142
 
144
143
  # Check with states for more codes:
145
144
  bad_data_codes = data_inputs.get_bad_QA_codes()
@@ -178,12 +177,12 @@ class ObservedHandler:
178
177
 
179
178
  # Classify gauges:
180
179
  flow_gauges, level_gauges, lake_level_gauges = categorise_gauges(self.gauges, self.parameter_sheet)
181
- print('flow gauges')
182
- print(flow_gauges)
183
- print('level gauges')
184
- print(level_gauges)
185
- print('lake level gauges')
186
- print(lake_level_gauges)
180
+ # print('flow gauges')
181
+ # print(flow_gauges)
182
+ # print('level gauges')
183
+ # print(level_gauges)
184
+ # print('lake level gauges')
185
+ # print(lake_level_gauges)
187
186
  # Call state API for flow and level gauge data, then combine to single dataframe
188
187
  log.info(f'Including gauges: flow gauges: { ", ".join(flow_gauges)} level gauges: { ", ".join(level_gauges)} lake level gauges: { ", ".join(lake_level_gauges)}')
189
188