Beispiel #1
0
    def fragment_lcia(self,
                      fragment,
                      quantity_ref,
                      scenario=None,
                      refresh=False,
                      **kwargs):
        if scenario is None:
            scenario = '1'
        lcia_q = self.get_lcia_quantity(quantity_ref)
        endpoint = 'scenarios/%s/%s/%s/lciaresults' % (scenario, fragment,
                                                       lcia_q.external_ref)
        lcia_r = self._archive.get_endpoint(endpoint, cache=False)
        if lcia_r is None or (isinstance(lcia_r, list)
                              and all(i is None for i in lcia_r)):
            res = LciaResult(lcia_q, scenario=scenario)
            return res

        res = LciaResult(lcia_q, scenario=lcia_r.pop('scenarioID'))
        total = lcia_r.pop('total')

        for component in lcia_r['lciaScore']:
            self.add_lcia_component(res, component)

        self.check_total(res.total(), total)

        return res
Beispiel #2
0
 def test_catalog_ref(self):
     """
     Create an LCIA result using a catalog ref as quantity
     :return:
     """
     qty = CatalogRef('fictitious.origin', 'dummy_ext_ref', entity_type='quantity', Name='Test Quantity')
     res = LciaResult(qty)
     self.assertEqual(res.total(), 0.0)
Beispiel #3
0
    def retrieve_lcia_scores(self, process_uuid, rf_uuid, quantities=None):
        """
        This function retrieves LCIA scores from an Ecospold02 file and stores them as characterizations in
        an LcFlow entity corresponding to the *first* (and presumably, only) reference intermediate flow

        Only stores cfs for quantities that exist locally.
        :param process_uuid:
        :param rf_uuid:
        :param quantities: list of quantity entities to look for (defaults to all local lcia_methods)
        :return: a dict of quantity uuid to score
        """
        if quantities is None:
            quantities = [l for l in self.entities_by_type('quantity') if l.is_lcia_method()]

        import time
        start_time = time.time()
        print('Loading LCIA results for %s_%s' % (process_uuid, rf_uuid))
        o = self.objectify(process_uuid, rf_uuid)

        self._print('%30.30s -- %5f' % ('Objectified', time.time() - start_time))
        p = self._create_process_entity(o)
        rf = self._grab_reference_flow(o, rf_uuid)

        exch = ExchangeValue(p, rf, 'Output', value=1.0)

        tags = dict()
        for q in quantities:
            if 'Method' in q.keys():
                if q['Name'] in tags:
                    raise KeyError('Name collision %s' % q['Name'])
                tags[q['Name']] = q

        results = LciaResults(p)

        for char in find_tag(o, 'flowData').getchildren():
            if 'impactIndicator' in char.tag:
                m = char.impactMethodName.text
                c = char.impactCategoryName.text
                i = char.name.text
                v = float(char.get('amount'))
                my_tag = ', '.join([m, c, i])
                if my_tag in tags:
                    q = tags[my_tag]
                    result = LciaResult(q)
                    cf = Characterization(rf, q, value=v, location=p['SpatialScope'])
                    result.add_score(p.get_uuid(), exch, cf, p['SpatialScope'])
                    results[q.get_uuid()] = result

        self._print('%30.30s -- %5f' % ('Impact scores collected', time.time() - start_time))

        return results
