Beispiel #1
0
 def find_or_create_term(self, exchange, background=None):
     """
     Finds a fragment that terminates the given exchange
     :param exchange:
     :param background: [None] - any frag; [True] - background frag; [False] - foreground frag
     :return:
     """
     try:
         bg = next(f for f in self._archive.fragments(background=background)
                   if f.term.terminates(exchange))
         print('%% Found existing termination bg=%s for %s' %
               (background, exchange.termination))
     except StopIteration:
         if background is None:
             background = False
         print('@@ Creating new termination bg=%s for %s' %
               (background, exchange.termination))
         bg = ed.create_fragment(exchange.flow,
                                 comp_dir(exchange.direction),
                                 background=background)
         bg.terminate(self._archive.catalog_ref(exchange.process.origin,
                                                exchange.termination,
                                                entity_type='process'),
                      term_flow=exchange.flow)
         self._archive.add_entity_and_children(bg)
     return bg
Beispiel #2
0
 def test_create_term(self):
     frag = self._petro_frag()
     term = FlowTermination(frag, self.petro)
     self.assertIs(frag.flow, term.term_flow)
     self.assertEqual(comp_dir(frag.direction), term.direction)
     self.assertTrue(term.is_process)
     self.assertFalse(term.is_null)
     self.assertFalse(term.is_null)
     self.assertFalse(term.is_subfrag)
     self.assertFalse(term.is_bg)
     self.assertFalse(term.term_is_bg)
Beispiel #3
0
    def ref_flow(cls, parent, use_ev):
        """

        :param parent:
        :param use_ev: required to create reference flows from fragment refs
        :return:
        """
        fragment = GhostFragment(parent, parent.flow,
                                 comp_dir(parent.direction))
        term = FlowTermination.null(fragment)
        return cls(fragment, use_ev, 1.0, term, parent.is_conserved_parent)
Beispiel #4
0
    def fragment_from_fragment_flow(self, qi, ff):
        """
        :param qi: query interface for entity lookup
        :param ff: should be a decorated entry from self._ff
        :return:
        """
        if ff['FragmentFlowID'] in self._frags:
            self._print('Already loaded: %s' % ff['FragmentFlowID'])
            return
        flow = qi.get(ff['FlowUUID'])
        direction = direction_map(ff['DirectionID'])
        stage = self.stage(ff['FragmentStageID'])
        name = ff['Name']

        # create the fragment, with or without a parent
        if ff['ParentFragmentFlowID'] == '':
            # must be a reference flow
            frag_uuid = ff['Fragment']['FragmentUUID']
            frag = self._ed.create_fragment(
                flow,
                comp_dir(direction),
                uuid=frag_uuid,
                StageName=stage,
                Name=name,
                FragmentFlowID=ff['FragmentFlowID'],
                origin=self._origin)
            self._fragments[ff['Fragment']['FragmentID']] = frag
        else:
            try:
                parent = self._frags[ff['ParentFragmentFlowID']]
            except KeyError:
                self._print('Recursing to %s' % ff['ParentFragmentFlowID'])
                self.fragment_from_fragment_flow(
                    qi,
                    self.fragment_flow_by_index(ff['ParentFragmentFlowID']))
                parent = self._frags[ff['ParentFragmentFlowID']]

            frag_uuid = ff['FragmentUUID']
            frag = self._ed.create_fragment(
                flow,
                direction,
                uuid=frag_uuid,
                Name=name,
                StageName=stage,
                parent=parent,
                FragmentFlowID=ff['FragmentFlowID'])

        # save the fragment
        if frag is None:
            raise TypeError
        self._frags[ff['FragmentFlowID']] = frag
Beispiel #5
0
 def terminates(self, exchange):
     """
     Returns True if the exchange's termination matches the term's term_node, and the flows also match, and the
     directions are complementary.
     If the exchange does not specify a termination, returns True if the flows match and directions are comp.
     :param exchange:
     :return:
     """
     if self.term_flow.match(exchange.flow) and self.direction == comp_dir(
             exchange.direction):
         if exchange.termination is None:
             return True
         else:
             if self.is_null:
                 return False
             if self.term_node.entity_type != 'process':
                 return False
             if exchange.termination == self._term.external_ref:
                 return True
     return False
