def _ensure_itree_codes_fetched(): global _itree_codes_by_region, _all_itree_codes if _itree_codes_by_region is None: result, err = ecobackend.json_benefits_call("itree_codes.json", {}) if err: raise Exception("Failed to retrieve i-Tree codes from ecoservice") _itree_codes_by_region = result["Codes"] _all_itree_codes = set(itertools.chain(*_itree_codes_by_region.values()))
def _run_model(instance, growth_model, scenario, region_code): n_years = scenario['years'] yearly_counts, planted_trees = growth_model.run(scenario) eco_trees = _model_trees_to_eco_trees(planted_trees, region_code) eco_input = { 'region': region_code, 'instance_id': str(instance.id), 'years': n_years, 'scenario_trees': eco_trees } eco, err = ecobackend.json_benefits_call('eco_scenario.json', eco_input, post=True, convert_params=False) if err: raise Exception(err) total_eco = compute_currency_and_transform_units(instance, eco['Total']) total_eco = format_benefits(instance, total_eco, None, digits=0) currency_symbol = total_eco['currency_symbol'] total_eco = _list_for_display(total_eco['benefits']) yearly_eco = [ compute_currency_and_transform_units(instance, benefits) for benefits in eco['Years'] ] yearly_eco = [_list_for_display(benefits) for benefits in yearly_eco] yearly_eco_condensed = yearly_eco[0] for i in range(0, len(yearly_eco_condensed)): yearly_eco_condensed[i] = { 'label': yearly_eco_condensed[i]['label'], 'unit': yearly_eco_condensed[i]['unit'], 'values': [benefits[i]['value'] for benefits in yearly_eco], 'currencies': [benefits[i]['currency'] for benefits in yearly_eco] } year_headers = [_('Year %(n)s' % {'n': i}) for i in range(1, n_years + 1)] growth_csv_data = _growth_csv_data(instance, year_headers, planted_trees) return { 'years': n_years, 'yearly_counts': yearly_counts, 'total_eco': total_eco, 'yearly_eco': yearly_eco_condensed, 'currency_symbol': currency_symbol, 'currency_axis_label': "%s %s" % (currency_symbol, _('saved')), 'eco_csv_header': _eco_csv_header(year_headers), 'growth_csv_data': growth_csv_data, }
def invalidate_ecoservice_cache_if_stale(): from treemap import ecobackend global my_itree_code_override_rev cached_rev = _init_if_needed() if my_itree_code_override_rev != cached_rev: __, err = ecobackend.json_benefits_call('invalidate_cache', {}) if err: raise Exception('Failed to invalidate ecoservice cache') my_itree_code_override_rev = cached_rev
def _ensure_itree_codes_fetched(): global _itree_codes_by_region, _all_itree_codes if _itree_codes_by_region is None: result, err = ecobackend.json_benefits_call('itree_codes.json', {}) if err: raise Exception('Failed to retrieve i-Tree codes from ecoservice') _itree_codes_by_region = result['Codes'] _all_itree_codes = set( itertools.chain(*_itree_codes_by_region.values()))
def _run_model(instance, growth_model, scenario, region_code): n_years = scenario['years'] yearly_counts, planted_trees = growth_model.run(scenario) eco_trees = _model_trees_to_eco_trees(planted_trees, region_code) eco_input = { 'region': region_code, 'instance_id': str(instance.id), 'years': n_years, 'scenario_trees': eco_trees } eco, err = ecobackend.json_benefits_call('eco_scenario.json', eco_input, post=True, convert_params=False) if err: raise Exception(err) total_eco = compute_currency_and_transform_units(instance, eco['Total']) total_eco = format_benefits(instance, total_eco, None, digits=0) currency_symbol = total_eco['currency_symbol'] total_eco = _list_for_display(total_eco['benefits']) yearly_eco = [compute_currency_and_transform_units(instance, benefits) for benefits in eco['Years']] yearly_eco = [_list_for_display(benefits) for benefits in yearly_eco] yearly_eco_condensed = yearly_eco[0] for i in range(0, len(yearly_eco_condensed)): yearly_eco_condensed[i] = { 'label': yearly_eco_condensed[i]['label'], 'unit': yearly_eco_condensed[i]['unit'], 'values': [benefits[i]['value'] for benefits in yearly_eco], 'currencies': [benefits[i]['currency'] for benefits in yearly_eco] } year_headers = [_('Year %(n)s' % {'n': i}) for i in range(1, n_years + 1)] growth_csv_data = _growth_csv_data(instance, year_headers, planted_trees) return { 'years': n_years, 'yearly_counts': yearly_counts, 'total_eco': total_eco, 'yearly_eco': yearly_eco_condensed, 'currency_symbol': currency_symbol, 'currency_axis_label': "%s %s" % (currency_symbol, _('saved')), 'eco_csv_header': _eco_csv_header(year_headers), 'growth_csv_data': growth_csv_data, }
def benefits_for_object(self, instance, plot): tree = plot.current_tree() error = None if tree is None: rslt = None error = 'NO_TREE' elif not tree.diameter: rslt = None error = 'MISSING_DBH' elif not tree.species: rslt = None error = 'MISSING_SPECIES' else: region_code = plot.itree_region.code if region_code: params = { 'otmcode': tree.species.otm_code, 'diameter': tree.diameter, 'region': region_code, 'instanceid': instance.pk, 'speciesid': tree.species.pk } rawb, err = ecobackend.json_benefits_call( 'eco.json', params.iteritems()) if err: rslt = {'error': err} error = err else: benefits = compute_currency_and_transform_units( instance, rawb['Benefits']) rslt = benefits else: rslt = None error = 'MISSING_REGION' basis = { 'plot': { 'n_objects_used': 1 if rslt else 0, 'n_objects_discarded': 0 if rslt else 1 } } return (rslt, basis, error)
def tree_benefits(instance, tree_or_tree_id): """Given a tree id, determine eco benefits via eco.py""" if isinstance(tree_or_tree_id, int): InstanceTree = instance.scope_model(Tree) tree = get_object_or_404(InstanceTree, pk=tree_or_tree_id) else: tree = tree_or_tree_id if not tree.diameter: rslt = {'tree_benefits': {}, 'error': 'MISSING_DBH'} elif not tree.species: rslt = {'tree_benefits': {}, 'error': 'MISSING_SPECIES'} else: if instance.itree_region_default: region = instance.itree_region_default else: regions = ITreeRegion.objects\ .filter(geometry__contains=tree.plot.geom) if len(regions) > 0: region = regions[0].code else: region = None if region: params = {'otmcode': tree.species.otm_code, 'diameter': tree.diameter, 'region': region, 'instanceid': instance.pk, 'speciesid': tree.species.pk} rawb, err = ecobackend.json_benefits_call( 'eco.json', params.iteritems()) if err: rslt = {'error': err} else: benefits, _ = _compute_currency_and_transform_units( instance, rawb['Benefits']) rslt = {'tree_benefits': benefits} else: rslt = {'tree_benefits': {}, 'error': 'MISSING_REGION'} return rslt
def benefits_for_object(self, instance, plot): tree = plot.current_tree() error = None if tree is None: rslt = None error = 'NO_TREE' elif not tree.diameter: rslt = None error = 'MISSING_DBH' elif not tree.species: rslt = None error = 'MISSING_SPECIES' else: region_code = plot.itree_region.code if region_code: params = {'otmcode': tree.species.otm_code, 'diameter': tree.diameter, 'region': region_code, 'instanceid': instance.pk, 'speciesid': tree.species.pk} rawb, err = ecobackend.json_benefits_call( 'eco.json', params.iteritems()) if err: rslt = {'error': err} error = err else: benefits = compute_currency_and_transform_units( instance, rawb['Benefits']) rslt = benefits else: rslt = None error = 'MISSING_REGION' basis = {'plot': {'n_objects_used': 1 if rslt else 0, 'n_objects_discarded': 0 if rslt else 1}} return (rslt, basis, error)
def benefits_for_object(self, instance, plot): tree = plot.current_tree() error = None if tree is None: rslt = None error = "NO_TREE" elif not tree.diameter: rslt = None error = "MISSING_DBH" elif not tree.species: rslt = None error = "MISSING_SPECIES" else: region_code = plot.itree_region.code if region_code: params = { "otmcode": tree.species.otm_code, "diameter": tree.diameter, "region": region_code, "instanceid": instance.pk, "speciesid": tree.species.pk, } rawb, err = ecobackend.json_benefits_call("eco.json", params.iteritems()) if err: rslt = {"error": err} error = err else: benefits = compute_currency_and_transform_units(instance, rawb["Benefits"]) rslt = benefits else: rslt = None error = "MISSING_REGION" basis = {"plot": {"n_objects_used": 1 if rslt else 0, "n_objects_discarded": 0 if rslt else 1}} return (rslt, basis, error)
def benefits_for_filter(self, instance, item_filter): from treemap.models import Plot, Tree instance = item_filter.instance plots = item_filter.get_objects(Plot) trees = Tree.objects.filter(plot__in=plots) n_total_trees = trees.count() if not instance.has_itree_region(): basis = {'plot': {'n_objects_used': 0, 'n_objects_discarded': n_total_trees}} return ({}, basis) if n_total_trees == 0: basis = {'plot': {'n_objects_used': 0, 'n_objects_discarded': n_total_trees}} empty_rslt = compute_currency_and_transform_units( instance, {}) return (empty_rslt, basis) # When calculating benefits we can skip region information # if there is only one intersecting region or if the # instance forces a region on us regions = instance.itree_regions() if len(regions) == 1: region_code = regions[0].code else: region_code = None # We want to do a values query that returns the info that # we need for an eco calculation: # diameter, species id and species code # # The species id is used to find potential overrides values = ('diameter', 'species__pk', 'species__otm_code',) # If there isn't a single region we need to # include geometry information if not region_code: values += ('plot__geom',) # We use two extra instance filter to help out # the database a bit when doing the joins treeValues = trees.filter(species__isnull=False)\ .filter(diameter__isnull=False)\ .filter(plot__instance=instance)\ .filter(species__instance=instance)\ .values_list(*values) query = self._make_sql_from_query(treeValues.query) # We want to extract x and y coordinates but django # doesn't make this easy since we need to force a join # on plot/mapfeature. To make sure the djago machinery # does that we use "plot__geom" above and then # do this rather dubious string manipulation below if not region_code: targetGeomField = '"treemap_mapfeature"."the_geom_webmercator"' xyGeomFields = 'ST_X(%s), ST_Y(%s)' % \ (targetGeomField, targetGeomField) query = query.replace(targetGeomField, xyGeomFields, 1) params = {'query': query, 'instance_id': instance.pk, 'region': region_code or ""} rawb, err = ecobackend.json_benefits_call( 'eco_summary.json', params.iteritems(), post=True) if err: raise Exception(err) benefits = rawb['Benefits'] if 'n_trees' in benefits: n_computed_trees = int(benefits['n_trees']) else: n_computed_trees = 1 # Extrapolate an average over the rest of the urban forest if n_computed_trees > 0 and n_total_trees > 0: percent = float(n_computed_trees) / n_total_trees for key in benefits: benefits[key] /= percent rslt = compute_currency_and_transform_units(instance, benefits) basis = {'plot': {'n_objects_used': n_computed_trees, 'n_objects_discarded': n_total_trees - n_computed_trees}} return (rslt, basis)
def benefits_for_trees(trees, instance): # When calculating benefits we can skip region information # if there is only one intersecting region or if the # instance forces a region on us region = None if instance.itree_region_default: region = instance.itree_region_default else: regions = ITreeRegion.objects.filter( geometry__intersects=instance.bounds) if regions.length() == 1: region = regions[0].code # We want to do a values query that returns the info that # we need for an eco calculation: # diameter, species id and species code # # The species id is used to find potential overrides values = ('diameter', 'species__pk', 'species__otm_code',) # If there isn't a single region we need to # include geometry information if not region: values += ('plot__geom',) # We use two extra instance filter to help out # the database a bit when doing the joins treeValues = trees.filter(species__isnull=False)\ .filter(diameter__isnull=False)\ .filter(plot__instance=instance)\ .filter(species__instance=instance)\ .values_list(*values) query = _make_sql_from_query(treeValues.query) # We want to extract x and y coordinates but django # doesn't make this easy since we need to force a join # on plot/mapfeature. To make sure the djago machinery # does that we use "plot__geom" above and then # do this rather dubious string manipulation below if not region: targetGeomField = '"treemap_mapfeature"."the_geom_webmercator"' xyGeomFields = 'ST_X(%s), ST_Y(%s)' % \ (targetGeomField, targetGeomField) query = query.replace(targetGeomField, xyGeomFields, 1) params = {'query': query, 'instance_id': instance.pk, 'region': region or ""} rawb, err = ecobackend.json_benefits_call( 'eco_summary.json', params.iteritems(), post=True) if err: raise Exception(err) benefits = rawb['Benefits'] return _compute_currency_and_transform_units(instance, benefits)