Beispiel #1
0
    def __init__(self, friendly_name, pwr, efficiency_factor, thermal_process,
                 read_params, write_params):
        """
        __init__(self, friendly_name, pwr, efficiency_factor, thermal_process, readparamlist, writeparamlist)

        This :class:`Actor` can either heat of cool a :class:`gridsim.thermal.core.ThermalProcess`.

        :param friendly_name: friendly name for the AbstractElectricalCPSElement
        :param pwr: power of the heater/cooler system
        :param efficiency_factor: efficiency factor of the system
        :param thermal_process: thermal process of the system
        :param read_params: read parameter of the actor
        :param write_params: write parameter of the actor
        """
        super(ElectroThermalHeaterCooler, self).__init__(friendly_name)

        self.read_params = read_params
        self.write_params = write_params

        self._efficiency_factor = units.value(efficiency_factor)

        self._thermal_process = thermal_process

        self.power = units.value(pwr, units.watt)

        self._on = False
Beispiel #2
0
    def __init__(self, friendly_name, mean_power, standard_deviation):
        """
        __init__(self, friendly_name, mean_power, standard_deviation)

        This class provides a Consuming-Producing-Storing element having a
        random behavior. The consecutive consumed or produced power values
        are IID (Independently and Identically Distributed). The distribution
        is Gaussian.

        At initialization, the `mean_power` and 'standard_distribution' are
        provided beside the element `friendly_name`. If `mean_power` is
        positive, the element is in the mean a consumer. If it is negative,
        the element is in the mean a producer.

        :param friendly_name: Friendly name for the element.
            Should be unique within the simulation module.
        :type friendly_name: str

        :param mean_power: The mean value of the Gaussian distributed power.
        :type mean_power: power, see :mod:`gridsim.unit`

        :param standard_deviation: The standard deviation of the Gaussian
            distributed power.
        :type standard_deviation: power, see :mod:`gridsim.unit`

        """
        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(mean_power, (int, float)):
            mean_power = units.value(units.to_si(mean_power))
        if not isinstance(standard_deviation, (int, float)):
            standard_deviation = units.value(units.to_si(standard_deviation))

        super(GaussianRandomElectricalCPSElement, self).__init__(friendly_name)
        self._mean_power = mean_power
        self._standard_deviation = standard_deviation
Beispiel #3
0
    def test_plot_recorder(self):

        recorder = PlotRecorder('power', units.minute, units.watt)

        recorder.on_simulation_reset(['foo', 'bar'])

        delta_time = units.value(1*units.minute, units.second)
        recorder.on_simulation_step(delta_time)
        recorder.on_observed_value('foo', delta_time, 14.2*units.watt)
        recorder.on_observed_value('bar', delta_time, 12*units.watt)

        delta_time = units.value(2*units.minute, units.second)
        recorder.on_simulation_step(delta_time)
        recorder.on_observed_value('foo', delta_time, 12*units.watt)
        recorder.on_observed_value('bar', delta_time, 12.1*units.watt)

        delta_time = units.value(3*units.minute, units.second)
        recorder.on_simulation_step(delta_time)
        recorder.on_observed_value('foo', delta_time, 16.1*units.watt)
        recorder.on_observed_value('bar', delta_time, 14.2*units.watt)

        delta_time = units.value(4*units.minute, units.second)
        recorder.on_simulation_step(delta_time)
        recorder.on_observed_value('foo', delta_time, 18.4*units.watt)
        recorder.on_observed_value('bar', delta_time, 9*units.watt)

        self.assertEqual(recorder.x_unit(), 'minute')
        self.assertEqual(recorder.x_values(), [1.0, 2.0, 3.0, 4.0])
        self.assertDictEqual(recorder.y_values(),
                             {'bar': [12, 12.1, 14.2, 9],
                              'foo': [14.2, 12, 16.1, 18.4]})
        self.assertEqual(recorder.y_unit(), 'watt')
Beispiel #4
0
    def __init__(self, friendly_name, k_factor, X, R=0):
        """
        __init__(self, friendly_name, k_factor, X, R=0)

        Class for representing a transformer and/or a phase shifter in an
        electrical network. Its parameters are
        linked to the usual transformer graphical representation below::

                                                             1:K
                          R              jX                 -   -
                    +-----------+   +-----------+        /   / \   \\
            o--->---|           |---|           |-------|---|--|---|------->---o
                    +-----------+   +-----------+       \   \ /   /
                                                           -   -

        While the transformer changes the voltage amplitude, the phase shifter
        changes the voltage phase. Accepting a complex ``K_factor`` parameter,
        the :class:`.ElectricalGenTransformer` is a common representation for a
        transformer and a phase shifter.

        At initialization, in addition to the line ``friendly_name``, the
        ``K-factor``, the reactance (``X``), and the resistance (``R``) have to be
        given. ``R`` defaults to zero.

        :param friendly_name: Friendly name for the transformer or phase
            shifter. Should be unique within the simulation module, i.e.
            different for example from the friendly name of a bus
        :type friendly_name: str

        :param k_factor: Transformer or phase shifter K-factor.
        :type k_factor: complex

        :param X: Transformer or phase shifter reactance.
        :type X: ohm, see :mod:`gridsim.unit`

        :param R: Transformer or phase shifter resistance.
        :type R: ohm, see :mod:`gridsim.unit`

        """

        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(X, (int, float)):
            X = units.value(units.to_si(X))
        if not isinstance(R, (int, float)):
            R = units.value(units.to_si(R))

        # super constructor needs units as it is a "public" function
        super(ElectricalGenTransformer,
              self).__init__(friendly_name, X * units.ohm, R * units.ohm)

        if k_factor == 0:
            raise RuntimeError(
                'Transformer or phase shifter K-factor can not be null')

        self.k_factor = k_factor
        """
Beispiel #5
0
    def __init__(self, friendly_name, k_factor, X, R=0):
        """
        __init__(self, friendly_name, k_factor, X, R=0)

        Class for representing a transformer and/or a phase shifter in an
        electrical network. Its parameters are
        linked to the usual transformer graphical representation below::

                                                             1:K
                          R              jX                 -   -
                    +-----------+   +-----------+        /   / \   \\
            o--->---|           |---|           |-------|---|--|---|------->---o
                    +-----------+   +-----------+       \   \ /   /
                                                           -   -

        While the transformer changes the voltage amplitude, the phase shifter
        changes the voltage phase. Accepting a complex ``K_factor`` parameter,
        the :class:`.ElectricalGenTransformer` is a common representation for a
        transformer and a phase shifter.

        At initialization, in addition to the line ``friendly_name``, the
        ``K-factor``, the reactance (``X``), and the resistance (``R``) have to be
        given. ``R`` defaults to zero.

        :param friendly_name: Friendly name for the transformer or phase
            shifter. Should be unique within the simulation module, i.e.
            different for example from the friendly name of a bus
        :type friendly_name: str

        :param k_factor: Transformer or phase shifter K-factor.
        :type k_factor: complex

        :param X: Transformer or phase shifter reactance.
        :type X: ohm, see :mod:`gridsim.unit`

        :param R: Transformer or phase shifter resistance.
        :type R: ohm, see :mod:`gridsim.unit`

        """

        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(X, (int, float)):
            X = units.value(units.to_si(X))
        if not isinstance(R, (int, float)):
            R = units.value(units.to_si(R))

        # super constructor needs units as it is a "public" function
        super(ElectricalGenTransformer, self).__init__(friendly_name, X*units.ohm, R*units.ohm)

        if k_factor == 0:
            raise RuntimeError(
                'Transformer or phase shifter K-factor can not be null')

        self.k_factor = k_factor
        """