Beispiel #6
0
 def serialize(self, save_unit_scores=False):
     if self.is_null:
         return {}
     j = {
         'origin': self._term.origin,
         'externalId': self._term.external_ref
     }
     if self.term_flow != self._parent.flow:
         if self.term_flow.origin == self.term_node.origin:
             j['termFlow'] = self.term_flow.external_ref
         else:
             j['termFlow'] = {
                 'origin': self.term_flow.origin,
                 'externalId': self.term_flow.external_ref
             }
     if self.direction != comp_dir(self._parent.direction):
         j['direction'] = self.direction
     if self._descend is False:
         j['descend'] = False
     if self._parent.is_background and save_unit_scores and len(
             self._score_cache) > 0:
         j['scoreCache'] = self._serialize_score_cache()
     return j
Beispiel #7
0
def group_ios(parent, ffs, include_ref_flow=True):
    """
    Utility function for dealing with a traversal result (list of FragmentFlows)
    Creates a list of cutoff flows from the inputs and outputs from a fragment traversal.
    ios is a list of FragmentFlows
    :param parent: the node generating the cutoffs
    :param ffs: a list of fragment flows resulting from a traversal of the parent
    :param include_ref_flow: [True] whether to include the reference fragment and adjust for autoconsumption
    :return: [list of grouped IO flows], [list of internal non-null flows]
    """
    out = defaultdict(float)
    internal = []
    external = []
    for ff in ffs:
        if ff.term.is_null:
            # accumulate IO flows under the convention that inflows are positive, outflows are negative
            if ff.fragment.direction == 'Input':
                magnitude = ff.magnitude
            else:
                magnitude = -ff.magnitude
            out[ff.fragment.flow] += magnitude
        else:
            internal.append(ff)

    # now deal with reference flow-- trivial fragment should wind up with two equal-and-opposite [pass-through] flows
    if include_ref_flow:
        ref_frag = parent.top()
        ref_mag = ffs[0].magnitude
        if ref_frag.flow in out:  # either pass through or autoconsumption
            ref_frag.dbg_print('either pass through or autoconsumption')
            val = out[ref_frag.flow]
            if val < 0:
                auto_dirn = 'Output'
            else:
                auto_dirn = 'Input'
            """
            Default is autoconsumption, which is fine as long as 
             (a) directions are complementary [meaning equal since ref flow dirn is w.r.t. parent] and 
             (b) magnitude of autoconsumption is smaller
            """
            if auto_dirn == ref_frag.direction:
                if abs(val) < ref_mag:
                    ref_frag.dbg_print('autoconsumption %g %g' %
                                       (val, ref_mag))
                    # autoconsumption, the direction sense of the autoconsumed flow should switch
                    if auto_dirn == 'Output':
                        out[ref_frag.flow] += ref_mag
                    else:
                        out[ref_frag.flow] -= ref_mag

                else:
                    ref_frag.dbg_print('pass thru no effect %g %g' %
                                       (val, ref_mag))
                    # pass-thru: pre-initialize external with the reference flow, having the opposite direction
                    external.append(
                        FragmentFlow.cutoff(parent, ref_frag.flow,
                                            comp_dir(auto_dirn), ref_mag))
            else:
                ref_frag.dbg_print('cumulation! %g %g' % (val, ref_mag))
                # cumulation: the directions are both the same... should they be accumulated?  not handled
                raise CumulatingFlows('%s' % parent)
                # external.append(FragmentFlow.cutoff(parent, ref_frag.flow, auto_dirn, ref_mag))
        else:
            ref_frag.dbg_print('uncomplicated ref flow')
            # no autoconsumption or pass-through, but we still want the ref flow to show up in the inventory
            external.append(
                FragmentFlow.cutoff(parent, ref_frag.flow,
                                    comp_dir(ref_frag.direction), ref_mag))

    for flow, value in out.items():
        if value < 0:
            direction = 'Output'
        else:
            direction = 'Input'
        external.append(
            FragmentFlow.cutoff(parent, flow, direction, abs(value)))

    return external, internal
Beispiel #8
0
 def test_fg(self):
     frag = self._frag_with_child()
     z = next(frag.child_flows)
     self.assertTrue(z.term.is_fg)
     self.assertIs(z.flow, z.term.term_flow)
     self.assertEqual(z.direction, comp_dir(z.term.direction))
Beispiel #9
0
 def direction(self, value):
     if value is None:
         value = comp_dir(self._parent.direction)
     self._direction = check_direction(value)