def connect(self, n1, n2, bidirectional=False, capacity=None): """Connect two nodes. Creates a flow and adds it to ``n1.outflows[resource]`` and ``n2.inflows[resource]``, if it does not already exist. Calling again makes no difference. The flow must be nonnegative. For bidirectional flows, use ``bidirectional=True``. Args: n1: The node the flow goes from. n2: The node the flow goes to. bidirectional (boolean, optional): Create a two-way flow? capacity (float, optional): The maximum amount that can flow between the nodes. Creates an upper bound ``ub=capacity`` on the flow :class:`~friendlysam.opt.Variable` for each index. """ edges = self._graph.edges() if not (n1, n2) in edges: self.add_part(n1) self.add_part(n2) self._graph.add_edge(n1, n2) name = 'flow({}-->{})'.format(n1, n2) with namespace(self): flow = VariableCollection(name, lb=0, ub=capacity) self._flows[(n1, n2)] = flow n1.outflows[self._resource].add(flow) n2.inflows[self._resource].add(flow) if bidirectional and (n2, n1) not in edges: self.connect(n2, n1)
def __init__(self, resource, capacity=None, maxchange=None, name=None): if name is not None: self.name = name self._resource = resource #:The maximum net inflow/outflow the storage #:can manage in one time step. In mathematical terms, it requires #:``abs(accumulation[resource](index)) <= maxchange`` for each ``index``. #:If ``None`` (the default), there is no limit. self.maxchange = maxchange with namespace(self): #:The volume of the storage at any time. Think of it as the #:volume at the **start** of a time step. To be concrete, #:``accumulation[resource](t) == volume(t+1) - volume(t)`` if #:the model is simply indexed in integers representing time. #:(And in more general terms, #:``accumulation[resource](idx) == volume(step_time(idx, 1)) - volume(idx)`` #:for any index ``idx``.) self.volume = VariableCollection('volume', lb=0., ub=capacity) self.accumulation[resource] = self._compute_accumulation self.constraints += self._maxchange_constraints