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

Degree Day unit tests #160

Merged
merged 2 commits into from
Dec 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions django/climate_change_api/indicators/abstract_indicators.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from datetime import date, timedelta
import calendar

from django.db.models import F, Case, When, CharField, IntegerField, Value, Sum
from django.db.models import F, Case, When, CharField, FloatField, Value, Sum
from django.db import connection


Expand Down Expand Up @@ -48,7 +48,9 @@ def __init__(self, city, scenario, models=None, years=None,
if self.units not in self.available_units:
raise ValueError('Cannot convert to requested units ({})'.format(self.units))

if self.parameters is not None and parameters is not None:
if self.parameters is not None:
# Because degree days changes the parameters object, we need to make sure we make a copy
parameters = parameters if parameters is not None else {}
self.parameters = {key: parameters.get(key, default)
for (key, default) in self.parameters.items()}

Expand Down Expand Up @@ -182,7 +184,7 @@ def aggregate(self):
agg_function = self.agg_function(
Case(When(then=self.expression, **self.conditions),
default=self.default,
output_field=IntegerField()))
output_field=FloatField()))
else:
agg_function = self.agg_function(self.expression)

Expand Down Expand Up @@ -377,7 +379,7 @@ def aggregate(self):
agg_function = self.agg_function(
Case(When(then=self.expression, **self.conditions),
default=self.default,
output_field=IntegerField()))
output_field=FloatField()))
else:
agg_function = self.agg_function(self.expression)

Expand Down Expand Up @@ -406,9 +408,16 @@ class MonthlyCountIndicator(MonthlyAggregationIndicator):
class BasetempIndicatorMixin(object):
""" Framework for pre-processing the basetemp parameter to a native unit
"""
def calculate(self):
m = re.match(r'(?P<value>\d+(\.\d+)?)(?P<unit>[FKC])?', self.parameters['basetemp'])
assert m, "Parameter basetemp must be numeric"

def __init__(self, *args, **kwargs):
super(BasetempIndicatorMixin, self).__init__(*args, **kwargs)

available_units = TemperatureConverter.available_units
m = re.match(r'^(?P<value>-?\d+(\.\d+)?)(?P<unit>%s)?$' % '|'.join(available_units),
self.parameters['basetemp'])
if not m:
raise ValueError('Parameter basetemp must be numeric and optionally end with %s'
% str(available_units))

value = float(m.group('value'))
unit = m.group('unit')
Expand All @@ -418,5 +427,3 @@ def calculate(self):
converter = TemperatureConverter.get(unit, self.storage_units)
self.parameters['basetemp'] = converter(value)
self.parameters['units'] = self.storage_units

return super(BasetempIndicatorMixin, self).calculate()
106 changes: 100 additions & 6 deletions django/climate_change_api/indicators/tests/test_indicators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
class IndicatorTests(ClimateDataSetupMixin, object):

indicator_class = None # Override this in subclass to set the indicator to test
parameters = None
indicator_name = ''
units = None
test_indicator_no_data_equals = {}
Expand All @@ -24,28 +25,32 @@ def test_indicator_description(self):
self.assertTrue(len(self.indicator_class.description) > 0)

def test_indicator_rcp85(self):
indicator = self.indicator_class(self.city1, self.rcp85, units=self.units)
indicator = self.indicator_class(self.city1, self.rcp85, units=self.units,
parameters=self.parameters)
data = indicator.calculate()
self.assertEqual(data, self.test_indicator_rcp85_equals)

def test_indicator_rcp45(self):
indicator = self.indicator_class(self.city1, self.rcp45, units=self.units)
indicator = self.indicator_class(self.city1, self.rcp45, units=self.units,
parameters=self.parameters)
data = indicator.calculate()
self.assertEqual(data, self.test_indicator_rcp45_equals)

def test_indicator_no_data(self):
indicator = self.indicator_class(self.city2, self.rcp85, units=self.units)
indicator = self.indicator_class(self.city2, self.rcp85, units=self.units,
parameters=self.parameters)
data = indicator.calculate()
self.assertEqual(data, self.test_indicator_no_data_equals)

