Skip to content
This repository has been archived by the owner on Aug 28, 2023. It is now read-only.

Commit

Permalink
Fix year filtering. Simplify queryset generator selection
Browse files Browse the repository at this point in the history
  • Loading branch information
Reed Martz committed Feb 15, 2017
1 parent bd234d3 commit ce24d26
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 23 deletions.
17 changes: 5 additions & 12 deletions django/climate_change_api/indicators/abstract_indicators.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@


from climate_data.models import ClimateData
from climate_data.filters import ClimateDataFilterSet
from .params import IndicatorParams, ThresholdIndicatorParams
from .serializers import IndicatorSerializer
from .unit_converters import DaysUnitsMixin, TemperatureConverter, PrecipitationConverter
from .query_ranges import (MonthQuerysetGenerator, QuarterQuerysetGenerator, YearQuerysetGenerator,
OffsetYearQuerysetGenerator, CustomQuerysetGenerator)
import queryset_generator


class Indicator(object):
Expand Down Expand Up @@ -108,21 +106,16 @@ def get_queryset(self):
by the constructor
"""
# Use the ranges to determine how each time aggregation should be keyed
range_config = {
'monthly': MonthQuerysetGenerator,
'quarterly': QuarterQuerysetGenerator,
'yearly': YearQuerysetGenerator,
'offset_yearly': OffsetYearQuerysetGenerator,
'custom': CustomQuerysetGenerator
}.get(self.params.time_aggregation.value)
# Get the queryset generator for this indicator's time aggregation
generator = queryset_generator.get(self.params.time_aggregation.value)
key_params = {}

# The custom range config accepts a user-defined parameter to pick which dates to use
if self.params.custom_time_agg.value is not None:
key_params['custom_time_agg'] = self.params.custom_time_agg.value

queryset = range_config.create_queryset(
# Use the queryset generator classes to construct the initial base climate data queryset
queryset = generator.create_queryset(
years=self.params.years.value,
models=self.params.models.value,
scenario=self.scenario,
Expand Down
37 changes: 26 additions & 11 deletions django/climate_change_api/indicators/queryset_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@
from climate_data.filters import ClimateDataFilterSet


def get(time_aggregation):
""" Provide the correct queryset generator class based on indicator time aggregation """
return {
'monthly': MonthQuerysetGenerator,
'quarterly': QuarterQuerysetGenerator,
'yearly': YearQuerysetGenerator,
'offset_yearly': OffsetYearQuerysetGenerator,
'custom': CustomQuerysetGenerator
}.get(time_aggregation)


class QuerysetGenerator(object):
""" Utility class to create querysets for ClimateData for a given time aggregation
Expand All @@ -16,6 +27,7 @@ class QuerysetGenerator(object):

CaseRange = namedtuple('CaseRange', ('key', 'start', 'length'))
range_config = None
filterset_kwargs = {}

@staticmethod
def get_leap_year_sets():
Expand Down Expand Up @@ -43,15 +55,16 @@ def create_queryset(cls, scenario, years=None, models=None, key_params=None):
data_source__scenario=scenario))

if years is not None or models is not None:
filterset = cls.get_filter_set()
queryset = filterset.filter_years(queryset, years)
queryset = filterset.filter_models(queryset, models)
queryset = cls.apply_filters(queryset, years, models)

return queryset

@classmethod
def get_filter_set(cls):
return ClimateDataFilterSet()
def apply_filters(cls, queryset, years, models):
filterset = ClimateDataFilterSet(**cls.filterset_kwargs)
queryset = filterset.filter_years(queryset, years)
queryset = filterset.filter_models(queryset, models)
return queryset

@classmethod
def get_interval_key(cls, index):
Expand Down Expand Up @@ -201,6 +214,7 @@ class OffsetYearQuerysetGenerator(QuerysetGenerator):
# By default place the year divide near the summer solstice to maximize the span that covers
# winter
custom_offset = 180
filterset_kwargs = {'year_col': 'offset_year'}

@classmethod
def make_ranges(cls, label):
Expand All @@ -220,10 +234,6 @@ def make_ranges(cls, label):
@classmethod
def create_queryset(cls, *args, **kwargs):
queryset = super(OffsetYearQuerysetGenerator, cls).create_queryset(*args, **kwargs)
queryset = queryset.annotate(offset_year=Case(
When(day_of_year__lt=cls.custom_offset,
then=F('data_source__year') - 1),
default=F('data_source__year')))

scenario = kwargs['scenario']
maxYear, minYear = (Scenario.objects
Expand All @@ -239,5 +249,10 @@ def create_queryset(cls, *args, **kwargs):
return queryset

@classmethod
def get_filter_set(cls):
return ClimateDataFilterSet(year_col='offset_year')
def apply_filters(cls, queryset, years, models):
queryset = queryset.annotate(offset_year=Case(
When(day_of_year__lt=cls.custom_offset,
then=F('data_source__year') - 1),
default=F('data_source__year')))

return super(OffsetYearQuerysetGenerator, cls).apply_filters(queryset, years, models)
21 changes: 21 additions & 0 deletions django/climate_change_api/indicators/tests/test_indicators.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,27 @@ class YearlyHeatingDegreeDaysTestCase(IndicatorTests, TestCase):
2003: {'avg': 58.5, 'min': 58.5, 'max': 58.5}}


class CrossYearlyHeatingDegreeDaysTestCase(IndicatorTests, TestCase):
indicator_class = indicators.HeatingDegreeDays
indicator_name = 'heating_degree_days'
time_aggregation = 'offset_yearly'
extra_params = {
'basetemp': '42.5',
'basetemp_units': 'K'
}
test_indicator_rcp85_equals = {}
test_indicator_rcp45_equals = {'2000-2001': {'avg': 49.5, 'min': 40.5, 'max': 58.5},
'2001-2002': {'avg': 58.5, 'min': 58.5, 'max': 58.5},
'2002-2003': {'avg': 58.5, 'min': 58.5, 'max': 58.5}}
# Years are filtered by the starting year, so years=2001,2002 gives data for 2001-2002
# and 2002-2003
test_years_filter_equals = {'2001-2002': {'avg': 58.5, 'min': 58.5, 'max': 58.5},
'2002-2003': {'avg': 58.5, 'min': 58.5, 'max': 58.5}}
test_models_filter_equals = {'2000-2001': {'avg': 58.5, 'min': 58.5, 'max': 58.5},
'2001-2002': {'avg': 58.5, 'min': 58.5, 'max': 58.5},
'2002-2003': {'avg': 58.5, 'min': 58.5, 'max': 58.5}}


class YearlyCoolingDegreeDaysTestCase(IndicatorTests, TestCase):
indicator_class = indicators.CoolingDegreeDays
indicator_name = 'cooling_degree_days'
Expand Down

0 comments on commit ce24d26

Please sign in to comment.