Beispiel #6
0
    def __init__(self, friendly_name, pwr, efficiency_factor, thermal_process):

        super(ElectroThermalHeaterCooler, self).__init__(friendly_name)

        self._efficiency_factor = units.value(efficiency_factor)

        self._thermal_process = thermal_process

        self._power = units.value(pwr, units.watt)

        self._on = False
        """
Beispiel #7
0
    def __init__(self, friendly_name, pwr, efficiency_factor, thermal_process):

        super(ElectroThermalHeaterCooler, self).__init__(friendly_name)

        self._efficiency_factor = units.value(efficiency_factor)

        self._thermal_process = thermal_process

        self.power = units.value(pwr, units.watt)

        self._on = False
        """
Beispiel #8
0
    def test_value(self):
        m = 3000*units.metre

        g = 10*units.gram
        kg = 0.01*units.kg

        self.assertEqual(units.value(g), 10)
        self.assertEqual(units.value(kg), 0.01)
        self.assertEqual(units.value(kg*m), 30.)

        self.assertEqual(units.value(g, units.decagram), 1.)
        self.assertEqual(units.value(m, units.Mm), 0.003)  # Megametre
Beispiel #9
0
    def test_si(self):

        km = 56*units.kilometre

        kg = 0.12*units.kilogram

        kwh = 43.1*units.kilowatthour

        self.assertEqual(units.value(units.to_si(km)), 56000)
        self.assertEqual(units.value(units.to_si(kg)), 0.12)
        self.assertEqual(units.value(units.to_si(kg*km)), 6720)
        self.assertEqual(units.value(units.to_si(kwh)), 155160000)  # joule
        self.assertRaises(AttributeError, self._value_si, 7)
        self.assertRaises(AttributeError, self._value_si, "85.2")
Beispiel #10
0
    def __init__(self, friendly_name, start_energy, max_energy, power,
                 read_params, write_params):
        """
        __init__(self,friendly_name,start_energy,max_energy,power,read_params,write_params)

        This :class:`Actor` simulates the behavior of a battery. The charge and discharge is considered equal.
        The battery reach a max energy when the battery is full and the empty state when the battery is low.

        .. note :: On consumption, the power is considered positive.
                   On injection, the power is considered negative.

        :param friendly_name: friendly name for the :class:`gridsim.core.AbstractSimulationElement`
        :param start_energy: amount of energy to start with
        :param max_energy: max energy of the battery, the battery will stop storing
        :param power: power rate for the storage and discharge
        :param read_params: read parameter for the actor
        :param write_params: write parameter for the actor
        """
        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(start_energy, (int, float)):
            start_energy = units.value(units.to_si(start_energy))
        if not isinstance(max_energy, (int, float)):
            max_energy = units.value(units.to_si(max_energy))
        if not isinstance(power, (int, float)):
            power = units.value(units.to_si(power))

        Actor.__init__(self)
        AbstractSimulationElement.__init__(self, friendly_name)
        CyberPhysicalModuleListener.__init__(self)

        self.read_params = read_params
        self.write_params = write_params

        self._store = True
        self._over_load = False
        self._empty = False
        if start_energy < max_energy:
            self._energy = start_energy
            self.energy = start_energy
        else:
            self._energy = max_energy
            self.energy = max_energy

        self._max_energy = max_energy
        self._power = power

        # the simulation runs with second, this is the conversion factor
        self._energy_seconds_to_hours = 3600.0
Beispiel #11
0
    def __init__(self, friendly_name, power):
        """
        __init__(self, friendly_name, power)

        This class provides the simplest Consuming-Producing-Storing element
        having a constant behavior.

        At initialization, the consumed or produced constant `power` has to
        be provided beside the element `friendly_name`. Power is positive, if
        consumed, negative, if produced. With the 'calculate' method the
        energy consumed or produced during the simulation step is calculated
        from the constant power value.

        :param friendly_name: Friendly name for the element. Should be unique
            within the simulation module.
        :type friendly_name: str

        :param power: The constant consumed (if positive) or produced
            (if negative) power.
        :type power: power, see :mod:`gridsim.unit`

        """
        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(power, (int, float)):
            power = units.value(units.to_si(power))
        super(ConstantElectricalCPSElement, self).__init__(friendly_name)
        self.power = power