def test_years_filter(self):
indicator = self.indicator_class(self.city1, self.rcp45,
units=self.units, years='2001:2002')
indicator = self.indicator_class(self.city1, self.rcp45, units=self.units,
years='2001:2002', parameters=self.parameters)
data = indicator.calculate()
self.assertEqual(data, self.test_years_filter_equals)

def test_models_filter(self):
indicator = self.indicator_class(self.city1, self.rcp45, units=self.units, models='CCSM4')
indicator = self.indicator_class(self.city1, self.rcp45, units=self.units, models='CCSM4',
parameters=self.parameters)
data = indicator.calculate()
self.assertEqual(data, self.test_models_filter_equals)

Expand Down Expand Up @@ -261,6 +266,54 @@ class YearlyExtremeColdEventsTestCase(IndicatorTests, TestCase):
2003: {'avg': 1.0, 'min': 1, 'max': 1}}


class YearlyHeatingDegreeDaysTestCase(IndicatorTests, TestCase):
indicator_class = indicators.YearlyHeatingDegreeDays
indicator_name = 'yearly_heating_degree_days'
parameters = {
'basetemp': '42.5K'
}
test_indicator_rcp85_equals = {2000: {'avg': 13.5, 'min': 4.5, 'max': 22.5}}
test_indicator_rcp45_equals = {2000: {'avg': 49.5, 'min': 40.5, 'max': 58.5},
2001: {'avg': 49.5, 'min': 40.5, 'max': 58.5},
2002: {'avg': 58.5, 'min': 58.5, 'max': 58.5},
2003: {'avg': 58.5, 'min': 58.5, 'max': 58.5}}
test_years_filter_equals = {2001: {'avg': 49.5, 'min': 40.5, 'max': 58.5},
2002: {'avg': 58.5, 'min': 58.5, 'max': 58.5}}
test_models_filter_equals = {2000: {'avg': 58.5, 'min': 58.5, 'max': 58.5},
2001: {'avg': 58.5, 'min': 58.5, 'max': 58.5},
2002: {'avg': 58.5, 'min': 58.5, 'max': 58.5},
2003: {'avg': 58.5, 'min': 58.5, 'max': 58.5}}


class YearlyCoolingDegreeDaysTestCase(IndicatorTests, TestCase):
indicator_class = indicators.YearlyCoolingDegreeDays
indicator_name = 'yearly_cooling_degree_days'
parameters = {
'basetemp': '-265.85C' # 7.3K
}
test_indicator_rcp85_equals = {2000: {'avg': 49.86, 'min': 40.86, 'max': 58.86000000000001}}
test_indicator_rcp45_equals = {2000: {'avg': 13.860000000000046, 'min': 4.86000000000009,
'max': 22.86},
2001: {'avg': 13.860000000000046, 'min': 4.86000000000009,
'max': 22.86},
2002: {'avg': 4.86000000000009, 'min': 4.86000000000009,
'max': 4.86000000000009},
2003: {'avg': 4.86000000000009, 'min': 4.86000000000009,
'max': 4.86000000000009}}
test_years_filter_equals = {2001: {'avg': 13.860000000000046, 'min': 4.86000000000009,
'max': 22.86},
2002: {'avg': 4.86000000000009, 'min': 4.86000000000009,
'max': 4.86000000000009}}
test_models_filter_equals = {2000: {'avg': 4.86000000000009, 'min': 4.86000000000009,
'max': 4.86000000000009},
2001: {'avg': 4.86000000000009, 'min': 4.86000000000009,
'max': 4.86000000000009},
2002: {'avg': 4.86000000000009, 'min': 4.86000000000009,
'max': 4.86000000000009},
2003: {'avg': 4.86000000000009, 'min': 4.86000000000009,
'max': 4.86000000000009}}


