...
 
Commits (3)
......@@ -39,7 +39,30 @@ from ...general.optimisation.elements import Quantity, DynamicConstraint
__docformat__ = "restructuredtext en"
class ElectricalToThermalConversionUnit(AssemblyUnit):
class ConversionUnit(AssemblyUnit):
"""
**Description**
Simple Conversion unit, inheriting from AssemblyUnit
**Attributes**
* time : TimeUnit describing the studied time period
* prod_units : list of the production units
* cons_units : list of the consumption units
* poles : dictionary of the poles of the conversion unit
"""
def __init__(self, time, name, prod_units=None, cons_units=None,
rev_units=None):
AssemblyUnit.__init__(self, time=time, name=name,
prod_units=prod_units,
cons_units=cons_units,
rev_units=rev_units)
class ElectricalToThermalConversionUnit(ConversionUnit):
"""
**Description**
......@@ -93,9 +116,9 @@ class ElectricalToThermalConversionUnit(AssemblyUnit):
time, name + '_elec_cons', p=p_in_elec,
energy_type='Electrical', verbose=verbose)
AssemblyUnit.__init__(self, time, name,
prod_units=[self.thermal_production_unit],
cons_units=[self.elec_consumption_unit])
ConversionUnit.__init__(self, time, name,
prod_units=[self.thermal_production_unit],
cons_units=[self.elec_consumption_unit])
if isinstance(elec_to_therm_ratio, (int, float)): # e2h_ratio is a
# mean value
......@@ -158,20 +181,133 @@ class ElectricalToThermalConversionUnit(AssemblyUnit):
"vector (list or dict) for each time period !")
class ElectricalConversionUnit(AssemblyUnit):
class ElectricalConversionUnit(ConversionUnit):
"""
**Description**
Electrical Conversion unit with an electricity consumption
and an electricity production
**Attributes**
* elec_production_unit : electricity production unit (electrical output)
* elec_consumption_unit : electricity consumption unit (electrical
input)
* conversion : Dynamic Constraint linking the electrical input to
the electrical output through the elec_to_elec ratio
"""
def __init__(self, time, name, pmin_in_elec=1e-5, pmax_in_elec=1e+5,
p_in_elec=None, pmin_out_elec=1e-5, pmax_out_elec=1e+5,
p_out_elec=None, elec_to_elec_ratio=1, operator=None):
"""
:param time: TimeUnit describing the studied time period
:param name: name of the electrical to elec conversion unit
:param pmin_in_elec: minimal incoming electrical power
:param pmax_in_elec: maximal incoming electrical power
:param p_in_elec: power input for the electrical consumption unit
:param pmin_out_elec: minimal power output (elec)
:param pmax_out_elec: maximal power output (elec)
:param p_out_elec: power output (elec)
:param elec_to_elec_ratio: electricity to elec ratio <=1
"""
if p_out_elec is None:
self.elec_production_unit = VariableProductionUnit(
time, name + '_elec_prod', energy_type='Electrical',
pmin=pmin_out_elec, pmax=pmax_out_elec)
else:
self.elec_production_unit = ProductionUnit(
time, name + '_elec_prod', energy_type='Electrical',
p=p_out_elec)
if p_in_elec is None:
self.elec_consumption_unit = VariableConsumptionUnit(
time, name + '_elec_cons', pmin=pmin_in_elec,
pmax=pmax_in_elec, energy_type='Electrical')
else:
self.elec_consumption_unit = ConsumptionUnit(
time, name, p=p_in_elec, energy_type='Electrical')
ConversionUnit.__init__(self, time, name,
prod_units=[self.elec_production_unit],
cons_units=[self.elec_consumption_unit])
if isinstance(elec_to_elec_ratio, (int, float)): # e2h_ratio is a
# mean value
if elec_to_elec_ratio <= 1:
self.conversion = DynamicConstraint(
exp_t='{0}_p[t] == {1} * {2}_p[t]'.format(
self.elec_production_unit.name,
elec_to_elec_ratio,
self.elec_consumption_unit.name),
t_range='for t in time.I', name='conversion', parent=self)
else:
raise ValueError('The elec_to_elec_ratio should be lower '
'than 1 (elec_production<elec_consumption)')
elif isinstance(elec_to_elec_ratio, list): # e2h_ratio is a list of
# values
if len(elec_to_elec_ratio) == self.time.LEN: # it must have the
# right size, i.e. the TimeUnit length.
if all(e <= 1 for e in elec_to_elec_ratio):
self.conversion = DynamicConstraint(
exp_t='{0}_p[t] == {1}[t] * {2}_p[t]'.format(
self.elec_production_unit.name,
elec_to_elec_ratio,
self.elec_consumption_unit.name),
t_range='for t in time.I', name='conversion',
parent=self)
else:
raise ValueError('The elec_to_elec_ratio values should be '
'lower than 1 (elec_production<elec_'
'consumption)')
else:
raise IndexError('The length of the elec_to_elec_ratio '
'vector should be of the same length as the '
'TimeUnit of the studied period')
elif isinstance(elec_to_elec_ratio, dict): # e2h_ratio is a dict of
# values
if len(elec_to_elec_ratio) == self.time.LEN:
if all(e <= 1 for e in elec_to_elec_ratio.values()):
self.conversion = DynamicConstraint(
exp_t='{0}_p[t] == {1}[t] * {2}_p[t]'.format(
self.elec_production_unit.name,
elec_to_elec_ratio,
self.elec_consumption_unit.name),
t_range='for t in time.I', name='conversion',
parent=self)
else:
raise ValueError('The elec_to_elec_ratio values should be '
'lower than 1 (elec_production<elec_'
'consumption)')
else:
raise IndexError('The length of the elec_to_elec_ratio '
'dictionary should be of the same length as '
'the TimeUnit of the studied period')
else:
raise TypeError(
"Electricity to elec ratio should be a mean value or a "
"vector (list or dict) for each time period !")
# Todo : make this class generic for conversion units ?
class ReversibleElectricalConversionUnit(ConversionUnit):
"""
**Description**
Electrical Conversion unit with an electricity consumption
and a electricity production
and an electricity production
**Attributes**
* elec_production_unit : elec production unit (elec output)
* elec_production_unit : electricity production unit (electrical output)
* elec_consumption_unit : electricity consumption unit (electrical
input)
* conversion : Dynamic Constraint linking the electrical input to
the elec output through the electrical to elec ratio
the electrical output through the elec_to_elec ratio
"""
......@@ -188,7 +324,6 @@ class ElectricalConversionUnit(AssemblyUnit):
:param pmax_out_elec: maximal power output (elec)
:param p_out_elec: power output (elec)
:param elec_to_elec_ratio: electricity to elec ratio <=1
:param operator : operator of the electrical to elec conversion unit
"""
if p_out_elec is None:
......@@ -208,9 +343,9 @@ class ElectricalConversionUnit(AssemblyUnit):
self.elec_consumption_unit = ConsumptionUnit(
time, name, p=p_in_elec, energy_type='Electrical')
AssemblyUnit.__init__(self, time, name,
prod_units=[self.elec_production_unit],
cons_units=[self.elec_consumption_unit])
ConversionUnit.__init__(self, time, name,
prod_units=[self.elec_production_unit],
cons_units=[self.elec_consumption_unit])
if isinstance(elec_to_elec_ratio, (int, float)): # e2h_ratio is a
# mean value
......@@ -271,7 +406,7 @@ class ElectricalConversionUnit(AssemblyUnit):
"vector (list or dict) for each time period !")
class HeatPump(AssemblyUnit):
class HeatPump(ConversionUnit):
"""
**Description**
......@@ -340,7 +475,7 @@ class HeatPump(AssemblyUnit):
self.elec_consumption_unit = ConsumptionUnit(
time, name, p=p_in_elec, energy_type='Electrical')
AssemblyUnit.__init__(self, time, name,
ConversionUnit.__init__(self, time, name,
prod_units=[self.thermal_production_unit],
cons_units=[self.thermal_consumption_unit,
self.elec_consumption_unit])
......
......@@ -1060,49 +1060,93 @@ class AssemblyUnit(OptObject):
# production units
self.cons_units = [] # Initialize an empty list for the consumption
# units
self.rev_units = [] # Initialize an empty list for the reversible
self.rev_units = [] # Initialize an empty list for the reversible
# units
self.poles = {} # Initialize an empty dictionary for the poles
# An assembly unit is created with at least a production unit and a
# consumption unit, and can integrate reversible unit.
if not prod_units:
raise IndexError('You have to fill at least a production unit.')
elif not isinstance(prod_units, list):
raise TypeError('prod_units should be a list.')
else:
for prod_unit in prod_units:
# prod_units should only contain ProductionUnit objects
if not isinstance(prod_unit, ProductionUnit):
raise TypeError('The elements in prod_units have to be the'
' type "ProductionUnit".')
# consumption unit,or a reversible unit.
# If a reversible unit is added, possibility to add (or not)
# production and/or consumption units.
if rev_units:
if not isinstance(rev_units, list):
raise TypeError('rev_units should be a list.')
else:
# if list or rev_units, adding rev_units
for rev_unit in rev_units:
# rev_units should only contain ReversibleUnit objects
if not isinstance(rev_unit, ReversibleUnit):
raise TypeError(
'The elements in rev_units have to be the'
' type "ReversibleUnit".')
else:
self._add_reversible_unit(rev_unit)
# if rev_units is not None, possibility to add prod_units
# (or not)
if prod_units is None:
pass
elif not isinstance(prod_units, list):
raise TypeError('prod_units should be a list')
else:
self._add_production_unit(prod_unit)
if not cons_units:
raise IndexError('You have to fill at least a consumption unit.')
elif not isinstance(cons_units, list):
raise TypeError('cons_units should be a list.')
else:
for cons_unit in cons_units:
# cons_units should only contain ConsumptionUnit
if not isinstance(cons_unit, ConsumptionUnit):
raise TypeError('The elements in cons_units have to be the'
' type "ConsumptionUnit".')
for prod_unit in prod_units:
# prod_units should only contain ProductionUnit objects
if not isinstance(prod_unit, ProductionUnit):
raise TypeError(
'The elements in prod_units have to be the'
' type "ProductionUnit".')
else:
self._add_production_unit(prod_unit)
# if rev_units is not None, possibility to add cons_units
# (or not)
if cons_units is None:
pass
elif not isinstance(cons_units, list):
raise TypeError('cons_units should be a list')
else:
self._add_consumption_unit(cons_unit)
# Assembly units can integrate reversible units.
if not (rev_units is None or isinstance(rev_units, list)):
raise TypeError('rev_units should be a list or None.')
for cons_unit in cons_units:
# cons_units should only contain ConsumptionUnit
# objects
if not isinstance(cons_unit, ConsumptionUnit):
raise TypeError(
'The elements in cons_units have to be the'
' type "ConsumptionUnit".')
else:
self._add_consumption_unit(cons_unit)
# If there is no reversible unit, the assembly unit needs at least
# one consumption and one production unit.
else:
for rev_unit in rev_units:
# rev_units should only contain ReversibleUnit objects
if not isinstance(rev_unit, ReversibleUnit):
raise TypeError('The elements in rev_units have to be the'
' type "ReversibleUnit".')
else:
self._add_reversible_unit(rev_unit)
if not prod_units:
raise IndexError(
'You have to fill at least a production unit.')
elif not isinstance(prod_units, list):
raise TypeError('prod_units should be a list.')
else:
for prod_unit in prod_units:
# prod_units should only contain ProductionUnit objects
if not isinstance(prod_unit, ProductionUnit):
raise TypeError(
'The elements in prod_units have to be the'
' type "ProductionUnit".')
else:
self._add_production_unit(prod_unit)
if not cons_units:
raise IndexError(
'You have to fill at least a consumption unit.')
elif not isinstance(cons_units, list):
raise TypeError('cons_units should be a list.')
else:
for cons_unit in cons_units:
# cons_units should only contain ConsumptionUnit
if not isinstance(cons_unit, ConsumptionUnit):
raise TypeError(
'The elements in cons_units have to be the'
' type "ConsumptionUnit".')
else:
self._add_consumption_unit(cons_unit)
def _add_production_unit(self, prod_unit):
"""
......