Beispiel #12
0
    def __init__(self, friendly_name, temperature, position=Position()):
        """
        __init__(self, friendly_name, temperature, position=Position())

        This is a special thermal process with an infinite thermal capacity
        which results that the temperature of the process is constant,
        independent how much energy is taken from or given to the process.

        :param friendly_name: Friendly name to give to the process.
        :type friendly_name: str, unicode
        :param temperature: The (constant) temperature in degrees celsius.
        :type temperature: temperature
        :param position: The position of the :class:`.ThermalProcess`.
        :type position: :class:`Position`
        """

        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(temperature, (int, float)):
            temperature = units.value(units.to_si(temperature))

        # super constructor needs units as it is a "public" function
        super(ConstantTemperatureProcess, self).__init__(
            friendly_name,
            float('inf')*units.heat_capacity, temperature*units.kelvin,
            position=position)
Beispiel #13
0
    def __init__(self, friendly_name, cycle_delta_time, power_values,
                 cycle_start_time=0):
        """
        __init__(self, friendly_name, cycle_delta_time, power_values, cycle_start_time=0*units.second)

        This class provides a cyclic Consuming-Producing-Storing element for
        which the consumed or produced power values may be updated. Update
        will take place at next cycle start.

        :param friendly_name: Friendly name for the element.
            Should be unique within the simulation module.
        :type friendly_name: str

        :param cycle_delta_time: cycle time resolution value in seconds.
        :type cycle_delta_time: int

        :param power_values: power values consumed or produced during a cycle.
        :type power_values: 1-D numpy array of float

        :param cycle_start_time: cycle start time in seconds. Defaults to 0.
        :type cycle_start_time: int

        """
        # HACK: when object is constructed with *args or **kwargs
        if power_values.dtype is not (int, float):
            power_values = units.value(units.to_si(power_values))

        super(UpdatableCyclicElectricalCPSElement, self).\
            __init__(friendly_name, cycle_delta_time,
                     power_values, cycle_start_time)
        self._new_power_values = power_values
        self._update_done = True
Beispiel #14
0
    def __init__(self, friendly_name, start_energy, max_energy, power, read_params, write_params):
        """
        __init__(self,friendly_name,start_energy,max_energy,power,read_params,write_params)

        This :class:`Actor` simulates the behavior of a battery. The charge and discharge is considered equal.
        The battery reach a max energy when the battery is full and the empty state when the battery is low.

        .. note :: On consumption, the power is considered positive.
                   On injection, the power is considered negative.

        :param friendly_name: friendly name for the :class:`gridsim.core.AbstractSimulationElement`
        :param start_energy: amount of energy to start with
        :param max_energy: max energy of the battery, the battery will stop storing
        :param power: power rate for the storage and discharge
        :param read_params: read parameter for the actor
        :param write_params: write parameter for the actor
        """
        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(start_energy, (int, float)):
            start_energy = units.value(units.to_si(start_energy))
        if not isinstance(max_energy, (int, float)):
            max_energy = units.value(units.to_si(max_energy))
        if not isinstance(power, (int, float)):
            power = units.value(units.to_si(power))

        Actor.__init__(self)
        AbstractSimulationElement.__init__(self, friendly_name)
        CyberPhysicalModuleListener.__init__(self)

        self.read_params = read_params
        self.write_params = write_params

        self._store = True
        self._over_load = False
        self._empty = False
        if start_energy < max_energy:
            self._energy = start_energy
            self.energy = start_energy
        else:
            self._energy = max_energy
            self.energy = max_energy

        self._max_energy = max_energy
        self._power = power

        # the simulation runs with second, this is the conversion factor
        self._energy_seconds_to_hours = 3600.0
Beispiel #15
0
    def calculate(self, time, delta_time):

        self._time_series.set_time(time)

        unit_delta_time = delta_time

        volume = units.to_si(units(self._time_series.volume, units.litre))*delta_time/units.value(self._time_converter(1), units.second)

        # thermal losses when used [W/K]
        on_losses = units.value(volume)*units.value(Water().weight)*units.value(Water().thermal_capacity)/unit_delta_time

        # total thermal losses [W/K]
        losses = self._off_losses + on_losses

        self._temperature = self._temperature + \
            ((unit_delta_time*losses/self._cb)*(self._temperature_in-self._temperature)) +\
            (unit_delta_time/self._cb)*self.power
Beispiel #16
0
    def test_simulation_time(self):

        total_time = 1*units.hour
        delta_time = 1*units.second

        sim = Simulator()
        el = sim.time_test.add(TimeTestElement('test'))
        sim.reset()
        sim.run(total_time, delta_time)

        self.assertEqual(el.val, units.value(total_time, units.second))
        self.assertEqual(el.iter, 3601)  # from 0 to 3601 included
Beispiel #17
0
    def __init__(self, friendly_name, X, R=0 * units.ohm):
        """
        __init__(self, friendly_name, X, R=0*units.ohm)

        This class is the base for all electrical element that can be placed
        on a network branch, e.g. transmission lines, transformers,
        phase shifters,... It is based on the general
        :class:`.AbstractElectricalElement` class. At initialization the user
        has to give the two-port ``friendly_name``.

        :param friendly_name: Friendly name for the element.
            Should be unique within the simulation module.
        :type friendly_name: str

        :param X: reactance of the element
        :type X: ohm, see :mod:`gridsim.unit`

        :param R: resistance of the element
        :type R: ohm, see :mod:`gridsim.unit`

        """
        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(X, (int, float)):
            X = units.value(units.to_si(X))
        if not isinstance(R, (int, float)):
            R = units.value(units.to_si(R))

        super(AbstractElectricalTwoPort, self).__init__(friendly_name, )

        if X <= 0:
            raise RuntimeError('Line reactance X cannot be negative or null')
        if R < 0:
            raise RuntimeError('Line resistance R can not be negative number')

        self.X = X
        """
        The reactance.
        """
        self.R = R
        """
Beispiel #18
0
    def __init__(self, friendly_name, X, R=0*units.ohm):
        """
        __init__(self, friendly_name, X, R=0*units.ohm)

        This class is the base for all electrical element that can be placed
        on a network branch, e.g. transmission lines, transformers,
        phase shifters,... It is based on the general
        :class:`.AbstractElectricalElement` class. At initialization the user
        has to give the two-port ``friendly_name``.

        :param friendly_name: Friendly name for the element.
            Should be unique within the simulation module.
        :type friendly_name: str

        :param X: reactance of the element
        :type X: ohm, see :mod:`gridsim.unit`

        :param R: resistance of the element
        :type R: ohm, see :mod:`gridsim.unit`

        """
        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(X, (int, float)):
            X = units.value(units.to_si(X))
        if not isinstance(R, (int, float)):
            R = units.value(units.to_si(R))

        super(AbstractElectricalTwoPort, self).__init__(friendly_name, )

        if X <= 0:
            raise RuntimeError('Line reactance X cannot be negative or null')
        if R < 0:
            raise RuntimeError('Line resistance R can not be negative number')

        self.X = X
        """
        The reactance.
        """
        self.R = R
        """