Beispiel #4
0
    def retrieve_lcia_scores(self, filename, quantities=None):
        """
        This function retrieves LCIA scores from an Ecospold02 file and stores them as characterizations in
        an LcFlow entity corresponding to the *first* (and presumably, only) reference intermediate flow

        Only stores cfs for quantities that exist locally.
        :param filename:
        :param quantities: list of quantity entities to look for (defaults to self.quantities())
        :return: a dict of quantity uuid to score
        """
        if quantities is None:
            quantities = self.quantities()

        import time
        start_time = time.time()
        print('Loading LCIA results from %s' % filename)
        o = self.objectify(filename)

        self._print('%30.30s -- %5f' % ('Objectified', time.time() - start_time))
        p = self._create_process_entity(o)
        rf = self._grab_reference_flow(o, spold_reference_flow(filename))

        exch = ExchangeValue(p, rf, 'Output', value=1.0)

        tags = dict()
        for q in quantities:
            if 'Method' in q.keys():
                if q['Name'] in tags:
                    raise KeyError('Name collision %s' % q['Name'])
                tags[q['Name']] = q

        results = LciaResults(p)

        for char in find_tag(o, 'flowData')[0].getchildren():
            if 'impactIndicator' in char.tag:
                m = char.impactMethodName.text
                c = char.impactCategoryName.text
                i = char.name.text
                v = float(char.get('amount'))
                my_tag = ', '.join([m, c, i])
                if my_tag in tags:
                    q = tags[my_tag]
                    result = LciaResult(q)
                    cf = Characterization(rf, q, value=v, location=p['SpatialScope'])
                    result.add_score(p.get_uuid(), exch, cf, p['SpatialScope'])
                    results[q.get_uuid()] = result

        self._print('%30.30s -- %5f' % ('Impact scores collected', time.time() - start_time))

        return results
Beispiel #5
0
 def lcia(self, quantity, ref_flow=None, scenario=None, flowdb=None):
     result = LciaResult(quantity, scenario)
     result.add_component(self.get_uuid(), entity=self)
     for ex in self.allocated_exchanges(scenario or ref_flow):
         if not ex.flow.has_characterization(quantity):
             if flowdb is not None:
                 if quantity in flowdb.known_quantities():
                     factor = flowdb.lookup_single_cf(ex.flow, quantity, self['SpatialScope'])
                     if factor is None:
                         ex.flow.add_characterization(quantity)
                     else:
                         ex.flow.add_characterization(factor)
         factor = ex.flow.factor(quantity)
         result.add_score(self.get_uuid(), ex, factor, self['SpatialScope'])
     return result
Beispiel #6
0
def frag_flow_lcia(fragmentflows,
                   quantity_ref,
                   scenario=None,
                   refresh=False,
                   ignore_uncached=True):
    """
    Recursive function to compute LCIA of a traversal record contained in a set of Fragment Flows.
    :param fragmentflows:
    :param quantity_ref:
    :param scenario: necessary if any remote traversals are required
    :param refresh: whether to refresh the LCIA CFs
    :param ignore_uncached: [True] whether to allow zero scores for un-cached, un-computable fragments
    :return:
    """
    result = LciaResult(quantity_ref)
    for ff in fragmentflows:
        if ff.term.is_null:
            continue

        node_weight = ff.node_weight
        if node_weight == 0:
            continue

        try:
            v = ff.term.score_cache(quantity=quantity_ref,
                                    refresh=refresh,
                                    ignore_uncached=ignore_uncached)
        except SubFragmentAggregation:
            # if we were given interior fragments, recurse on them. otherwise ask remote.
            if len(ff.subfragments) == 0:
                v = ff.term.term_node.fragment_lcia(quantity_ref,
                                                    scenario=scenario,
                                                    refresh=refresh)
            else:
                v = frag_flow_lcia(ff.subfragments,
                                   quantity_ref,
                                   refresh=refresh)
        if v.is_null:
            continue

        if ff.term.direction == ff.fragment.direction:
            # if the directions collide (rather than complement), the term is getting run in reverse
            node_weight *= -1

        result.add_summary(ff.fragment.uuid, ff, node_weight, v)
    return result