class MonthlyAverageHighTemperatureTestCase(TemperatureIndicatorTests, TestCase):
indicator_class = indicators.MonthlyAverageHighTemperature
indicator_name = 'monthly_average_high_temperature'
Expand Down Expand Up @@ -412,3 +465,44 @@ class MonthlyExtremeColdEventsTestCase(IndicatorTests, TestCase):
'2001-01': {'avg': 1.0, 'min': 1, 'max': 1},
'2002-01': {'avg': 1.0, 'min': 1, 'max': 1},
'2003-01': {'avg': 1.0, 'min': 1, 'max': 1}}


class MonthlyHeatingDegreeDaysTestCase(IndicatorTests, TestCase):
indicator_class = indicators.MonthlyHeatingDegreeDays
indicator_name = 'monthly_heating_degree_days'
parameters = {
'basetemp': '-384.07',
'units': 'F'
}
test_indicator_rcp85_equals = {'2000-01': {'avg': 12.60000000000001,
'min': 3.6000000000000183, 'max': 21.6}}
test_indicator_rcp45_equals = {'2000-01': {'avg': 48.6, 'min': 39.6, 'max': 57.6},
'2001-01': {'avg': 48.6, 'min': 39.6, 'max': 57.6},
'2002-01': {'avg': 57.6, 'min': 57.6, 'max': 57.6},
'2003-01': {'avg': 57.6, 'min': 57.6, 'max': 57.6}}
test_years_filter_equals = {'2001-01': {'avg': 48.6, 'min': 39.6, 'max': 57.6},
'2002-01': {'avg': 57.6, 'min': 57.6, 'max': 57.6}}
test_models_filter_equals = {'2000-01': {'avg': 57.6, 'min': 57.6, 'max': 57.6},
'2001-01': {'avg': 57.6, 'min': 57.6, 'max': 57.6},
'2002-01': {'avg': 57.6, 'min': 57.6, 'max': 57.6},
'2003-01': {'avg': 57.6, 'min': 57.6, 'max': 57.6}}


class MonthlyCoolingDegreeDaysTestCase(IndicatorTests, TestCase):
indicator_class = indicators.MonthlyCoolingDegreeDays
indicator_name = 'monthly_cooling_degree_days'
parameters = {
'basetemp': '-273.15',
'units': 'C'
}
test_indicator_rcp85_equals = {'2000-01': {'avg': 63.0, 'min': 54.0, 'max': 72.0}}
test_indicator_rcp45_equals = {'2000-01': {'avg': 27.0, 'min': 18.0, 'max': 36.0},
'2001-01': {'avg': 27.0, 'min': 18.0, 'max': 36.0},
'2002-01': {'avg': 18.0, 'min': 18.0, 'max': 18.0},
'2003-01': {'avg': 18.0, 'min': 18.0, 'max': 18.0}}
test_years_filter_equals = {'2001-01': {'avg': 27.0, 'min': 18.0, 'max': 36.0},
'2002-01': {'avg': 18.0, 'min': 18.0, 'max': 18.0}}
test_models_filter_equals = {'2000-01': {'avg': 18.0, 'min': 18.0, 'max': 18.0},
'2001-01': {'avg': 18.0, 'min': 18.0, 'max': 18.0},
'2002-01': {'avg': 18.0, 'min': 18.0, 'max': 18.0},
'2003-01': {'avg': 18.0, 'min': 18.0, 'max': 18.0}}
6 changes: 5 additions & 1 deletion django/climate_change_api/indicators/unit_converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ def get(cls, start, end):
# Create a lamdba for converting these specific units
return cls.create(start, end)

@classproperty
def available_units(cls):
return cls.units.keys()


class LinearConverter(UnitConverter):
@classmethod
Expand Down Expand Up @@ -104,7 +108,7 @@ def getConverter(self, start, end):

@classproperty
def available_units(cls):
return cls.converter_class.units.keys()
return cls.converter_class.available_units


class TemperatureUnitsMixin(ConversionMixin):
Expand Down