Beispiel #19
0
    def calculate(self, time, delta_time):
        """
        Calculates the energy consumed or produced by the element during the
        simulation step.

        :param time: The actual time of the simulator in seconds.
        :type time: time, see :mod:`gridsim.unit`
        :param delta_time: The delta time for which the calculation has to be
            done in seconds.
        :type delta_time: time, see :mod:`gridsim.unit`
        """
        self._time_series.set_time(time)
        self._internal_delta_energy = units.value(self._time_series.power) * delta_time
Beispiel #20
0
    def calculate(self, time, delta_time):
        self._time_series.set_time(time)
        unit_delta_time = delta_time

        if self._time_converter == None:
            volume = units.to_si(units(self._time_series.volume,
                                       units.litre)) * delta_time
        else:
            volume = units.to_si(
                units(self._time_series.volume,
                      units.litre)) * delta_time / units.value(
                          self._time_converter(1), units.second)

        # thermal losses when used [W/K]
        on_losses = units.value(volume) * units.value(
            Water().weight) * units.value(
                Water().thermal_capacity) / unit_delta_time

        # total thermal losses [W/K]
        losses = self._off_losses + on_losses

        self._temperature = self._temperature + \
                            ((unit_delta_time * losses / self._cb) * (self._temperature_in - self._temperature)) + \
                            (unit_delta_time / self._cb) * self.power
Beispiel #21
0
    def calculate(self, time, delta_time):
        """
        calculate(self, time, delta_time)

        Calculates the temperature of the element during the simulation step.

        :param time: The actual time of the simulator.
        :type time: float in second

        :param delta_time: The delta time for which the calculation has to be
            done.
        :type delta_time: float in second

        .. seealso:: :func:`gridsim.timeseries.TimeSeriesObject.set_time`
        """
        self._time_series.set_time(time)
        # the parent (ThermalProcess) already has a 'temperature' in
        # its local params
        self.temperature = units.value(self._time_series.temperature)
Beispiel #22
0
    def __init__(self, friendly_name, cycle_delta_time, power_values,
                 cycle_start_time=0):
        """
        __init__(self, friendly_name, cycle_delta_time, power_values, cycle_start_time=0)

        This class provides a Consuming-Producing-Storing element having a
        cyclic behavior.

        At initialization, beside the element `friendly_name`, the cycle time
        resolution `cycle_delta_time`, the cycle sequence of `power_values`,
        and the `cycle_start_time` have to be given.

        :param friendly_name: Friendly name for the element. Should be unique
            within the simulation module.
        :type friendly_name: str

        :param cycle_delta_time: cycle time resolution value in seconds.
        :type cycle_delta_time: int

        :param power_values: power values consumed or produced during a cycle.
        :type power_values: 1-D numpy array of power

        :param cycle_start_time: cycle start time in seconds. Defaults to 0.
        :type cycle_start_time: int

        """
        super(CyclicElectricalCPSElement, self).__init__(friendly_name)

        # HACK: when object is constructed with *args or **kwargs
        if power_values.dtype is not (int, float):
            power_values = units.value(units.to_si(power_values))

        if power_values.dtype != float:
            raise TypeError("'power_values' has to be an array of floats.")
        if len(power_values.shape) != 1:
            raise RuntimeError(
                "'power_values' has to be a one-dimensional array")

        self._cycle_delta_time = cycle_delta_time
        self._power_values = power_values
        self._cycle_length = len(power_values)
        self._cycle_start_time = cycle_start_time
Beispiel #23
0
 def __getattr__(self, item):
     return units.value(getattr(self._time_series, item))
Beispiel #24
0
 def _value_si(self, a):
     return units.value(units.to_si(a))