Beispiel #7
0
    def lcia(self, process, ref_flow, quantity_ref, refresh=False, **kwargs):
        """
        Antelope v1 doesn't support or even have any knowledge of process reference-flows. this is a somewhat
        significant design flaw.  well, no matter.  each antelopev1 process must therefore represent an allocated single
        operation process that has an unambiguous reference flow.  This is a problem to solve on the server side;
        for now we just ignore the ref_flow argument.

        If the quantity ref is one of the ones natively known by the antelope server-- i.e. if it is a catalog ref whose
        origin matches the origin of the current archive-- then it is trivially used.  Otherwise, the lcia call reduces
        to obtaining the inventory and computing LCIA locally.
        :param process:
        :param ref_flow:
        :param quantity_ref:
        :param refresh:
        :param kwargs:
        :return:
        """
        lcia_q = self.get_lcia_quantity(quantity_ref)
        endpoint = '%s/%s/lciaresults' % (process, lcia_q.external_ref)
        lcia_r = self._archive.get_endpoint(endpoint, cache=False)

        res = LciaResult(lcia_q, scenario=lcia_r.pop('scenarioID'))
        total = lcia_r.pop('total')

        if len(lcia_r['lciaScore']) > 1:
            raise AntelopeV1Error(
                'Process LCIA result contains too many components\n%s' %
                process)

        component = lcia_r['lciaScore'][0]
        cum = component['cumulativeResult']
        self.check_total(cum, total)

        if 'processes/%s' % component['processID'] != process:
            raise AntelopeV1Error('Reference mismatch: %s begat %s' %
                                  (process, component['processID']))

        self.add_lcia_component(res, component)

        self.check_total(res.total(), total)
        return res
Beispiel #8
0
 def fg_lcia(self, process_ref, quantities=None, dist=3, scenario=None, **kwargs):
     """
     :param process_ref:
     :param quantities: defaults to foreground lcia quantities
     :param dist: [1] how far afield to search for cfs (see CLookup.find() from flowdb)
     :param scenario: (not presently used) - some day the flow-quantity database will be scenario-sensitive
     :return:
     """
     if self._catalog.fg is None:
         print('Missing a foreground!')
         return None
     if not self._catalog.is_loaded(0):
         self._catalog.load(0)
     if not self._catalog.is_loaded(process_ref.index):
         self._catalog.load(process_ref.index)
     exch = self.db.filter_exch(process_ref, elem=True, **kwargs)
     qs = self._prep_quantities(quantities)
     results = LciaResults(process_ref.entity())
     for q in qs:
         q_result = LciaResult(q)
         if q in self.db.known_quantities():
             for x in exch:
                 if not x.flow.has_characterization(q):
                     # look locally
                     local = self[0][x.flow.get_uuid()]
                     if local is not None and local.has_characterization(q):
                         cf = local.factor(q)
                         x.flow.add_characterization(cf)
                     else:
                         cf = self.db.lookup_single_cf(x.flow, q, dist=dist, location=process_ref['SpatialScope'])
                         if cf is None:
                             x.flow.add_characterization(q)
                         else:
                             x.flow.add_characterization(cf)
                             self.add_to_foreground(x.flow)
                 fac = x.flow.factor(q)
                 q_result.add_score(process_ref.id, x, fac, process_ref['SpatialScope'])
         results[q.get_uuid()] = q_result
     return results
Beispiel #9
0
 def lcia(self, quantity, ref_flow=None):
     if not quantity.is_entity:
         # only works for quantity refs-- in other words, always works
         return quantity.do_lcia(self.inventory(ref_flow=ref_flow),
                                 locale=self['SpatialScope'])
     else:
         result = LciaResult(quantity)
         result.add_component(self.get_uuid(), entity=self)
         for ex in self.inventory(ref_flow):
             factor = ex.flow.factor(quantity)
             result.add_score(self.get_uuid(), ex, factor,
                              self['SpatialScope'])
         return result
Beispiel #10
0
 def score_cache(self,
                 quantity=None,
                 ignore_uncached=False,
                 refresh=False,
                 **kwargs):
     if quantity is None:
         return self._score_cache
     if quantity.uuid in self._score_cache and refresh is False:
         return self._score_cache[quantity.uuid]
     else:
         try:
             res = self.compute_unit_score(quantity,
                                           refresh=refresh,
                                           **kwargs)
         except UnCachedScore:
             if ignore_uncached:
                 res = LciaResult(quantity)
             else:
                 raise
         self._score_cache[quantity.uuid] = res
         return res
