# documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # -- Project information ----------------------------------------------------- from eemeter import get_version project = "eemeter" copyright = "2016-2018, Open Energy Efficiency, Inc." author = "Phil Ngo" # The short X.Y version version = get_version() # The full version, including alpha/beta/rc tags release = version # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ "sphinx.ext.autodoc", "sphinx.ext.intersphinx",
def evaluate(self, meter_input, formatter=None, model=None, weather_source=None, weather_normal_source=None): ''' Main entry point to the meter, which models traces and calculates derivatives. Parameters ---------- meter_input : dict Serialized input containing trace and project data. formatter : tuple of (class, dict), default None Formatter for trace and weather data. Used to create input for model. If None is provided, will be auto-matched to appropriate default formatter. Class name can be provided as a string (class.__name__) or object. model : tuple of (class, dict), default None Model to use in modeling. If None is provided, will be auto-matched to appropriate default model. Class can be provided as a string (class.__name__) or class object. weather_source : eemeter.weather.WeatherSource Weather source to be used for this meter. Overrides weather source found using :code:`project.site`. Useful for test mocking. weather_normal_source : eemeter.weather.WeatherSource Weather normal source to be used for this meter. Overrides weather source found using :code:`project.site`. Useful for test mocking. Returns ------- results : dict Dictionary of results with the following keys: - :code:`"status"`: SUCCESS/FAILURE - :code:`"failure_message"`: if FAILURE, message indicates reason for failure, may include traceback - :code:`"logs"`: list of collected log messages - :code:`"model_class"`: Name of model class - :code:`"model_kwargs"`: dict of model keyword arguments (settings) - :code:`"formatter_class"`: Name of formatter class - :code:`"formatter_kwargs"`: dict of formatter keyword arguments (settings) - :code:`"eemeter_version"`: version of the eemeter package - :code:`"modeled_energy_trace"`: modeled energy trace - :code:`"derivatives"`: derivatives for each interpretation - :code:`"weather_source_station"`: Matched weather source station. - :code:`"weather_normal_source_station"`: Matched weather normal source station. ''' SUCCESS = "SUCCESS" FAILURE = "FAILURE" output = OrderedDict([ ("status", None), ("failure_message", None), ("logs", []), ("eemeter_version", get_version()), ("trace_id", None), ("project_id", None), ("interval", None), ("meter_kwargs", self.kwargs), ("model_class", None), ("model_kwargs", None), ("formatter_class", None), ("formatter_kwargs", None), ("weather_source_station", None), ("weather_normal_source_station", None), ("derivatives", None), ("modeled_energy_trace", None), ]) # Step 1: Deserialize input and validate deserialized_input = deserialize_meter_input(meter_input) if "error" in deserialized_input: message = ("Meter input could not be deserialized:\n{}".format( deserialized_input)) output['status'] = FAILURE output['failure_message'] = message return output # Assume that deserialized input fails without these keys, so don't # bother error checking trace = deserialized_input["trace"] project = deserialized_input["project"] zipcode = project["zipcode"] site = ZIPCodeSite(zipcode) # Can be blank for models capable of structural change analysis, so # provide default modeling_period_set = project.get("modeling_period_set", None) project_id = project["project_id"] trace_id = trace.trace_id interval = trace.interval output['project_id'] = project_id output['trace_id'] = trace_id output['interval'] = interval logger.debug('Running meter for for trace {} and project {}'.format( project_id, trace_id)) # Step 2: Match weather use_cz2010 = (self.weather_station_mapping == 'CZ2010') if weather_source is None: weather_source = get_weather_source(site, use_cz2010=use_cz2010) if weather_source is None: message = ( "Could not find weather normal source matching site {}". format(site)) weather_source_usaf_id = None else: message = "Using weather_source {}".format(weather_source) weather_source_usaf_id = weather_source.usaf_id else: message = "Using supplied weather_source" weather_source_usaf_id = weather_source.usaf_id output['weather_source_station'] = weather_source_usaf_id output['logs'].append(message) logger.debug(message) if weather_normal_source is None: use_cz2010 = (self.weather_normal_station_mapping == 'CZ2010') weather_normal_source = get_weather_normal_source( site, use_cz2010=use_cz2010) if weather_normal_source is None: message = ( "Could not find weather normal source matching site {}". format(site)) weather_normal_source_usaf_id = None else: message = ("Using weather_normal_source {}".format( weather_normal_source)) weather_normal_source_usaf_id = weather_normal_source.usaf_id else: message = "Using supplied weather_normal_source" weather_normal_source_usaf_id = weather_normal_source.usaf_id output['weather_normal_source_station'] = weather_normal_source_usaf_id output['logs'].append(message) logger.debug(message) # Step 3: Check to see if trace is placeholder. If so, # return with SUCCESS, empty derivatives. if trace.placeholder: message = ( 'Skipping modeling for placeholder trace {}'.format(trace)) logger.info(message) output['logs'].append(message) output['status'] = SUCCESS output['derivatives'] = [] return output # Step 4: Determine trace interpretation and frequency # TODO use trace interval here. And enforce upstream that interval use # pandas interval strings? trace_frequency = get_approximate_frequency(trace) if trace_frequency not in ['H', 'D', '15T', '30T']: trace_frequency = None selector = (trace.interpretation, trace_frequency) # Step 5: create formatter instance FormatterClass, formatter_kwargs = self._get_formatter( formatter, selector) if FormatterClass is None: message = ("Default formatter mapping did not find a match for the" " selector {}".format(selector)) output['status'] = FAILURE output['failure_message'] = message return output output["formatter_class"] = FormatterClass.__name__ output["formatter_kwargs"] = formatter_kwargs formatter_instance = FormatterClass(**formatter_kwargs) # Step 6: create model instance ModelClass, model_kwargs = self._get_model(model, selector) if ModelClass is None: message = ("Default model mapping did not find a match for the" " selector {}".format(selector)) output['status'] = FAILURE output['failure_message'] = message return output output["model_class"] = ModelClass.__name__ output["model_kwargs"] = model_kwargs # Step 7: validate modeling period set. Always fails for now, since # no models are yet fully structural change analysis aware if modeling_period_set is None: message = ( "Model is not structural-change capable, so `modeling_period`" " argument must be supplied.") output['status'] == FAILURE output['failure_message'] = message return output # Step 8: create split modeled energy trace model_mapping = { modeling_period_label: ModelClass(modeling_period_interpretation=modeling_period_label, **model_kwargs) for modeling_period_label, _ in modeling_period_set.iter_modeling_periods() } modeled_trace = SplitModeledEnergyTrace(trace, formatter_instance, model_mapping, modeling_period_set) modeled_trace.fit(weather_source) output["modeled_energy_trace"] = \ serialize_split_modeled_energy_trace(modeled_trace) # Step 9: for each modeling period group, create derivatives derivative_freq = 'D' if 'freq_str' in formatter_kwargs.keys() and \ formatter_kwargs['freq_str'] == 'H': derivative_freq = 'H' derivatives = [] for ((baseline_label, reporting_label), (baseline_period, reporting_period)) in \ modeling_period_set.iter_modeling_period_groups(): raw_derivatives = [] deriv_input = unpack(modeled_trace, baseline_label, reporting_label, baseline_period, reporting_period, weather_source, weather_normal_source, site, derivative_freq=derivative_freq) if deriv_input is None: continue raw_derivatives.extend([ hdd_balance_point_baseline(deriv_input), hdd_coefficient_baseline(deriv_input), cdd_balance_point_baseline(deriv_input), cdd_coefficient_baseline(deriv_input), intercept_baseline(deriv_input), hdd_balance_point_reporting(deriv_input), hdd_coefficient_reporting(deriv_input), cdd_balance_point_reporting(deriv_input), cdd_coefficient_reporting(deriv_input), intercept_reporting(deriv_input), cumulative_baseline_model_minus_reporting_model_normal_year( deriv_input), baseline_model_minus_reporting_model_normal_year(deriv_input), cumulative_baseline_model_normal_year(deriv_input), baseline_model_normal_year(deriv_input), cumulative_baseline_model_reporting_period(deriv_input), baseline_model_reporting_period(deriv_input), masked_baseline_model_reporting_period(deriv_input), cumulative_baseline_model_minus_observed_reporting_period( deriv_input), baseline_model_minus_observed_reporting_period(deriv_input), masked_baseline_model_minus_observed_reporting_period( deriv_input), baseline_model_baseline_period(deriv_input), cumulative_reporting_model_normal_year(deriv_input), reporting_model_normal_year(deriv_input), reporting_model_reporting_period(deriv_input), cumulative_observed_reporting_period(deriv_input), observed_reporting_period(deriv_input), masked_observed_reporting_period(deriv_input), cumulative_observed_baseline_period(deriv_input), observed_baseline_period(deriv_input), observed_project_period(deriv_input), temperature_baseline_period(deriv_input), temperature_reporting_period(deriv_input), masked_temperature_reporting_period(deriv_input), temperature_normal_year(deriv_input), baseline_mask(deriv_input), reporting_mask(deriv_input), reporting_period_resource_curve(deriv_input) ]) resource_curve_normal_year = normal_year_resource_curve( deriv_input) raw_derivatives.extend([resource_curve_normal_year]) if resource_curve_normal_year is not None: resource_curve_normal_year = pd.Series( resource_curve_normal_year['value'], index=pd.to_datetime( resource_curve_normal_year['orderable'])) raw_derivatives.extend([ normal_year_co2_avoided(deriv_input, resource_curve_normal_year) ]) derivatives += [ Derivative( (baseline_label, reporting_label), d['series'], reduce(lambda a, b: a + ' ' + b, d['description'].split()), d['orderable'], d['value'], d['variance'], ) for d in raw_derivatives if d is not None ] output["derivatives"] = serialize_derivatives(derivatives) output["status"] = SUCCESS return output
def test_get_version(): assert get_version().startswith("2")
def run_meter(self, meter_class='EnergyEfficiencyMeter', meter_settings=None, project_run=None, weather_source=None, weather_normal_source=None): """ If possible, run the meter specified by meter_class. Parameters ---------- meter_class : str One of the keys in METER_CLASS_CHOICES meter_settings : dict Dictionary of extra settings to send to the meter. Returns ------- project_result : datastore.models.ProjectResult Object containing results of meter run. """ try: project = self.eemeter_project() except ValueError: message = ( "Cannot create eemeter project; skipping project id={}." .format(self.project_id) ) warn(message) return None meter = self._get_meter(meter_class, settings=meter_settings) results = meter.evaluate(project, weather_source=weather_source, weather_normal_source=weather_normal_source) weather_source = results['weather_source'] if weather_source is not None: weather_source_station = weather_source.station else: weather_source_station = None weather_normal_source = \ results['weather_normal_source'] if weather_normal_source is not None: weather_normal_source_station = weather_normal_source.station else: weather_normal_source_station = None project_result = ProjectResult.objects.create( project=self, project_run=project_run, eemeter_version=get_version(), meter_class=meter_class, meter_settings=meter_settings, weather_source_station=weather_source_station, weather_normal_source_station=weather_normal_source_station, ) modeling_period_mapping = {} for modeling_period_label, modeling_period in \ results['modeling_period_set'].iter_modeling_periods(): mp = ModelingPeriod.objects.create( project_result=project_result, interpretation=modeling_period.interpretation, start_date=modeling_period.start_date, end_date=modeling_period.end_date, ) modeling_period_mapping[modeling_period_label] = mp modeling_period_group_mapping = {} for (baseline_label, reporting_label), _ in \ results['modeling_period_set'].iter_modeling_period_groups(): mp_baseline = modeling_period_mapping[baseline_label] mp_reporting = modeling_period_mapping[reporting_label] mpg = ModelingPeriodGroup.objects.create( project_result=project_result, baseline_period=mp_baseline, reporting_period=mp_reporting, ) modeling_period_group_mapping[ (baseline_label, reporting_label)] = mpg # one result per trace per model energy_trace_model_result_mapping = {} for trace_label, modeled_energy_trace in \ results['modeled_energy_traces'].items(): for model_label, outputs in \ modeled_energy_trace.fit_outputs.items(): etm = EnergyTraceModelResult.objects.create( project_result=project_result, energy_trace_id=trace_label, modeling_period=modeling_period_mapping[model_label], model_serializiation=None, status=outputs['status'], r2=outputs.get('r2'), rmse=outputs.get('rmse'), cvrmse=outputs.get('cvrmse'), upper=outputs.get('upper'), lower=outputs.get('lower'), n=outputs.get('n'), ) energy_trace_model_result_mapping[ (trace_label, model_label)] = etm aggregation_interpretations = [ 'annualized_weather_normal', 'gross_predicted', ] for trace_label, modeling_period_group_derivatives in \ results['modeled_energy_trace_derivatives'].items(): # get all modeling period derivatives modeling_period_derivatives = {} for (baseline_label, reporting_label), derivatives in \ modeling_period_group_derivatives.items(): modeling_period_derivatives[baseline_label] = \ derivatives['BASELINE'] modeling_period_derivatives[reporting_label] = \ derivatives['REPORTING'] for modeling_period_label, derivatives in \ modeling_period_derivatives.items(): for interpretation in aggregation_interpretations: derivative = derivatives.get(interpretation, None) energy_trace_model_res = \ energy_trace_model_result_mapping[ (trace_label, modeling_period_label)] if derivative is not None: Derivative.objects.create( energy_trace_model_result=energy_trace_model_res, interpretation=interpretation, value=derivative[0], upper=derivative[1], lower=derivative[2], n=derivative[3], ) # one result per aggregation - baseline + reporting? for group_label, group_derivatives in \ results['project_derivatives'].items(): for name, named_results in group_derivatives.items(): if named_results is None: continue for interpretation in aggregation_interpretations: baseline_output = \ named_results['BASELINE'][interpretation] reporting_output = \ named_results['REPORTING'][interpretation] modeling_period_group = \ modeling_period_group_mapping[group_label] DerivativeAggregation.objects.create( project_result=project_result, modeling_period_group=modeling_period_group, trace_interpretation=name, interpretation=interpretation, baseline_value=baseline_output[0], baseline_upper=baseline_output[1], baseline_lower=baseline_output[2], baseline_n=baseline_output[3], reporting_value=reporting_output[0], reporting_upper=reporting_output[1], reporting_lower=reporting_output[2], reporting_n=reporting_output[3], ) return project_result
def run_meter(self, meter_class='EnergyEfficiencyMeter', meter_settings=None, project_run=None, weather_source=None, weather_normal_source=None): """ If possible, run the meter specified by meter_class. Parameters ---------- meter_class : str One of the keys in METER_CLASS_CHOICES meter_settings : dict Dictionary of extra settings to send to the meter. Returns ------- project_result : datastore.models.ProjectResult Object containing results of meter run. """ try: project = self.eemeter_project() except ValueError: message = ("Cannot create eemeter project; skipping project id={}." .format(self.project_id)) warn(message) return None meter = self._get_meter(meter_class, settings=meter_settings) results = meter.evaluate(project, weather_source=weather_source, weather_normal_source=weather_normal_source) weather_source = results['weather_source'] if weather_source is not None: weather_source_station = weather_source.station else: weather_source_station = None weather_normal_source = \ results['weather_normal_source'] if weather_normal_source is not None: weather_normal_source_station = weather_normal_source.station else: weather_normal_source_station = None project_result = ProjectResult.objects.create( project=self, project_run=project_run, eemeter_version=get_version(), meter_class=meter_class, meter_settings=meter_settings, weather_source_station=weather_source_station, weather_normal_source_station=weather_normal_source_station, ) modeling_period_mapping = {} for modeling_period_label, modeling_period in \ results['modeling_period_set'].iter_modeling_periods(): mp = ModelingPeriod.objects.create( project_result=project_result, interpretation=modeling_period.interpretation, start_date=modeling_period.start_date, end_date=modeling_period.end_date, ) modeling_period_mapping[modeling_period_label] = mp modeling_period_group_mapping = {} for (baseline_label, reporting_label), _ in \ results['modeling_period_set'].iter_modeling_period_groups(): mp_baseline = modeling_period_mapping[baseline_label] mp_reporting = modeling_period_mapping[reporting_label] mpg = ModelingPeriodGroup.objects.create( project_result=project_result, baseline_period=mp_baseline, reporting_period=mp_reporting, ) modeling_period_group_mapping[(baseline_label, reporting_label)] = mpg # one result per trace per model energy_trace_model_result_mapping = {} for trace_label, modeled_energy_trace in \ results['modeled_energy_traces'].items(): for model_label, outputs in \ modeled_energy_trace.fit_outputs.items(): etm = EnergyTraceModelResult.objects.create( project_result=project_result, energy_trace_id=trace_label, modeling_period=modeling_period_mapping[model_label], model_serializiation=None, status=outputs['status'], r2=outputs.get('r2'), rmse=outputs.get('rmse'), cvrmse=outputs.get('cvrmse'), upper=outputs.get('upper'), lower=outputs.get('lower'), n=outputs.get('n'), ) energy_trace_model_result_mapping[(trace_label, model_label)] = etm aggregation_interpretations = [ 'annualized_weather_normal', 'gross_predicted', ] for trace_label, modeling_period_group_derivatives in \ results['modeled_energy_trace_derivatives'].items(): # get all modeling period derivatives modeling_period_derivatives = {} for (baseline_label, reporting_label), derivatives in \ modeling_period_group_derivatives.items(): modeling_period_derivatives[baseline_label] = \ derivatives['BASELINE'] modeling_period_derivatives[reporting_label] = \ derivatives['REPORTING'] for modeling_period_label, derivatives in \ modeling_period_derivatives.items(): for interpretation in aggregation_interpretations: derivative = derivatives.get(interpretation, None) energy_trace_model_res = \ energy_trace_model_result_mapping[ (trace_label, modeling_period_label)] if derivative is not None: Derivative.objects.create( energy_trace_model_result=energy_trace_model_res, interpretation=interpretation, value=derivative[0], upper=derivative[1], lower=derivative[2], n=derivative[3], ) # one result per aggregation - baseline + reporting? for group_label, group_derivatives in \ results['project_derivatives'].items(): for name, named_results in group_derivatives.items(): if named_results is None: continue for interpretation in aggregation_interpretations: baseline_output = \ named_results['BASELINE'][interpretation] reporting_output = \ named_results['REPORTING'][interpretation] modeling_period_group = \ modeling_period_group_mapping[group_label] DerivativeAggregation.objects.create( project_result=project_result, modeling_period_group=modeling_period_group, trace_interpretation=name, interpretation=interpretation, baseline_value=baseline_output[0], baseline_upper=baseline_output[1], baseline_lower=baseline_output[2], baseline_n=baseline_output[3], reporting_value=reporting_output[0], reporting_upper=reporting_output[1], reporting_lower=reporting_output[2], reporting_n=reporting_output[3], ) return project_result
def test_get_version(): assert get_version() is not None
# you can simply install eemeter by pip install eemeter import eemeter eemeter.get_version()