Beispiel #25
0
    def __init__(self, friendly_name, length, X, R=0, B=0):
        """
        __init__(self, friendly_name, length, X, R=0, B=0)

        Class for representing a transmission line in an electrical network.
        Its parameters are linked to the
        transmission line PI model represented graphically below::

                                  R              jX
                            +-----------+   +-----------+
            o--->---o-------|           |---|           |-------o--->---o
                    |       +-----------+   +-----------+       |
                    |                                           |
                  -----  jB/2                                 -----  jB/2
                  -----                                       -----
                    |                                           |
                    |                                           |
                   ---                                         ---

        At initialization, in addition to the line ``friendly_name``,
        the line length, the line reactance (``X``), line resistance (``R``) and
        line charging (B) have to be given. ``R`` and ``B`` default to zero.

        :param friendly_name: Friendly name for the line. Should be unique
            within the simulation module, i.e. different for example from the
            friendly name of a bus.
        :type friendly_name: str

        :param length: Line length.
        :type length: length, see :mod:`gridsim.unit`

        :param X: Line reactance.
        :type X: ohm, see :mod:`gridsim.unit`

        :param R: Line resistance.
        :type R: ohm, see :mod:`gridsim.unit`

        :param B: Line charging.
        :type B: siemens, see :mod:`gridsim.unit`
        """

        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(length, (int, float)):
            length = units.value(units.to_si(length))
        if not isinstance(X, (int, float)):
            X = units.value(units.to_si(X))
        if not isinstance(R, (int, float)):
            R = units.value(units.to_si(R))
        if not isinstance(B, (int, float)):
            B = units.value(units.to_si(B))

        # super constructor needs units as it is a "public" function
        super(ElectricalTransmissionLine, self).__init__(friendly_name, X*units.ohm, R*units.ohm)

        if length <= 0:
            raise RuntimeError('Length has to be a strictly positive number')
        if B < 0:
            raise RuntimeError('Line charging B can not be negative number')

        self.length = length
        """
        The transmission line length.
        """
        self.B = B
        """
Beispiel #26
0
    def __init__(self, friendly_name,
                 thermal_capacity, initial_temperature, mass=1,
                 position=Position()):
        """
        __init__(self, friendly_name, thermal_capacity, initial_temperature, mass=1*units.kilogram, position=Position()):

        The very basic element of a thermal simulation. A thermal process
        represents a closed thermal envelope like a room or a amount of
        matter which has an uniform thermal capacity and and stores an amount of
        thermal energy resulting in a temperature. Those thermal processes
        can be coupled by :class:`ThermalCoupling` element.

        :param friendly_name: The name to give to the thermal process.
        :type friendly_name: str

        :param thermal_capacity: The thermal capacity of the process.
            See :class:`.Material`.
        :type thermal_capacity: heat_capacity, see :mod:`gridsim.unit`

        :param initial_temperature: The initial temperature of the process in
            degrees.
        :type initial_temperature: kelvin, see :mod:`gridsim.unit`

        :param mass: the mass of the element
        :type mass: mass, see :mod:`gridsim.unit`

        :param position: The position of the process.
        :type position: :class:`.Position`
        """

        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(thermal_capacity, (int, float)):
            thermal_capacity = units.value(units.to_si(thermal_capacity))
        if not isinstance(initial_temperature, (int, float)):
            initial_temperature = units.value(units.to_si(initial_temperature))
        if not isinstance(mass, (int, float)):
            mass = units.value(units.to_si(mass))

        super(ThermalProcess, self).__init__(friendly_name, position)

        self._initial_temperature = initial_temperature
        """
        The initial temperature of the process. Need for reset.
        """

        self._mass = mass
        """
        The mass of the thermal process.
        """

        self._thermal_capacity = thermal_capacity
        """
        The thermal capacity of the thermal process.
        """

        self.temperature = self._initial_temperature
        """
        The temperature of the process.
        """

        self._internal_thermal_energy = self._initial_temperature * \
            self._thermal_capacity * self._mass
        """
        The internal thermal energy stored inside the thermal process.
        """

        self.thermal_energy = self._internal_thermal_energy
        """