Beispiel #11
0
    def do_lcia(self, quantity, inventory, locale='GLO', refresh=False, debug=False, **kwargs):
        """
        takes a quantity and an exchanges generator; returns an LciaResult for the given quantity.
        For now, does NOT pre-load quantity LCIA methods. that is a catalog action. the Qdb doesn't do catalog stuff.
        I am open to re-thinking it, though.
        :param quantity:
        :param inventory: generates exchanges
        :param locale: ['GLO']
        :param refresh: [False] whether to rewrite characterization factors from the database
        :param debug: [False] print extra information to screen
        :param kwargs: just quell_biogenic_co2 for the moment
        :return: an LciaResult whose components are the flows of the exchanges
        """
        q = self[quantity.link]
        q_ind = self._get_q_ind(q)
        _is_quiet = self._quiet
        if debug:
            self._quiet = False
        self._print('q_ind: %d' % q_ind)
        r = LciaResult(q)
        for x in inventory:
            if refresh or not x.flow.has_characterization(q):
                try:
                    factor = self.convert(flow=x.flow, query_q_ind=q_ind, locale=locale, **kwargs)
                except MissingCompartment:
                    self._print('Missing compartment %s; abandoning this exchange' % x.flow['Compartment'])
                    continue
                except ConversionReferenceMismatch:
                    print('Mismatch %s' % x)
                    factor = None

                if factor is not None:
                    self._print('factor %g %s' % (factor, x))
                    x.flow.add_characterization(q, value=factor, overwrite=refresh)
                else:
                    self._print('factor NONE %s' % x)
                    x.flow.add_characterization(q)
            if x.flow.cf(q) is not None:
                r.add_component(x.flow.external_ref, entity=x.flow)
                fac = x.flow.factor(q)
                fac.set_natural_direction(self.c_mgr)
                r.add_score(x.flow.external_ref, x, fac, locale)
        self._quiet = _is_quiet
        return r
Beispiel #12
0
 def lcia(x, y, z):
     local = self[0][y.get_uuid()]
     if local is not y:
         raise AmbiguousReference('!!! this should be in foreground')
     return LciaResult.from_cfs(x, self.db.factors_for_flow(local, z))
Beispiel #13
0
 def add_lcia_score(self, quantity, score, scenario=None):
     res = LciaResult(quantity, scenario=scenario)
     res.add_summary(self._parent.uuid, self._parent, 1.0, score)
     self._score_cache.add(res)
Beispiel #14
0
    def compute_unit_score(self, quantity_ref, **kwargs):
        """
        four different ways to do this.
        0- we are a subfragment-- throw exception: use subfragment traversal results contained in the FragmentFlow
        1- parent is bg: ask catalog to give us bg_lcia (process or fragment)
        2- get fg lcia for unobserved exchanges

        If
        :param quantity_ref:
        :return:
        """
        if self.is_subfrag:
            if self.descend:
                return LciaResult(
                    quantity_ref
                )  # null result for subfragments that are explicitly followed
            else:
                raise SubFragmentAggregation  # to be caught

        if self.is_bg:
            if self.is_fg:
                # surprisingly not inconsistent! in the current pre-ContextRefactor world, this is how we are handling
                # cached-LCIA-score nodes
                raise UnCachedScore('fragment: %s\nquantity: %s' %
                                    (self._parent, quantity_ref))

            elif self.is_frag:
                # need bg_lcia method for FragmentRefs
                # this is probably not currently supported
                return self.term_node.bg_lcia(
                    lcia_qty=quantity_ref,
                    ref_flow=self.term_flow.external_ref,
                    **kwargs)

        try:
            locale = self.term_node['SpatialScope']
        except KeyError:
            locale = 'GLO'
        try:
            res = quantity_ref.do_lcia(self._unobserved_exchanges(),
                                       locale=locale,
                                       **kwargs)
        except PrivateArchive:
            if self.is_bg:
                print(
                    'terminations.compute_unit_score UNTESTED for private bg archives!'
                )
                res = self.term_node.bg_lcia(
                    lcia_qty=quantity_ref,
                    ref_flow=self.term_flow.external_ref,
                    **kwargs)
            else:
                res = self.term_node.fg_lcia(
                    quantity_ref,
                    ref_flow=self.term_flow.external_ref,
                    **kwargs)
                print(
                    'terminations.compute_unit_score UNTESTED for private fg archives!'
                )
                # res.set_scale(self.inbound_exchange_value)
        return res