Example #1
0
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()))
Example #2
0
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,
    }
Example #3
0
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()))
Example #5
0
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,
        }
Example #6
0
    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)
Example #7
0
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
Example #8
0
    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)
Example #9
0
    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)
Example #10
0
    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)
Example #11
0
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)
Example #12
0
    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)