Beispiel #27
0
    def __init__(self, friendly_name, thermal_conductivity,
                 from_process, to_process,
                 contact_area=1, thickness=1):
        """
        __init__(self, friendly_name, thermal_conductivity, from_process, to_process, contact_area=1*units.metre**2, thickness=1*units.metre)

        A thermal coupling connects two thermal processes allowing them to
        exchange thermal energy.

        :param friendly_name: The friendly name to identify the element.
        :type friendly_name: str

        :param thermal_conductivity: The thermal conductivity of the thermal
            element.
        :type thermal_conductivity: thermal conductivity, see :mod:`gridsim.unit`

        :param from_process: The first process coupled
            process.
        :type from_process: :class:`ThermalProcess`

        :param to_process: The second process coupled process.
        :type to_process: :class:`ThermalProcess`

        :param contact_area: The size of the contact area
            process.
        :type contact_area: square_meter, see :mod:`gridsim.unit`

        :param thickness: the thickness of the contact area
            process.
        :type thickness: meter, see :mod:`gridsim.unit`
        """

        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(thermal_conductivity, (int, float)):
            thermal_conductivity = units.value(units.to_si(thermal_conductivity))
        if not isinstance(contact_area, (int, float)):
            contact_area = units.value(units.to_si(contact_area))
        if not isinstance(thickness, (int, float)):
            thickness = units.value(units.to_si(thickness))

        super(ThermalCoupling, self).__init__(friendly_name)

        self.from_process = from_process
        self.to_process = to_process

        self.thermal_conductivity = thermal_conductivity
        """
        The thermal conductivity of the coupling in W/K.
        """
        self._contact_area = contact_area
        """
        The size of the contact area between the two :class:`ThermalProcess`
        """
        self._thickness = thickness
        """
        The thickness of the material between the two :class:`ThermalProcess`
        """
        self._delta_energy = 0
        """
        The energy variation
        """
        self.power = None
        """
Beispiel #28
0
    def __init__(self, friendly_name, target_temperature, hysteresis,
                 thermal_process, subject, attribute,
                 on_value=True, off_value=False, position=Position()):
        """
        A thermostat controller. This class measures the temperature of a
        thermal process (typically a room) and controls ANY attribute of any
        AbstractSimulationElement depending the measured temperature, the given
        target_temperature and the hysteresis.

        :param: friendly_name: User friendly name to give to the element.
        :type friendly_name: str

        :param: target_temperature: The temperature to try to maintain inside
            the target ThermalProcess.
        :type: target_temperature: temperature see :mod:`gridsim.unit`

        :param: hysteresis: The +- hysteresis in order to avoid to fast on/off
            switching.
        :type: hysteresis: delta temperature see :mod:`gridsim.unit`

        :param: thermal_process: The reference to the thermal process to
            observe.
        :type: thermal_process: :class:`.ThermalProcess`

        :param: subject: Reference to the object of which is attribute has to be
            changed depending on the temperature.
        :type: object

        :param: attribute: The name of the attribute to control as string.
        :type: str

        :param: on_value: The value to set for the attribute in order to turn
            the device "on".
        :type: on_value: any

        :param: off_on_value: The value to set for the attribute in order to
            turn the device "off".
        :type: off_value: any

        :param position: The position of the thermal element.
            Defaults to [0,0,0].
        :type position: :class:`Position`
        """
        super(Thermostat, self).__init__(friendly_name, position)
        self.target_temperature = units.value(target_temperature, units.kelvin)
        """
        The temperature to try to retain inside the observer thermal process by
        conducting an electrothermal element.
        """

        self.hysteresis = units.value(hysteresis, units.kelvin)
        """
        The +- hysteresis applied to the temperature measure in order to avoid
        to fast on/off switching.
        """

        if not hasattr(thermal_process, 'temperature'):
            raise TypeError('thermal_process')
        self.thermal_process = thermal_process
        """
        The reference to the thermal process to observe and read the
        temperature from.
        """

        self.subject = subject
        """
        The reference to the element to control.
        """

        self.attribute = attribute
        """
        Name of the attribute to control.
        """

        self.on_value = on_value
        """
        Value to set in order to turn the element on.
        """

        self.off_value = off_value
        """
        Value to set in order to turn the element off.
        """

        self._output_value = off_value
Beispiel #29
0
    def __init__(self, friendly_name, fname_or_power_values, frequencies=None):
        """
        __init__(self, friendly_name, fname_or_power_values, frequencies=None)

        This class provides a Consuming-Producing-Storing element having a
        random behavior. The consecutive consumed or produced power values
        are IID (Independently and Identically Distributed). The distribution,
        discrete and finite, is given as parameter.

        Beside the element ``friendly_name``, the constructor parameters are
        either the name of the file the distribution has to be read from, either
        the potentially consumed or produced ``power_values``,together with their
        ``frequencies`` or probabilities. Input ``power values`` has to be a
        monotonically increasing sequence of float. Input 'frequencies' can be
        either integers (number of occurrences), or floats summing to 1.0
        (relative frequencies or probabilities), or monotonically increasing
        sequence of positive floats ending with 1.0 (cumulative relative
        frequencies or probabilities)

        :param friendly_name: Friendly name for the element.
            Should be unique within the simulation module.
        :type friendly_name: str

        :param fname_or_power_values: Name of the file from which the
            distribution has to be read or Power values which may be consumed
            (positive) or produced (negative), ordered in a monotonically
            increasing sequence.
        :type fname_or_power_values: either string or 1-D numpy array of float

        :param frequencies: Number of occurrences (frequencies), or relative
            frequencies, or cumulative relative frequencies of corresponding
            power values, if those are given as second parameter, None if
            filename is given as 2nd parameter
        :type frequencies: None or 1-D numpy array of integer or float
        """

        # HACK: when object is constructed with *args or **kwargs
        if fname_or_power_values.dtype is not (int, float):
           fname_or_power_values = units.value(units.to_si(fname_or_power_values))

        super(AnyIIDRandomElectricalCPSElement, self).__init__(friendly_name)
        # if first parameter is a string (name of a file), read data
        if isinstance(fname_or_power_values, str):
            if not frequencies is None:
                raise RuntimeError(
                    "'frequencies' cannot be passed as argument, they are read "
                    "from file with name '" + fname_or_power_values +
                    "' in this case")
            [power_values, frequencies] = self._read_hist_from_file(
                fname_or_power_values)
        else:
            power_values = fname_or_power_values  # just copy variable
        # check
        if power_values.dtype != float:
            raise TypeError("'power_values' has to be an array of floats.")
        if len(power_values.shape) != 1:
            raise RuntimeError(
                "'power_values' has to be a one-dimensional array")
        if not frequencies.dtype in (int, float):
            raise TypeError(
                "'frequencies' has to be an array of integers or floats.")
        if len(frequencies.shape) != 1:
            raise RuntimeError(
                "'frequencies' has to be a one-dimensional array")
        if frequencies.shape[0] != power_values.shape[0]:
            raise RuntimeError(
                "'frequencies' and 'power_values' must have the same length")
        self._power_values = power_values
        if frequencies[-1] == 1.0:
            for i_pos in range(1, frequencies.shape[0]):
                if frequencies[i_pos] <= frequencies[i_pos - 1]:
                    raise RuntimeError(
                        "cumulative relative 'frequencies' should be "
                        "monotonically increasing.")
            self._cdf = frequencies
        else:
            if frequencies.dtype == int:
                frequencies.astype('float')
            sum_freq = sum(frequencies)
            if sum_freq == 0.:
                raise TypeError(
                    "sum of values in 'frequencies' may not be zero.")
            self._cdf = np.cumsum((1.0 / sum_freq) * frequencies)
Beispiel #30
0
    def __init__(self, friendly_name, length, X, R=0, B=0):
        """
        __init__(self, friendly_name, length, X, R=0, B=0)

        Class for representing a transmission line in an electrical network.
        Its parameters are linked to the
        transmission line PI model represented graphically below::

                                  R              jX
                            +-----------+   +-----------+
            o--->---o-------|           |---|           |-------o--->---o
                    |       +-----------+   +-----------+       |
                    |                                           |
                  -----  jB/2                                 -----  jB/2
                  -----                                       -----
                    |                                           |
                    |                                           |
                   ---                                         ---

        At initialization, in addition to the line ``friendly_name``,
        the line length, the line reactance (``X``), line resistance (``R``) and
        line charging (B) have to be given. ``R`` and ``B`` default to zero.

        :param friendly_name: Friendly name for the line. Should be unique
            within the simulation module, i.e. different for example from the
            friendly name of a bus.
        :type friendly_name: str

        :param length: Line length.
        :type length: length, see :mod:`gridsim.unit`

        :param X: Line reactance.
        :type X: ohm, see :mod:`gridsim.unit`

        :param R: Line resistance.
        :type R: ohm, see :mod:`gridsim.unit`

        :param B: Line charging.
        :type B: siemens, see :mod:`gridsim.unit`
        """

        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(length, (int, float)):
            length = units.value(units.to_si(length))
        if not isinstance(X, (int, float)):
            X = units.value(units.to_si(X))
        if not isinstance(R, (int, float)):
            R = units.value(units.to_si(R))
        if not isinstance(B, (int, float)):
            B = units.value(units.to_si(B))

        # super constructor needs units as it is a "public" function
        super(ElectricalTransmissionLine,
              self).__init__(friendly_name, X * units.ohm, R * units.ohm)

        if length <= 0:
            raise RuntimeError('Length has to be a strictly positive number')
        if B < 0:
            raise RuntimeError('Line charging B can not be negative number')

        self.length = length
        """
        The transmission line length.
        """
        self.B = B
        """
Beispiel #31
0
 def __getattr__(self, item):
     # this function is not called when using thermalprocess.temperature
     # because its parent (ThermalProcess) already has a 'temperature'
     return units.value(getattr(self._time_series, item))
Beispiel #32
0
    def __init__(self,
                 friendly_name,
                 height,
                 radius,
                 thickness,
                 initial_temperature,
                 heat_transfer_coeff,
                 power,
                 temperature_in,
                 time_series,
                 readparamlist,
                 writeparamlist,
                 time_converter=None):
        """

        :param friendly_name: Friendly name to give to the process.
        :type friendly_name: str, unicode
        :param height: the height of the boiler
        :type height: units.metre
        :param radius: the radius of the boiler
        :type radius: units.metre
        :param thickness: the thickness of the boiler
        :type thickness: units.metre
        :param initial_temperature: the initial temperature of the water
                                    in the boiler.
        :type initial_temperature: units.kelvin
        :param heat_transfer_coeff: the heat transfer coefficient
        :type heat_transfer_coeff: units.watt/(units.kelvin*(units.meter**2)
        :param power: the electrical power to heat the boiler
        :type power: units.watt
        :param temperature_in: the temperature of the input water
        :type temperature_in: units.kelvin
        :param time_series: the time_series to load the stream
        :type time_series: class:`gridsim.timeseries.TimeSeries`
        :param readparamlist: read parameter of the actor
        :param writeparamlist: write parameter of the actor
        :param time_converter:
        :type time_converter: types.FunctionType or ``None``
        :return:
        """

        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(height, (int, float)):
            height = units.value(units.to_si(height))
        if not isinstance(radius, (int, float)):
            radius = units.value(units.to_si(radius))
        if not isinstance(thickness, (int, float)):
            thickness = units.value(units.to_si(thickness))
        if not isinstance(initial_temperature, (int, float)):
            initial_temperature = units.value(units.to_si(initial_temperature))
        if not isinstance(heat_transfer_coeff, (int, float)):
            heat_transfer_coeff = units.value(units.to_si(heat_transfer_coeff))
        if not isinstance(temperature_in, (int, float)):
            temperature_in = units.value(units.to_si(temperature_in))
        if not isinstance(power, (int, float)):
            power = units.value(units.to_si(power))

        super(Boiler, self). \
            __init__(friendly_name)

        self.readparamtype = readparamlist
        self.writeparamtype = writeparamlist

        self._time_converter = time_converter

        self._time_series = time_series
        self._time_series.load(time_converter=time_converter)

        self._height = height
        self._radius = radius
        self._thickness = thickness

        self._initial_temperature = initial_temperature
        self._temperature = self._initial_temperature

        self._heat_transfer_coeff = heat_transfer_coeff

        self._power = power
        self.old_power = 0

        self._temperature_in = temperature_in

        # potential energy [J/K]
        self._cb = units.value(Water().thermal_capacity) * \
                   units.value(Water().weight) * math.pi * self._height * (self._radius ** 2)

        # global loss factor [W/K.m2]
        self._ub = 1 / ((1 / self._heat_transfer_coeff) +
                        (self._thickness /
                         units.value(BoilerMaterial().thermal_conductivity)))

        # thermal losses when off [W/K]
        self._off_losses = self._ub * (
            (2. * math.pi *
             (self._radius**2)) + (2 * math.pi * self._height * self._radius))

        self._on = False
Beispiel #33
0
    def __init__(self,
                 friendly_name,
                 thermal_capacity,
                 initial_temperature,
                 mass=1,
                 position=Position()):
        """
        __init__(self, friendly_name, thermal_capacity, initial_temperature, mass=1*units.kilogram, position=Position()):

        The very basic element of a thermal simulation. A thermal process
        represents a closed thermal envelope like a room or a amount of
        matter which has an uniform thermal capacity and and stores an amount of
        thermal energy resulting in a temperature. Those thermal processes
        can be coupled by :class:`ThermalCoupling` element.

        :param friendly_name: The name to give to the thermal process.
        :type friendly_name: str

        :param thermal_capacity: The thermal capacity of the process.
            See :class:`.Material`.
        :type thermal_capacity: heat_capacity, see :mod:`gridsim.unit`

        :param initial_temperature: The initial temperature of the process in
            degrees.
        :type initial_temperature: kelvin, see :mod:`gridsim.unit`

        :param mass: the mass of the element
        :type mass: mass, see :mod:`gridsim.unit`

        :param position: The position of the process.
        :type position: :class:`.Position`
        """

        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(thermal_capacity, (int, float)):
            thermal_capacity = units.value(units.to_si(thermal_capacity))
        if not isinstance(initial_temperature, (int, float)):
            initial_temperature = units.value(units.to_si(initial_temperature))
        if not isinstance(mass, (int, float)):
            mass = units.value(units.to_si(mass))

        super(ThermalProcess, self).__init__(friendly_name, position)

        self._initial_temperature = initial_temperature
        """
        The initial temperature of the process. Need for reset.
        """

        self._mass = mass
        """
        The mass of the thermal process.
        """

        self._thermal_capacity = thermal_capacity
        """
        The thermal capacity of the thermal process.
        """

        self.temperature = self._initial_temperature
        """
        The temperature of the process.
        """

        self._internal_thermal_energy = self._initial_temperature * \
            self._thermal_capacity * self._mass
        """
        The internal thermal energy stored inside the thermal process.
        """

        self.thermal_energy = self._internal_thermal_energy
        """
Beispiel #34
0
    def __init__(self,
                 friendly_name,
                 target_temperature,
                 hysteresis,
                 thermal_process,
                 subject,
                 attribute,
                 on_value=True,
                 off_value=False,
                 position=Position()):
        """
        A thermostat controller. This class measures the temperature of a
        thermal process (typically a room) and controls ANY attribute of any
        AbstractSimulationElement depending the measured temperature, the given
        target_temperature and the hysteresis.

        :param: friendly_name: User friendly name to give to the element.
        :type friendly_name: str

        :param: target_temperature: The temperature to try to maintain inside
            the target ThermalProcess.
        :type: target_temperature: temperature see :mod:`gridsim.unit`

        :param: hysteresis: The +- hysteresis in order to avoid to fast on/off
            switching.
        :type: hysteresis: delta temperature see :mod:`gridsim.unit`

        :param: thermal_process: The reference to the thermal process to
            observe.
        :type: thermal_process: :class:`.ThermalProcess`

        :param: subject: Reference to the object of which is attribute has to be
            changed depending on the temperature.
        :type: object

        :param: attribute: The name of the attribute to control as string.
        :type: str

        :param: on_value: The value to set for the attribute in order to turn
            the device "on".
        :type: on_value: any

        :param: off_on_value: The value to set for the attribute in order to
            turn the device "off".
        :type: off_value: any

        :param position: The position of the thermal element.
            Defaults to [0,0,0].
        :type position: :class:`Position`
        """
        super(Thermostat, self).__init__(friendly_name, position)
        self.target_temperature = units.value(target_temperature, units.kelvin)
        """
        The temperature to try to retain inside the observer thermal process by
        conducting an electrothermal element.
        """

        self.hysteresis = units.value(hysteresis, units.kelvin)
        """
        The +- hysteresis applied to the temperature measure in order to avoid
        to fast on/off switching.
        """

        if not hasattr(thermal_process, 'temperature'):
            raise TypeError('thermal_process')
        self.thermal_process = thermal_process
        """
        The reference to the thermal process to observe and read the
        temperature from.
        """

        self.subject = subject
        """
        The reference to the element to control.
        """

        self.attribute = attribute
        """
        Name of the attribute to control.
        """

        self.on_value = on_value
        """
        Value to set in order to turn the element on.
        """

        self.off_value = off_value
        """
        Value to set in order to turn the element off.
        """

        self._output_value = off_value
Beispiel #35
0
    def __init__(self,
                 friendly_name,
                 thermal_conductivity,
                 from_process,
                 to_process,
                 contact_area=1,
                 thickness=1):
        """
        __init__(self, friendly_name, thermal_conductivity, from_process, to_process, contact_area=1*units.metre**2, thickness=1*units.metre)

        A thermal coupling connects two thermal processes allowing them to
        exchange thermal energy.

        :param friendly_name: The friendly name to identify the element.
        :type friendly_name: str

        :param thermal_conductivity: The thermal conductivity of the thermal
            element.
        :type thermal_conductivity: thermal conductivity, see :mod:`gridsim.unit`

        :param from_process: The first process coupled
            process.
        :type from_process: :class:`ThermalProcess`

        :param to_process: The second process coupled process.
        :type to_process: :class:`ThermalProcess`

        :param contact_area: The size of the contact area
            process.
        :type contact_area: square_meter, see :mod:`gridsim.unit`

        :param thickness: the thickness of the contact area
            process.
        :type thickness: meter, see :mod:`gridsim.unit`
        """

        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(thermal_conductivity, (int, float)):
            thermal_conductivity = units.value(
                units.to_si(thermal_conductivity))
        if not isinstance(contact_area, (int, float)):
            contact_area = units.value(units.to_si(contact_area))
        if not isinstance(thickness, (int, float)):
            thickness = units.value(units.to_si(thickness))

        super(ThermalCoupling, self).__init__(friendly_name)

        self.from_process = from_process
        self.to_process = to_process

        self.thermal_conductivity = thermal_conductivity
        """
        The thermal conductivity of the coupling in W/K.
        """
        self._contact_area = contact_area
        """
        The size of the contact area between the two :class:`ThermalProcess`
        """
        self._thickness = thickness
        """
        The thickness of the material between the two :class:`ThermalProcess`
        """
        self._delta_energy = 0
        """
        The energy variation
        """
        self.power = None
        """
Beispiel #36
0
    def __init__(self, friendly_name, height, radius, thickness,
                 initial_temperature, heat_transfer_coeff, power,
                 temperature_in,
                 time_series,
                 time_converter=None):
        """

        :param friendly_name:Friendly name to give to the process.
        :type friendly_name: str, unicode
        :param height: the height of the boiler
        :type height: units.metre
        :param radius: the radius of the boiler
        :type radius: units.metre
        :param thickness: the thickness of the boiler
        :type thickness: units.metre
        :param initial_temperature: the initial temperature of the water
                                    in the boiler.
        :type initial_temperature: units.kelvin
        :param heat_transfer_coeff: the heat transfer coefficient
        :type heat_transfer_coeff: units.watt/(units.kelvin*(units.meter**2)
        :param power: the electrical power to heat the boiler
        :type power: units.watt
        :param temperature_in: the temperature of the input water
        :type temperature_in: units.kelvin
        :param time_series: the time_series to load the stream
        :type time_series: class:`gridsim.timeseries.TimeSeries`
        :param time_converter:
        :type time_converter: types.FunctionType or ``None``
        :return:
        """

        # HACK: when object is constructed with *args or **kwargs
        if not isinstance(height, (int, float)):
            height = units.value(units.to_si(height))
        if not isinstance(radius, (int, float)):
            radius = units.value(units.to_si(radius))
        if not isinstance(thickness, (int, float)):
            thickness = units.value(units.to_si(thickness))
        if not isinstance(initial_temperature, (int, float)):
            initial_temperature = units.value(units.to_si(initial_temperature))
        if not isinstance(heat_transfer_coeff, (int, float)):
            heat_transfer_coeff = units.value(units.to_si(heat_transfer_coeff))
        if not isinstance(temperature_in, (int, float)):
            temperature_in = units.value(units.to_si(temperature_in))
        if not isinstance(power, (int, float)):
            power = units.value(units.to_si(power))

        super(Boiler, self).\
            __init__(friendly_name)

        self._time_converter = time_converter

        self._time_series = time_series
        self._time_series.load(time_converter=time_converter)

        self._height = height
        self._radius = radius
        self._thickness = thickness

        self._initial_temperature = initial_temperature
        self._temperature = self._initial_temperature

        self._heat_transfer_coeff = heat_transfer_coeff

        self._power = power
        self.old_power = 0

        self._temperature_in = temperature_in

        # potential energy [J/K]
        self._cb = units.value(Water().thermal_capacity) * \
            units.value(Water().weight)*math.pi*self._height*(self._radius**2)

        # global loss factor [W/K.m2]
        self._ub = 1/((1/self._heat_transfer_coeff) +
                      (self._thickness/units.value(BoilerMaterial().thermal_conductivity)))

        # thermal losses when off [W/K]
        self._off_losses = self._ub * ((2.*math.pi*(self._radius**2)) +
                                       (2*math.pi*self._height*self._radius))

        self._on = False