Control to avoid Legionella in the DHW. This model represents the anti legionella control of a real heat
  pump. Based on a daily or weekly approach, the given supply
  temperature is raised above the minimal temperature required for the
  thermal desinfection (at least 60 °C) for a given duration
  minTimeAntLeg.

within AixLib.Controls.HeatPump;
model AntiLegionella "Control to avoid Legionella in the DHW"

  parameter Modelica.Units.SI.ThermodynamicTemperature TLegMin=333.15
    "Temperature at which the legionella in DWH dies";

  parameter Modelica.Units.SI.Time minTimeAntLeg
    "Minimal duration of antilegionella control";
  parameter Boolean weekly=true
    "Switch between a daily or weekly trigger approach"
  parameter Integer trigWeekDay "Day of the week at which control is triggered"
  parameter Integer trigHour "Hour of the day at which control is triggered";
  parameter AixLib.Utilities.Time.Types.ZeroTime zerTim
    "Enumeration for choosing how reference time (time = 0) should be defined";
  parameter Integer yearRef=2016 "Year when time = 0, used if zerTim=Custom";
  Modelica.Blocks.Logical.GreaterEqual
                               TConLessTLegMin
    "Compare if current TCon is smaller than the minimal TLeg"
  AixLib.Utilities.Logical.SmoothSwitch switchTLeg
    "Switch to Legionalla control if needed"
  Modelica.Blocks.Interfaces.RealOutput TSet_out
    "Set value for the condenser outlet temperature"

  Modelica.Blocks.Sources.Constant constTLegMin(final k=TLegMin)
    "Temperature at which the legionella in DWH dies"
  Modelica.Blocks.Logical.Timer timeAntiLeg "Time in which legionella will die"
  Modelica.Blocks.Logical.GreaterThreshold
                               greaterThreshold(final threshold=minTimeAntLeg)
  Modelica.Blocks.Interfaces.RealInput TSet_in "Input of TSet"
  Modelica.Blocks.Logical.Pre pre1
  AixLib.Utilities.Time.DaytimeSwitch daytimeSwitch(
    final hourDay=trigHour,
    final zerTim=zerTim,
    final yearRef=yearRef,
    final weekDay=trigWeekDay)
    "If given day and hour match the current daytime, output will be true"
  Modelica.Blocks.MathInteger.TriggeredAdd triggeredAdd(use_reset=true, use_set=
       false,
    y_start=0)
              "See info of model for description"
  Modelica.Blocks.Sources.IntegerConstant intConPluOne(final k=1)
    "Value for counting"
  Modelica.Blocks.Logical.LessThreshold    lessThreshold(final threshold=1)
    "Checks if value is less than one"
  Modelica.Blocks.Math.IntegerToReal intToReal "Converts Integer to Real"
  Modelica.Blocks.Interfaces.RealInput TSupAct
    "Input of actual supply temperature"
equation
  connect(constTLegMin.y, TConLessTLegMin.u2)
  connect(switchTLeg.y, TSet_out)
  connect(TSet_in, switchTLeg.u1)
  connect(switchTLeg.u3, constTLegMin.y)
  connect(timeAntiLeg.u, pre1.y)
  connect(TConLessTLegMin.y, pre1.u)
  connect(lessThreshold.y, switchTLeg.u2)
  connect(intToReal.y, lessThreshold.u)
  connect(intConPluOne.y, triggeredAdd.u)
  connect(intToReal.u, triggeredAdd.y)
  connect(greaterThreshold.y, triggeredAdd.reset)
  connect(TSupAct, TConLessTLegMin.u1)
  connect(daytimeSwitch.isDaytime, triggeredAdd.trigger)
  connect(timeAntiLeg.y, greaterThreshold.u)
end AntiLegionella;


Control block to ensure no frost limits heat flow at the evaporator. Basic model for a defrost control. The icing factor is calculated in
  the heat pump based on functions or other models.

within AixLib.Controls.HeatPump;
model DefrostControl
  "Control block to ensure no frost limits heat flow at the evaporator"
  parameter Real minIceFac "Minimal value above which no defrost is necessary";

  parameter Real deltaIceFac = 0.1 "Bandwitdth for hystereses. If the icing factor is based on the duration of defrost, this value is necessary to avoid state-events.";
  Modelica.Blocks.Interfaces.BooleanInput hea
  Modelica.Blocks.Interfaces.RealInput ySet
    "Set value relative speed of compressor. Analog from 0 to 1"
  Utilities.Logical.SmoothSwitch swiErr
    "If an error occurs, the value of the conZero block will be used(0)"
  Modelica.Blocks.Sources.Constant conOne(final k=1)
    "If Defrost is enabled, HP runs at full power"
  Modelica.Blocks.Interfaces.RealOutput yOut
    "Relative speed of compressor. From 0 to 1"
  Modelica.Blocks.Interfaces.BooleanOutput heaOut
  Fluid.HeatPumps.ModularReversible.BaseClasses.RefrigerantMachineControlBus sigBus
  Modelica.Blocks.Logical.Hysteresis            iceFacGreMinChi(
    final uLow=minIceFac,
    final uHigh=minIceFac + deltaIceFac,
    final pre_y_start=true)
    "Check if icing factor is greater than a boundary"
  Modelica.Blocks.Logical.LogicalSwitch logicalSwitch
    "If a chiller is used to defrost, mode will be false"
  Modelica.Blocks.Sources.BooleanConstant conTrueUseChi(final k=false)
  "Set mode to false to simulate the defrost cycle"
equation
  connect(conOne.y, swiErr.u3)
  connect(swiErr.y,yOut)
  connect(ySet, swiErr.u1)

  connect(sigBus.iceFacMea, iceFacGreMinChi.u)
  connect(iceFacGreMinChi.y, swiErr.u2)
  connect(logicalSwitch.y, heaOut)
  connect(hea, logicalSwitch.u1)
  connect(iceFacGreMinChi.y, logicalSwitch.u2)
  connect(conTrueUseChi.y, logicalSwitch.u3)
end DefrostControl;


Control block which makes sure the desired temperature is supplied by the HP. Model of a heat pump controller, setting a compressor signal and heat
  pump mode based on a given input temperarute. A heating curve is used
  to determine the supply temperature. This TSet is later converted to
  a signal nSet based on the acutal temperature in the system.
  Futhermore, a legionella protection for DHW-Simulation is
  implemented.

within AixLib.Controls.HeatPump;
model HPControl
  "Control block which makes sure the desired temperature is supplied by the HP"
  //General
  replaceable model TSetToNSet =
      AixLib.Controls.HeatPump.BaseClasses.PartialTSetToNSet constrainedby
    AixLib.Controls.HeatPump.BaseClasses.PartialTSetToNSet(
    final use_secHeaGen=use_secHeaGen)

  parameter Boolean use_secHeaGen=false "True to choose a bivalent system"
//Heating Curve
  parameter Boolean use_tableData=true
    "Choose between tables or function to calculate TSet"
  replaceable function HeatingCurveFunction =
      SetPoints.Functions.HeatingCurveFunction constrainedby
    SetPoints.Functions.PartialBaseFct
  parameter
    AixLib.DataBase.Boiler.DayNightMode.HeatingCurvesDayNightBaseDataDefinition
    heatingCurveRecord=
      AixLib.DataBase.Boiler.DayNightMode.HeatingCurves_Vitotronic_Day25_Night10()
    "Record with information about heating curve data"
  parameter Real declination=2 "Declination of curve"
  parameter Real day_hour=6 "Hour of day at which day mode is enabled"
  parameter Real night_hour=22 "Hour of day at which night mode is enabled"
  parameter AixLib.Utilities.Time.Types.ZeroTime zerTim=AixLib.Utilities.Time.Types.ZeroTime.NY2017
    "Enumeration for choosing how reference time (time = 0) should be defined. Used for heating curve and antilegionella"
//Anti Legionella
  parameter Boolean use_antLeg "True if Legionella Control is of relevance"
  parameter Modelica.Units.SI.ThermodynamicTemperature TLegMin=333.15
    "Temperature at which the legionella in DWH dies"
  parameter Modelica.Units.SI.Time minTimeAntLeg
    "Minimal duration of antilegionella control"
  parameter Boolean weekly=true
    "Switch between a daily or weekly trigger approach"
  parameter Integer trigWeekDay "Day of the week at which control is triggered"
  parameter Integer trigHour=3 "Hour of the day at which control is triggered"

  AixLib.Controls.HeatPump.AntiLegionella antiLegionella(
    final TLegMin=TLegMin,
    minTimeAntLeg=minTimeAntLeg,
    trigWeekDay=trigWeekDay,
    trigHour=trigHour,
    yearRef=2017,
    final zerTim=zerTim)
                    if use_antLeg
  AixLib.Fluid.HeatPumps.ModularReversible.BaseClasses.RefrigerantMachineControlBus sigBusHP
  Modelica.Blocks.Interfaces.RealOutput yOut "Relative compressor speed"
  Modelica.Blocks.Interfaces.RealInput T_oda "Outdoor air temperature"
  Modelica.Blocks.Interfaces.RealOutput ySecHeaGen if use_secHeaGen
                                                   "Relative power of second heat generator, from 0 to 1"
  Modelica.Blocks.Interfaces.RealOutput y_sou
  Modelica.Blocks.Interfaces.RealOutput y_sin
  Modelica.Blocks.Sources.Constant        constHeating1(final k=1)
    "If you want to include chilling, please insert control blocks first"

  AixLib.Controls.SetPoints.HeatingCurve heatCurve(
    final TOffset=0,
    final use_dynTRoom=false,
    final zerTim=zerTim,
    final day_hour=day_hour,
    final night_hour=night_hour,
    final heatingCurveRecord=heatingCurveRecord,
    final declination=declination,
    redeclare function HeatingCurveFunction = HeatingCurveFunction,
    use_tableData=use_tableData,
    final TRoom_nominal=293.15)

  TSetToNSet ConvTSetToNSet
  Modelica.Blocks.Routing.RealPassThrough realPasThrAntLeg if not use_antLeg
                                                           "No Anti Legionella"
  Modelica.Blocks.Sources.BooleanConstant constHeating(final k=true)
    "If you want to include chilling, please insert control blocks first"
  Modelica.Blocks.Interfaces.BooleanOutput hea "Heating mode"
  Modelica.Blocks.Interfaces.RealInput TSup "Supply temperature"

equation

  connect(T_oda, sigBusHP.T_oda)
  connect(T_oda, heatCurve.T_oda)
  connect(heatCurve.TSet, antiLegionella.TSet_in)

  connect(antiLegionella.TSet_out,ConvTSetToNSet. TSet)

  connect(ConvTSetToNSet.nOut,yOut)

  connect(sigBusHP,ConvTSetToNSet. sigBusHP)
  connect(heatCurve.TSet, realPasThrAntLeg.u)

  connect(realPasThrAntLeg.y,ConvTSetToNSet. TSet)
  connect(hea, constHeating.y)
  connect(TSup, antiLegionella.TSupAct)

  connect(TSup,ConvTSetToNSet.TMea)

  connect(ConvTSetToNSet.ySecHeaGen, ySecHeaGen)
  connect(ySecHeaGen, ySecHeaGen)
  connect(constHeating1.y, y_sou)
  connect(constHeating1.y, y_sin)
end HPControl;


Converter model for an inverter / speed controlled HP modulating between 0 and 1.

within AixLib.Controls.HeatPump;
model InverterControlledHP
  "Converter model for an inverter / speed controlled HP modulating between 0 and 1"
  extends BaseClasses.PartialTSetToNSet;
  parameter Real bandwidth "Bandwith of hysteresis of controller";
  parameter Real k     "Gain of controller"
  parameter Modelica.Units.SI.Time Ti    "Time constant of Integrator block"
  parameter Real yMin=0.2 "Minimal relative compressor speed"

  Modelica.Blocks.Logical.OnOffController onOffController(bandwidth=bandwidth,
      pre_y_start=false)                                                                    "Hysteresis controller for set temperature"
  Modelica.Blocks.Continuous.LimPID InverterControl(
    final controllerType=Modelica.Blocks.Types.SimpleController.PI,
    final k=k,
    final Ti=Ti,
    final yMax=1,
    final yMin=yMin)
    "PI-Control for a inverter controlled HP"

equation
  connect(TSet, onOffController.reference)
  connect(InverterControl.y, swiNullHP.u1)
  connect(TSet, InverterControl.u_s)
  connect(TMea, onOffController.u)
  connect(TMea, InverterControl.u_m)
  connect(onOffController.y, andHeaLim.u1)
end InverterControlledHP;


within AixLib.Controls;
package HeatPump "Contains typical controllers for heat pumps"
extends Modelica.Icons.VariantsPackage;
end HeatPump;


Controller gives full speed or stop signal depending on temperature hysteresis.

within AixLib.Controls.HeatPump;
model TwoPointControlledHP
  "Controller gives full speed or stop signal depending on temperature hysteresis"
  extends AixLib.Controls.HeatPump.BaseClasses.PartialTSetToNSet;
  parameter Real bandwidth "Bandwith of hysteresis of controller";
  Modelica.Blocks.Logical.OnOffController onOffController(final bandwidth=bandwidth,
      final pre_y_start=false)                                                              "Hysteresis controller for set temperature"
  Modelica.Blocks.Sources.Constant conOne(final k=1)
                                               "Constant one for on off heat pump"

equation
  connect(TSet, onOffController.reference)
  connect(conOne.y, swiNullHP.u1)
  connect(TMea, onOffController.u)
  connect(onOffController.y, andHeaLim.u1)
end TwoPointControlledHP;


within AixLib.Controls.HeatPump;
package BaseClasses "Package with base classes for the HeatPump controller"
end BaseClasses;


Base class of a heat pump controller with bus interface. Base class for heat pump controllers that contains the AixLib.Controls.Interfaces.HeatPumpControlBus.

within AixLib.Controls.HeatPump.BaseClasses;
partial model PartialHPController
  "Base class of a heat pump controller with bus interface"
  AixLib.Fluid.HeatPumps.ModularReversible.BaseClasses.RefrigerantMachineControlBus heatPumpControlBus
end PartialHPController;


Partial model to convert set temperature to compressor speed of heat pump.

within AixLib.Controls.HeatPump.BaseClasses;
partial model PartialTSetToNSet
  "Partial model to convert set temperature to compressor speed of heat pump"
  parameter Boolean use_secHeaGen=false
                                       "True to choose a bivalent system"

  // Heating limit temperature
  parameter Boolean use_heaLim=true "=false to disable moving average heating limit"
  parameter Modelica.Units.SI.Temperature T_heaLim=293.15
    "Heating limit temperature. If the filtered outdoor air temperature surpasses this threshold, the device will be shut down"
  parameter Modelica.Units.SI.Time movAveTime=300
    "Time span for building the average of the outdoor air temperature. Used for heating limit temperature"

  Modelica.Blocks.Logical.Switch        swiNullHP "If HP is off, zero is passed"
  Modelica.Blocks.Sources.Constant conZer(final k=0)
                                               "If an error occurs, the compressor speed is set to zero"
  Modelica.Blocks.Interfaces.RealInput TSet(
      final quantity="ThermodynamicTemperature",
      final unit="K",
      final displayUnit="degC") "Set temperature"
  Modelica.Blocks.Interfaces.RealOutput nOut "Relative speed of compressor. From 0 to 1"
  AixLib.Fluid.HeatPumps.ModularReversible.BaseClasses.RefrigerantMachineControlBus sigBusHP
  Modelica.Blocks.Interfaces.RealOutput ySecHeaGen if use_secHeaGen
                                                   "Relative power of second heat generator, from 0 to 1"
  Modelica.Blocks.Interfaces.RealInput TMea(
      final quantity="ThermodynamicTemperature",
      final unit="K",
      final displayUnit="degC") "Actual temperature, control variable"
  AixLib.Utilities.Logical.SmoothSwitch swiNullsecHeaGen if use_secHeaGen
    "If second heater is off, zero is passed"
  AixLib.Utilities.Math.MovingAverage movAve(final aveTime=movAveTime, final u_start=0)
    if use_heaLim
    "Moving average to account for fluctuations in the outdoor air temperature"
  Modelica.Blocks.Logical.And andHeaLim
    "Check if control and heating limit temperature yield true to turn the device on"
  Modelica.Blocks.Logical.LessThreshold      lessThreshold(final threshold=
        T_heaLim) if use_heaLim

  Modelica.Blocks.Sources.BooleanConstant    booleanConstant(final k=true)
 if not use_heaLim
equation
  connect(conZer.y, swiNullHP.u3)
  connect(swiNullHP.y, nOut)
  connect(swiNullsecHeaGen.y, ySecHeaGen)
  connect(conZer.y, swiNullsecHeaGen.u3)
  connect(sigBusHP.T_oda, movAve.u)
  connect(movAve.y, lessThreshold.u)
  connect(lessThreshold.y, andHeaLim.u2)
  connect(andHeaLim.y, swiNullHP.u2)
  connect(booleanConstant.y, andHeaLim.u2)
end PartialTSetToNSet;


<html><p>
  Example for an inverter controlled heat pump. Play around with the PI
  settings to see how they influence nSet depending on TSet and TMea.
</p>
</html>. Example for an inverter controlled heat pump. Play around with the PI
  settings to see how they influence nSet depending on TSet and TMea.

within AixLib.Controls.HeatPump.Examples;
model InverterControlledHeatPump
  extends Modelica.Icons.Example;
  extends PartialHeatPumpController(redeclare InverterControlledHP hPController(
      bandwidth=2,
      k=0.05,
      Ti=100));
end InverterControlledHeatPump;


within AixLib.Controls.HeatPump;
package Examples "Examples for controller and interface usage"
extends Modelica.Icons.ExamplesPackage;
end Examples;


Example for usage of heat pump controller. Partial example model for heat pump controls.

within AixLib.Controls.HeatPump.Examples;
partial model PartialHeatPumpController
  "Example for usage of heat pump controller"

  AixLib.Fluid.HeatPumps.ModularReversible.BaseClasses.RefrigerantMachineControlBus heatPumpControlBus
    "Required to make the signals on the bus accessible"
  Modelica.Blocks.Sources.Sine T_meas(
    f=1/3600,
    amplitude=6,
    offset=310) "Generates the measured temperature"
  Modelica.Blocks.Sources.Constant T_set(k=310)
    "Provides the temperature set point"
  Modelica.Blocks.Interfaces.RealOutput TMea(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC",
    min=0) "Outputs the temperature measurement"
  replaceable BaseClasses.PartialTSetToNSet hPController constrainedby
    BaseClasses.PartialTSetToNSet(
    final use_secHeaGen=false,
    use_heaLim=false,
    T_heaLim=293.15,
    movAveTime=300)
  Modelica.Blocks.Interfaces.RealOutput TSet(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC",
    min=0) "Outputs the temperature measurement"
  Modelica.Blocks.Interfaces.RealOutput nSet
    "Outputs the temperature measurement"
  Modelica.Blocks.Sources.Constant T_oda(k=273.15)
    "Provides the temperature set point"
equation
  connect(T_meas.y, TMea)
  connect(hPController.TSet, T_set.y)
  connect(hPController.TMea, T_meas.y)
  connect(nSet, hPController.nOut)
  connect(T_oda.y, heatPumpControlBus.TOdaMea)
  connect(heatPumpControlBus, hPController.sigBusHP)
  connect(T_set.y, TSet)
end PartialHeatPumpController;


<html><p>
  Example for an two-point hysteresis controlled heat pump. Play around
  with the bandwith settings to see how it influence nSet depending on
  TSet and TMea.
</p>
</html>. Example for an two-point hysteresis controlled heat pump. Play around
  with the bandwith settings to see how it influence nSet depending on
  TSet and TMea.

within AixLib.Controls.HeatPump.Examples;
model TwoPointControlledHeatPump
  extends Modelica.Icons.Example;
  extends PartialHeatPumpController(redeclare TwoPointControlledHP hPController(
        bandwidth=2));
end TwoPointControlledHeatPump;


Model of an internal controller for modular compressors. This a controller block used for modular compressor models as
  presented in AixLib.Fluid.Movers.Compressors.ModularCompressors.
  The controller block consists of simple PID controllers for each
  compressor and no further control strategy is implemented yet.
  However, these PID controller are only initialised a nd activated if
  no external controller is provided (i.g. if useExt =
  false).

within AixLib.Controls.HeatPump.ModularHeatPumps;
model ModularCompressorController
  "Model of an internal controller for modular compressors"
  extends BaseClasses.PartialModularController(
    dataBus(final nCom=nCom));

  // Definition of dummy signals for controllers' rest inputs
  //
  Modelica.Blocks.Sources.BooleanConstant trigger[nCom](each k=false)
    "Boolean block to provide dummy signal to controllers' trigger signals"
  Modelica.Blocks.Sources.Constant triggerVal[nCom](each k=0)
    "Real block to provide dummy signal to controllers' rest signals"

equation
  // Connect internal controller with inputs and outputs
  //
  connect(intCon.u_m, dataBus.comBus.meaConVarCom);
  connect(intCon.u_s, dataBus.comBus.intSetPoiCom);
  connect(intCon.y, manVarThr);

  if useExt then
    connect(manVarThr, dataBus.comBus.extManVarCom);
  end if;
  manVar = manVarThr;

  /*The output block 'manVarThr' is mandantory since the internal controller is
    conditional. Therefore, the connection 'connect(internalController.y,
    manVarThr)' is required to prevent errors that would occur otherwise if the
    internal controller is removed conditionally.
  */

  // Connect dummy signals to controllers' rest inputs
  //
  connect(trigger.y, intCon.trigger)
  connect(triggerVal.y, intCon.y_reset_in)

  // Connect output signals
  //
  connect(useExtBlo, dataBus.comBus.extConCom)
  connect(curManVar, dataBus.comBus.curManVarVal)
end ModularCompressorController;


Model of an internal controller for modular expansion valves. This a controller block used for modular expansion valve models as
  presented in
  AixLib.Fluid.Actuators.Valves.ExpansionValves.ModularExpansionValves.
  The controller block consists of simple PID controllers for each
  expansion valve and no further control strategy is implemented.
  However, these PID controller are only initialised and activated if
  no external controller is provided (i.g. if useExt =
  false).

within AixLib.Controls.HeatPump.ModularHeatPumps;
model ModularExpansionValveController
  "Model of an internal controller for modular expansion valves"
  extends BaseClasses.PartialModularController(
    dataBus(final nVal=nCom));

  // Definition of dummy signals for controllers' rest inputs
  //
  Modelica.Blocks.Sources.BooleanConstant tri[nCom](each k=false)
    "Boolean block to provide dummy signal to controllers' trigger signals"
  Modelica.Blocks.Sources.Constant triVal[nCom](each k=0)
    "Real block to provide dummy signal to controllers' rest signals"

equation
  // Connect internal controller with inputs and outputs
  //
  connect(intCon.u_m, dataBus.expValBus.meaConVarVal);
  connect(intCon.u_s, dataBus.expValBus.intSetPoiVal);
  connect(intCon.y, manVarThr);

  if useExt then
    connect(manVar, dataBus.expValBus.extManVarVal);
  end if;
  manVar = manVarThr;

  /*The output block 'manVarThr' is mandantory since the internal controller is
    conditional. Therefore, the connection 'connect(internalController.y,
    manVarThr)' is required to prevent errors that would occur otherwise if the
    internal controller is removed conditionally.
  */

  // Connect dummy signals to controllers' rest inputs
  //
  connect(tri.y, intCon.trigger)
  connect(triVal.y, intCon.y_reset_in)

  // Connect parameters describing if internal or external signal is used
  //
  connect(useExtBlo, dataBus.expValBus.extConVal)

  // Connect output signals
  //
  connect(curManVar, dataBus.expValBus.curManVarVal)
end ModularExpansionValveController;


within AixLib.Controls.HeatPump;
package ModularHeatPumps "Package that contains controllers used for modular heat pumps"
  extends Modelica.Icons.VariantsPackage;
end ModularHeatPumps;


within AixLib.Controls.HeatPump.ModularHeatPumps;
package BaseClasses "Package that contains base models used for controllers of modular heat pumps"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Base model used for all modular controllers. This is a base model used by all modular controller models. It
  defines basic inputs, outputs, parameters and sub-models. The main
  inputs and outputs are the modular heat pump control bus AixLib.Controls.Interfaces.ModularHeatPumpControlBus,
  the manipulated signals passed to the controlled components and the
  current manipulated signals. The main sub-model is a PID controller
  presented in AixLib.Controls.Continuous.LimPID
  that is initialised if no external controller is used. Furthermore,
  all parameters with respect to the PID controller are propagated
  because the modular controller shall be used in an architectural
  modeling approach.

within AixLib.Controls.HeatPump.ModularHeatPumps.BaseClasses;
partial model PartialModularController
  "Base model used for all modular controllers"

  // Definition of parameters describing modular approach
  //
  parameter Integer nCom = 1
    "Number of components"
  parameter Boolean useExt = true
    "= true, if external signal is used instead of internal controllers"

  // Definition of parameters describing the controller
  //
  parameter Modelica.Blocks.Types.SimpleController controllerType[nCom]=
    fill(Modelica.Blocks.Types.SimpleController.PID,nCom)
    "Type of controller"
  parameter Boolean reverseAction[nCom] = fill(false,nCom)
    "= true, if medium flow rate is throttled through cooling coil controller"
  parameter AixLib.Types.Reset reset[nCom]=
    fill(AixLib.Types.Reset.Disabled,nCom)
    "Type of controller output reset"

  parameter Real k[nCom] = fill(1,nCom)
    "Gain of controller"

  parameter Modelica.Units.SI.Time Ti[nCom]=fill(0.5, nCom)
    "Time constant of integrator block"
  parameter Real Ni[nCom] = fill(0.9,nCom)
    "Ni*Ti is time constant of anti-windup compensation"

  parameter Modelica.Units.SI.Time Td[nCom]=fill(0.1, nCom)
    "Time constant of derivative block"
  parameter Real Nd[nCom] = fill(10,nCom)
    "The higher Nd, the more ideal the derivative block"

  parameter Real wp[nCom] = fill(1,nCom)
    "Set-point weight for Proportional block (0..1)"
  parameter Real wd[nCom] = fill(0,nCom)
    "Set-point weight for Derivative block (0..1)"

  parameter Real yMax[nCom] = fill(1,nCom)
    "Upper limit of output"
  parameter Real yMin[nCom] = fill(0,nCom)
    "Lower limit of output"

  parameter Modelica.Blocks.Types.Init initType[nCom]=fill(Modelica.Blocks.Types.Init.InitialState,
      nCom)
    "Init: (1: no init, 2: steady state, 3: initial state, 4: initial output)"
  parameter Real xi_start[nCom] = fill(0,nCom)
    "Initial or guess value value for integrator output (= integrator state)"
  parameter Real xd_start[nCom] = fill(0,nCom)
    "Initial or guess value for state of derivative block"
  parameter Real y_start[nCom] = fill(0,nCom)
    "Initial value of output"

  // Definition of models
  //
  Continuous.LimPID intCon[nCom](
    final controllerType=controllerType,
    final k=k,
    final Ti=Ti,
    final Ni=Ni,
    final Td=Td,
    final Nd=Nd,
    final wp=wp,
    final wd=wd,
    final yMax=yMax,
    final yMin=yMin,
    final initType=initType,
    final xi_start=xi_start,
    final xd_start=xd_start,
    final y_start=y_start,
    final reverseActing=reverseAction,
    final reset=reset) if not useExt
    "Internal controller if internal controller is required"

  // Definition of connectors and inputs and outputs
  //
  Modelica.Blocks.Interfaces.BooleanOutput useExtBlo
    "Boolean block used to set data bus' useExt-signal"
  Modelica.Blocks.Interfaces.RealOutput manVarThr[nCom]
    "Input connector to pass controller's manipualted signals through if activated"

  Modelica.Blocks.Interfaces.RealInput curManVar[nCom]
    "Array of signals with current manipulated variables of controlled components"
  Modelica.Blocks.Interfaces.RealOutput manVar[nCom]
    "Array of manipulated variables for controlled components"

  Interfaces.ModularHeatPumpControlBus dataBus "Data bus with control signals"
end PartialModularController;


within AixLib.Controls;
package HVACAgentBasedControl "This package contains a library for agent-based control of HVAC systems"
extends Modelica.Icons.VariantsPackage;
end HVACAgentBasedControl;


Boolean variable to describe whether all proposals have been collected.

within AixLib.Controls.HVACAgentBasedControl.Agents;
model Broker
  extends BaseClasses.PartialAgent;

  Boolean proposalsComplete(start=false)
    "Boolean variable to describe whether all proposals have been collected";
  Boolean requestComplete(start= false)
    "Boolean variable to describe whether all requests are served by the current constellation";
  Boolean rejectsComplete( start=false);
  Real[:,7] heatSupplierTable(start=startTable);
  parameter Real[:,7] startTable = [30001,0,0,0,0,0,0; 30002,0,0,0,0,0,0]
    "Initialization table for the negotiation process. Fill first column with ProducerAgents";
  Integer proposalCounter(start=1) "Integer variable to describe proposalCounter";
  Integer counterReject(start=1) "Integer variable to describe counterReject";
  Real lowestPrice(start=0) "Real variable to define lowestPrice";
  Integer counter(start=1) "Integer variable to describe counter";
  Boolean requestsExceedSupply(start=false) "Boolean variable to describe whteher requests exceed supply";

  // Tables and variables note the requests by the consumers
  Real requestTable[10,1](start=[0;0;0;0;0;0;0;0;0;0]) "Real variable to define requestTable";
  Real requestAddresses[10,1](start=[0;0;0;0;0;0;0;0;0;0]) "Real variable to define requestAddresses";
  Real heatingRequestSum(start=0) "Real variable to define the sum of heating requests";
  Integer requestCounter(start=1) "Real variable to define requestCounter";

  // Variables for average price (for storage)
  Real totalPrice "Real variable to define totalPrice";
  Real totalHeat "Real variable to define totalHeat";
  Real averagePrice "Real variable to define averagePrice";

  // Variables for finding the lowest price combination
  Real heatingCalculationSum(start=0) "Real variable to define the sum of heatingCalculation";
  Integer cheapest(start=1) "Integer variable to define the cheapest offer";
  Real heatingPriceSum "Real variable to define the sum of heatingPrice";
  Real totalaveragePrice "Real variable to define totalaveragePrice";
  Real restHeat "Real variable to define restHeat";
  Boolean calculationDone( start=false) "Boolean variable to annonce calculationDone";

  // Variable for composing information
  Integer informationCounter(start=1) "Integer variable to define informationCounter";
  Boolean informationDone(start=false) "Boolean variable to announce informationDone";

  // Variables for requests from producers
  Boolean finalRequestDone(start=false) "Boolean variable to announce finalRequestDone";

// This section contains the blocks for the state-machine logic of the agent

public
  Modelica.StateGraph.InitialStep waiting(nIn=7, nOut=1)
  Modelica.StateGraph.TransitionWithSignal newMessage
  Modelica.StateGraph.Step message(nOut=2, nIn=1)
  Modelica.Blocks.Math.IntegerChange integerChange
  Modelica.Blocks.Sources.BooleanExpression booleanExpression(y=noEvent(
        getperformative.y[1] == 19))
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal
  Modelica.StateGraph.Step requests(nIn=2, nOut=1)
  Modelica.StateGraph.Transition waitforRequests(enableTimer=true, waitTime=10)
  Modelica.StateGraph.TransitionWithSignal newRequests
  Modelica.StateGraph.Step callForProposal(nIn=2, nOut=1)
  Modelica.StateGraph.TransitionWithSignal newProposal(waitTime=0.1,
      enableTimer=false)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression1(y=noEvent((
        getperformative.y[1] == 13) or (getperformative.y[1] == 17)))
  Modelica.StateGraph.Step collectProposal(nOut=2, nIn=1)
  Modelica.StateGraph.TransitionWithSignal allProposalsCollected(enableTimer=true, waitTime=
       0.1)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression2(y=noEvent(
        proposalsComplete))
  Modelica.StateGraph.Step sendOutRequest(nOut=1, nIn=3)

  Modelica.StateGraph.TransitionWithSignal notFinished(enableTimer=true, waitTime=
       0.1)
  Modelica.Blocks.Logical.Not not2
  Modelica.StateGraph.StepWithSignal sendCall(nOut=2, nIn=1)
  Modelica.StateGraph.Transition transition(enableTimer=true, waitTime=0.1)
  Modelica.StateGraph.StepWithSignal sendRequest(       nOut=2, nIn=1)
  Modelica.StateGraph.Transition transition1(enableTimer=true, waitTime=0.1)
  Modelica.StateGraph.Step check(nOut=2, nIn=1)
  Modelica.StateGraph.TransitionWithSignal correctPerformative(waitTime=0.5,
      enableTimer=false)
  Modelica.StateGraph.Step check1(
                                 nOut=1, nIn=1)
  Modelica.StateGraph.TransitionWithSignal correctPerformative1(
                                                               waitTime=0.5,
      enableTimer=false)
  Modelica.StateGraph.Transition requestNoted(enableTimer=true, waitTime=1)
  Modelica.StateGraph.StepWithSignal sendConfirmation(nOut=2, nIn=1)

  Modelica.StateGraph.TransitionWithSignal actionConfirmed(waitTime=0.5,
      enableTimer=false)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression5(y=noEvent((
        getperformative.y[1] == 5) and (getsender.y[1] == receiver.u[1])))

  Modelica.StateGraph.TransitionWithSignal transitionWithSignal3(
                                                                enableTimer=
       true, waitTime=0.5)
  Modelica.StateGraph.Step composeNotUnderstood(nIn=1, nOut=1)
  Modelica.StateGraph.Transition transition2(enableTimer=true, waitTime=1)
  Modelica.StateGraph.StepWithSignal sendNotUnderstood(nOut=1, nIn=1)
  Modelica.StateGraph.Transition transition4(enableTimer=true, waitTime=1)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression6(y=not (
        getperformative.y[1] == 19))

// The algorithm section contains the logic of the broker, describing the
// actions taken during each active state of the agent

  Modelica.StateGraph.Step composeInformation(nOut=1, nIn=2)
  Modelica.StateGraph.TransitionWithSignal newConfirm(waitTime=0.1, enableTimer=
       false)
  Modelica.StateGraph.Step check2(nOut=2, nIn=1)
  Modelica.StateGraph.TransitionWithSignal correctPerformative2(
                                                               waitTime=0.5,
      enableTimer=false)
  Modelica.StateGraph.Step collectConfirm(nOut=3, nIn=1)
  Modelica.StateGraph.Step computePrice(nOut=1, nIn=1)
  Modelica.StateGraph.TransitionWithSignal
                                 transition5(
                                            enableTimer=true, waitTime=0.5)
  Modelica.StateGraph.Transition transition6(
                                            enableTimer=true, waitTime=0.1)
  Modelica.StateGraph.StepWithSignal sendInformation(nIn=1, nOut=1)
  Modelica.StateGraph.TransitionWithSignal confirmComplete(waitTime=0.5,
      enableTimer=false)
  Modelica.StateGraph.Step computeFinalConstellation(nOut=1, nIn=1)
  Modelica.StateGraph.Transition transition7(
                                            enableTimer=true, waitTime=0.1)
  Modelica.StateGraph.Step checkRequestComplete(nOut=2, nIn=1)
  Modelica.StateGraph.TransitionWithSignal requestsComplete(waitTime=0.5,
      enableTimer=false)
  Modelica.StateGraph.TransitionWithSignal requestsNotComplete(waitTime=0.5,
      enableTimer=false)
  Modelica.StateGraph.TransitionWithSignal confirmNotComplete(waitTime=0.5,
      enableTimer=false)
  Modelica.Blocks.Logical.Or or1
  Modelica.Blocks.Logical.Or or2
  Modelica.Blocks.Logical.Or or3
  Modelica.Blocks.Logical.Or or4
  Modelica.Blocks.Sources.BooleanExpression booleanExpression3(y=noEvent((
        getperformative.y[1] == 5 or getperformative.y[1] == 3) and (
        getsender.y[1] == receiver.u[1])))
  Modelica.Blocks.Sources.BooleanExpression booleanExpression4(y=noEvent(
        informationDone and (abs(heatingRequestSum) >= 1)))
  Modelica.Blocks.Sources.BooleanExpression booleanExpression7(y=noEvent(not (
        informationDone)))
  Modelica.Blocks.Sources.BooleanExpression booleanExpression8(y=noEvent(
        finalRequestDone))
  Modelica.Blocks.Sources.BooleanExpression booleanExpression9(y=noEvent(not (
        finalRequestDone)))
  Modelica.StateGraph.Transition           abort(enableTimer=true, waitTime=10)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression11(y=noEvent(
        calculationDone))
  Modelica.StateGraph.Step prepareTableforRejections(nOut=1, nIn=1)
  Modelica.StateGraph.Transition transition3(
                                            enableTimer=true, waitTime=0.1)
  Modelica.StateGraph.Transition reset(enableTimer=true, waitTime=60)
  Modelica.StateGraph.Transition reset1(enableTimer=true, waitTime=60)
  Modelica.StateGraph.Transition reset2(enableTimer=true, waitTime=60)
  Modelica.StateGraph.Transition reset3(enableTimer=true, waitTime=60)
  Modelica.StateGraph.Step checkAvailability(nIn=1, nOut=2)
  Modelica.StateGraph.TransitionWithSignal enoughSupply(enableTimer=true, waitTime=
       0.1)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression10(y=noEvent(not (
        requestsExceedSupply)))
  Modelica.StateGraph.Step limitedSupplyAbort(
                                             nIn=1, nOut=1)
  Modelica.StateGraph.TransitionWithSignal enoughSupply1(enableTimer=true,
      waitTime=1)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression12(y=noEvent(
        requestsExceedSupply))
  Modelica.StateGraph.Transition reset4(enableTimer=true, waitTime=1)
algorithm
  when noEvent(waiting.active) then
    counter :=1;
    counterReject := 1;
    lowestPrice :=0;
    heatSupplierTable := startTable;
    proposalCounter := 1;

    finalRequestDone :=false;
    informationCounter :=1;
    informationDone :=false;
    heatingCalculationSum :=0;
    cheapest :=1;
    heatingPriceSum :=0;
    totalaveragePrice :=0;
    restHeat := 0;
    requestTable :=[0;0;0;0;0;0;0;0;0;0];
    requestAddresses := [0;0;0;0;0;0;0;0;0;0];
    heatingRequestSum := 0;
    requestCounter :=1;

    proposalsComplete := false;
    requestComplete := false;
    heatingRequestSum :=0;
    rejectsComplete := false;
    content.u[1] := 0;
    content.u[2] := 0;

    calculationDone := false;
    requestsExceedSupply := false;
  end when;

// Collecting requests to bundle goals
  when noEvent(requests.active) then

    // Collect the requests
    heatingRequestSum := heatingRequestSum + get_content.y[1];
    requestTable[requestCounter,1] := get_content.y[1];
    requestAddresses[requestCounter,1] := getsender.y[1];

    // Create the confirmation for the consumer agent
    performative.u[1] := 5; //"confirm"
    ontology.u[1] :=1;
    sender.u[1] := name;
    receiver.u[1] := getsender.y[1];
    reply_to.u[1] := name;
    content.u[1] := get_content.y[1];
    uDPSend_adapted.receiver := getsender.y[1];
    messageID.u[1] := name*name + integer(time);

    Modelica.Utilities.Streams.print("Broker "+ String(name)+ " collected the request of " + String(requestTable[requestCounter,1]) + " W of heat from Consumer " + String(requestAddresses[requestCounter,1])+".");

    requestCounter := requestCounter +1;
  end when;

// Broker calls all heatSuppliers in the list for a proposal for the requested heat
  when noEvent(callForProposal.active) then
      performative.u[1]:= 4;
      sender.u[1]:=name;
      receiver.u[1]:= integer(heatSupplierTable[proposalCounter,1]);
      reply_to.u[1] := name;
      content.u[1] := heatingRequestSum;
      ontology.u[1] := 1;
      uDPSend_adapted.receiver := heatSupplierTable[proposalCounter,1];
      messageID.u[1] := name*name + integer(time);
      Modelica.Utilities.Streams.print("Broker "+ String(name)+ " calls for proposal of " + String(heatingRequestSum) + " W of heat from Producer " + String(receiver.u[1])+".");
  end when;

// Receiving the proposals and add the information that proposal was received
// price for the proposal and maximum capacity
   when noEvent(collectProposal.active) then

     if noEvent(getperformative.y[1] == 13) then
      heatSupplierTable[proposalCounter,3] := get_content.y[1];
      heatSupplierTable[proposalCounter,4] := get_content.y[2];
      heatSupplierTable[proposalCounter,5] := if heatingRequestSum >=0 then (get_content.y[1]/max(0.0001,get_content.y[2])) else -(get_content.y[1]/min(0.0001,get_content.y[2]));
      heatSupplierTable[proposalCounter,7] := heatSupplierTable[proposalCounter,5];
      /*if getsender.y[1] == 30001 then
        heatSupplierTable[proposalCounter,3] := averagePrice;
        heatSupplierTable[proposalCounter,7] := averagePrice;
        end if;*/
      Modelica.Utilities.Streams.print("Broker "+ String(name)+ " collects proposal of " + String(get_content.y[2]) + " W of heat for the price of " + String(heatSupplierTable[proposalCounter,3]) + " from Producer " + String(receiver.u[1])+".");
   else
      heatSupplierTable[proposalCounter,3] := 999999999;
      heatSupplierTable[proposalCounter,4] := 0.0001;
      heatSupplierTable[proposalCounter,5] := 999999999;
      heatSupplierTable[proposalCounter,7] := 999999999;
      heatSupplierTable[proposalCounter,2] := 3;
      Modelica.Utilities.Streams.print("Broker "+ String(name)+ " collects refusal from from Producer " + String(receiver.u[1])+".");
   end if;

    if noEvent(proposalCounter== size(heatSupplierTable,1)) then
      proposalsComplete := true; //if all proposals are there go to next block
    end if;
    proposalCounter := proposalCounter +1;
  end when;

// Check whether the possible supply exceeds the demand
  when  noEvent(checkAvailability.active) then
    if abs(sum(heatSupplierTable[:,4])) < (abs(heatingRequestSum)-1) then
      Modelica.Utilities.Streams.print("Broker received less proposals than necessary to fulfill demand. Ordering all available capacity.");
      heatingRequestSum := sum(heatSupplierTable[:,4]);
    end if;
    if abs(sum(heatSupplierTable[:,4])) < 10 then
      requestsExceedSupply := true;
    end if;

  end when;

  // Abort procedure if demand exceeds supply
  when noEvent(limitedSupplyAbort.active) then
    Modelica.Utilities.Streams.print("Broker received no proposal. Abort process.");
  end when;

   // Block to compute the price
   when noEvent(computePrice.active) then
     restHeat := heatingRequestSum;

       while (abs(heatingCalculationSum)<abs(heatingRequestSum)) loop
       lowestPrice := min(heatSupplierTable[:,7]);
       for i in 1:size(heatSupplierTable,1) loop
         if noEvent(Modelica.Math.isEqual(heatSupplierTable[i,7],lowestPrice)) then
           cheapest := i;
           break;
         end if;
       end for;

       heatSupplierTable[cheapest,6] := if (heatingRequestSum > 0) then min(restHeat,heatSupplierTable[cheapest,4]) else max(restHeat,heatSupplierTable[cheapest,4]);
       heatSupplierTable[cheapest,2] := 1;
       heatingCalculationSum := heatingCalculationSum + heatSupplierTable[cheapest,6];
       heatingPriceSum := heatingPriceSum + heatSupplierTable[cheapest,6]*heatSupplierTable[cheapest,5];
       heatSupplierTable[cheapest,7] := 9999999999.0;
       restHeat := heatingRequestSum - heatingCalculationSum;

     end while;

     totalaveragePrice := heatingPriceSum/heatingCalculationSum;
     Modelica.Utilities.Streams.print("Broker "+ String(name)+ " calculates an average price of " + String(totalaveragePrice) + " per W of heat.");
     heatingRequestSum :=0;
     heatingCalculationSum := 0;
     calculationDone := true;
   end when;

   // Composeinformation for consumer agents in order to get a confirmation afterwards
   when noEvent(composeInformation.active) then
     performative.u[1]:=8;
     sender.u[1]:=name;
     receiver.u[1]:= integer(requestAddresses[informationCounter,1]);
     reply_to.u[1] := name;
     content.u[1] := totalaveragePrice*requestTable[informationCounter,1];
     content.u[2] := requestTable[informationCounter,1];
     ontology.u[1] := 1;
     uDPSend_adapted.receiver := requestAddresses[informationCounter,1];
     messageID.u[1] := name*name + integer(time);
     Modelica.Utilities.Streams.print("Broker "+ String(name)+ " asks for a confirmation of " + String(content.u[2]) + " W of heat for the total price of " + String(content.u[1]) + " from Consumer " + String(receiver.u[1])+".");
   end when;

   // Collect confirms of the consumers and catch the final amount of heat requested
   when noEvent(collectConfirm.active) then
     if noEvent(getperformative.y[1] == 5) then
       heatingRequestSum := heatingRequestSum + get_content.y[2];
     end if;

     informationCounter := informationCounter +1;
     if noEvent(requestAddresses[informationCounter,1]<1) then
       informationDone := true;
       if (abs(heatingRequestSum) >= 1) then
       Modelica.Utilities.Streams.print(String(heatingRequestSum)+ " W of heat were confirmed by consumers at broker " + String(name) +". Go on to final requests to producers.");
       else
       Modelica.Utilities.Streams.print("There was no request confirmed by consumers at broker " + String(name) +". It sends rejections to the producers.");
       end if;

     end if;

   end when;

   when noEvent(prepareTableforRejections.active) then
     for i in 1:size(heatSupplierTable,1) loop
       heatSupplierTable[i,3] := 0;
       heatSupplierTable[i,2] := 0;
     end for;
   end when;

   when noEvent(computeFinalConstellation.active) then
      if abs(sum(heatSupplierTable[:,4])) < (abs(heatingRequestSum)-1) then
        Modelica.Utilities.Streams.print("Broker received less proposals than necessary to fulfill demand. Ordering all available capacity.");
        heatingRequestSum := sum(heatSupplierTable[:,4]);
      end if;

     restHeat := heatingRequestSum;

     // Writing the right price back from column 5 to column 7 and resetting the requested capacity
     for i in 1:size(heatSupplierTable,1) loop
       heatSupplierTable[i,7] := heatSupplierTable[i,5];
       heatSupplierTable[i,6] := 0;
     end for;

     // As long as the total request is not served, the next cheapest supplier is looked for
     while (abs(heatingCalculationSum)<abs(heatingRequestSum)) loop
       lowestPrice := min(heatSupplierTable[:,7]);
       // Looking for the index of the cheapest supplier
       for i in 1:size(heatSupplierTable,1) loop
         if noEvent(Modelica.Math.isEqual(heatSupplierTable[i,7],lowestPrice)) then
           cheapest := i;
           break;
         end if;
       end for;

       heatSupplierTable[cheapest,6] := if (heatingRequestSum > 0) then min(restHeat,heatSupplierTable[cheapest,4]) else max(restHeat,heatSupplierTable[cheapest,4]); //setting the requested capacity (minimum of the maximum device capacity and the rest of heat that needs to be supplied)
       heatSupplierTable[cheapest,2] := 1; //setting approve for supplier
       heatingCalculationSum := heatingCalculationSum + heatSupplierTable[cheapest,6]; //saving the amount of heat that is approved already
       heatingPriceSum := heatingPriceSum + heatSupplierTable[cheapest,6]*heatSupplierTable[cheapest,5]; //saving the the total price of the heat so far
       heatSupplierTable[cheapest,7] := 9999999999.0; //setting the price high, so the next cheapest producer can be found in the next loop
       restHeat := heatingRequestSum - heatingCalculationSum; //calculating the amount of heat that still needs to be approved in the next loop

     end while;

     // Update the average energy price
     totalPrice := totalPrice + heatingPriceSum;
     totalHeat := totalHeat + heatingRequestSum;
     averagePrice := totalPrice/totalHeat;
     counter:=1; //reset counter for next block
   end when;

// Block to send out accept proposal to all providing producers
   when noEvent(sendOutRequest.active) then

     sender.u[1]:=name;
     receiver.u[1]:= integer(heatSupplierTable[counter,1]);
     reply_to.u[1] := name;
     content.u[1] := heatSupplierTable[counter,6];
     ontology.u[1] := 1;
     uDPSend_adapted.receiver := heatSupplierTable[counter,1];
     messageID.u[1] := name*name + integer(time);

     if noEvent(heatSupplierTable[counter,2] > 0 and heatSupplierTable[counter,2] <3) then
       performative.u[1]:=1;//accept proposal
       Modelica.Utilities.Streams.print("Broker "+ String(name)+ " accepts the proposal of " + String(receiver.u[1]) + " and orders " + String(content.u[1]) + " W of heat.");
     else
       if noEvent(heatSupplierTable[counter,2] <3) then
       performative.u[1]:=18;//reject proposal
       Modelica.Utilities.Streams.print("Broker "+ String(name)+ " rejects the proposal of " + String(receiver.u[1])+ ".");
       else
       performative.u[1]:=18;
       Modelica.Utilities.Streams.print("Broker "+ String(name)+ " accepts refusal of " + String(receiver.u[1])+ ".");
       end if;
     end if;

     counter := counter+1;

     if noEvent(counter > size(heatSupplierTable,1)) then
       finalRequestDone := true;
     end if;

   end when;

// Send out "not understood" message, if message has unknown performative
  when noEvent(composeNotUnderstood.active) then
    performative.u[1] := 11; //"not understood"
    content.u[1] := 0;
    content.u[2] := 0;
    sender.u[1] := name;
    receiver.u[1] := getsender.y[1];
    uDPSend_adapted.receiver :=  getsender.y[1];
    ontology.u[1] := getontology.y[1];
    messageID.u[1] := name*name + integer(time);
  end when;

equation
  connect(newMessage.inPort,waiting. outPort[1])
  connect(newMessage.outPort,message. inPort[1])
  connect(integerChange.y, newMessage.condition)
  connect(integerChange.u, getMessageID.y[1])
  connect(booleanExpression.y, transitionWithSignal.condition)
  connect(transitionWithSignal.outPort,requests. inPort[1])
  connect(callForProposal.inPort[1], waitforRequests.outPort)

  connect(notFinished.inPort, collectProposal.outPort[1])
  connect(not2.y, notFinished.condition)

  connect(message.outPort[1], transitionWithSignal.inPort)

  connect(notFinished.outPort, callForProposal.inPort[2])
  connect(allProposalsCollected.inPort, collectProposal.outPort[2])

  connect(transition.inPort, callForProposal.outPort[1])
  connect(transition.outPort, sendCall.inPort[1])
  connect(sendCall.outPort[1], newProposal.inPort)
  connect(sendOutRequest.outPort[1], transition1.inPort)
  connect(check.inPort[1], newProposal.outPort)
  connect(booleanExpression1.y, correctPerformative.condition)
  connect(correctPerformative.outPort, collectProposal.inPort[1])
  connect(correctPerformative.inPort, check.outPort[1])
  connect(newRequests.condition, newMessage.condition)
  connect(correctPerformative1.outPort, requests.inPort[2])
  connect(check1.outPort[1], correctPerformative1.inPort)
  connect(check1.inPort[1], newRequests.outPort)
  connect(correctPerformative1.condition, transitionWithSignal.condition)
  connect(requests.outPort[1], requestNoted.inPort)
  connect(sendConfirmation.inPort[1], requestNoted.outPort)
  connect(sendConfirmation.outPort[1], waitforRequests.inPort)

  connect(newRequests.inPort, sendConfirmation.outPort[2])
  connect(newProposal.condition, newMessage.condition)
  connect(booleanExpression2.y, not2.u)
  connect(booleanExpression2.y, allProposalsCollected.condition)
  connect(actionConfirmed.inPort, sendRequest.outPort[1])
  connect(booleanExpression5.y, actionConfirmed.condition)
  connect(transition1.outPort, sendRequest.inPort[1])

  connect(booleanExpression6.y, transitionWithSignal3.condition)
  connect(transitionWithSignal3.inPort, message.outPort[2])
  connect(transitionWithSignal3.outPort, composeNotUnderstood.inPort[1])
  connect(composeNotUnderstood.outPort[1], transition2.inPort)
  connect(transition2.outPort, sendNotUnderstood.inPort[1])
  connect(sendNotUnderstood.outPort[1], transition4.inPort)
  connect(transition4.outPort, waiting.inPort[2])
  connect(computePrice.outPort[1], transition5.inPort)
  connect(transition5.outPort, composeInformation.inPort[1])
  connect(composeInformation.outPort[1], transition6.inPort)
  connect(transition6.outPort, sendInformation.inPort[1])
  connect(sendInformation.outPort[1], newConfirm.inPort)

  connect(newConfirm.outPort, check2.inPort[1])
  connect(check2.outPort[1], correctPerformative2.inPort)
  connect(correctPerformative2.outPort, collectConfirm.inPort[1])
  connect(collectConfirm.outPort[1], confirmComplete.inPort)
  connect(confirmComplete.outPort, computeFinalConstellation.inPort[1])
  connect(computeFinalConstellation.outPort[1], transition7.inPort)
  connect(transition7.outPort, sendOutRequest.inPort[1])
  connect(actionConfirmed.outPort, checkRequestComplete.inPort[1])
  connect(checkRequestComplete.outPort[1], requestsComplete.inPort)
  connect(requestsNotComplete.outPort, sendOutRequest.inPort[2])
  connect(requestsNotComplete.inPort, checkRequestComplete.outPort[2])

  connect(confirmNotComplete.inPort, collectConfirm.outPort[2])
  connect(confirmNotComplete.outPort, composeInformation.inPort[2])
  connect(requestsComplete.outPort, waiting.inPort[1])
  connect(or1.u2, sendCall.active)
  connect(sendConfirmation.active, or1.u1)
  connect(sendNotUnderstood.active, or2.u1)
  connect(sendRequest.active, or2.u2)
  connect(sendInformation.active, or3.u2)
  connect(or1.y, or3.u1)
  connect(or4.u1, or3.y)
  connect(or4.y, uDPSend_adapted.trigger)
  connect(or2.y, or4.u2)
  connect(newConfirm.condition, newMessage.condition)
  connect(booleanExpression3.y, correctPerformative2.condition)
  connect(booleanExpression4.y, confirmComplete.condition)
  connect(booleanExpression7.y, confirmNotComplete.condition)
  connect(booleanExpression8.y, requestsComplete.condition)
  connect(booleanExpression9.y, requestsNotComplete.condition)
  connect(abort.inPort, collectConfirm.outPort[3])
  connect(booleanExpression11.y, transition5.condition)
  connect(prepareTableforRejections.inPort[1], abort.outPort)
  connect(prepareTableforRejections.outPort[1], transition3.inPort)
  connect(transition3.outPort, sendOutRequest.inPort[3])
  connect(reset.outPort, waiting.inPort[3])
  connect(reset.inPort, sendRequest.outPort[2])
  connect(reset1.inPort, check2.outPort[2])
  connect(sendCall.outPort[2], reset2.inPort)
  connect(check.outPort[2], reset3.inPort)
  connect(reset1.outPort, waiting.inPort[4])
  connect(reset2.outPort, waiting.inPort[5])
  connect(reset3.outPort, waiting.inPort[6])
  connect(checkAvailability.inPort[1], allProposalsCollected.outPort)
  connect(enoughSupply.inPort, checkAvailability.outPort[1])
  connect(enoughSupply.outPort, computePrice.inPort[1])
  connect(enoughSupply.condition, booleanExpression10.y)
  connect(enoughSupply1.outPort, limitedSupplyAbort.inPort[1])
  connect(enoughSupply1.condition, booleanExpression12.y)
  connect(checkAvailability.outPort[2], enoughSupply1.inPort)
  connect(reset4.inPort, limitedSupplyAbort.outPort[1])
  connect(reset4.outPort, waiting.inPort[7])
end Broker;


Maximum capacity for heat/cold generation (heat positive, cold negative).

within AixLib.Controls.HVACAgentBasedControl.Agents;
model ColdProducerAgent
  extends BaseClasses.PartialAgent;
  parameter Real maxCapacity = 0
    "Maximum capacity for heat/cold generation (heat positive, cold negative)";
  parameter Real minCapacity = -10000
    "Minimum capacity for heat/cold generation (heat positive, cold negative)";
  Real minCapacityInternal "Real variable to define minCapacityInternal";
  Real costCurrent(start=40) "Real variable to define costCurrent";
  Real costNew(start=0) "Real variable to define costNew";
  Real setCapacity(start=2000) "Real variable to define setCapacity";
  Real costDifference(start=0) "Real variable to define costDifference";
  Real totalRequest(start=0) "Real variable to define totalRequest";
  Real currentCapacityDiscrete(start=2000) "Real variable to define currentCapacityDiscrete";
  parameter Boolean maxCapacityExternal=false
    "Use external input for minimal capacity";

// CostFunction related components

// This section contains the blocks for the state-machine logic of the agent
  Modelica.StateGraph.InitialStep waiting(       nOut=2, nIn=4)
  Modelica.StateGraph.TransitionWithSignal newMessage
  Modelica.StateGraph.Step message(nOut=2, nIn=1)
  Modelica.StateGraph.Step adjustHeat(nIn=1, nOut=1)
  Modelica.StateGraph.Transition transition2(
      enableTimer=true, waitTime=2)

  Modelica.StateGraph.Step computeProposal(nIn=1, nOut=1)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression(y=noEvent(
        getperformative.y[1] == 4))
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal(
             waitTime=0.5, enableTimer=false)
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal1(
                        waitTime=0.5, enableTimer=false)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression1(y=noEvent(
        getperformative.y[1] == 1))
  Modelica.StateGraph.Transition transition1(                  waitTime=0.1,
      enableTimer=true)

  Modelica.StateGraph.StepWithSignal sendProposal(nOut=3, nIn=1)
  Modelica.Blocks.Math.IntegerChange integerChange
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal2(
                        waitTime=0.5, enableTimer=false)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression2(y=noEvent(
        getperformative.y[1] == 18))
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal3(
                                                                enableTimer=
       true, waitTime=0.5)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression3(y=noEvent(
        getperformative.y[1] == 4))
  Modelica.Blocks.Logical.Not not1
  Modelica.StateGraph.Step composeNotUnderstood(nIn=1, nOut=1)
  Modelica.StateGraph.Transition transition3(enableTimer=true, waitTime=1)

  Modelica.StateGraph.StepWithSignal sendNotUnderstood(nOut=1, nIn=1)
  Modelica.StateGraph.Transition transition4(enableTimer=true, waitTime=1)
  Modelica.Blocks.Logical.Or or1
  Modelica.Blocks.Interfaces.RealInput currentCapacity
    "Input for current capacity of device"
  Modelica.Blocks.Interfaces.RealOutput setCapacityOut
    "Output for set capacity of device"

  Modelica.StateGraph.StepWithSignal sendConfirmation(nOut=1, nIn=2)
  Modelica.StateGraph.Transition transition5(                  waitTime=0.1,
      enableTimer=true)
  Modelica.Blocks.Logical.Or or2

protected
  Modelica.Blocks.Interfaces.BooleanInput send

public
  Modelica.StateGraph.Step confirm(nIn=1, nOut=1)
  Modelica.StateGraph.Transition transition6(
      enableTimer=true, waitTime=2)
  Modelica.Blocks.Interfaces.RealOutput calcCapacity
    "Output to connect with cost function"
  Modelica.Blocks.Interfaces.RealInput calcCost
    "Input to connect with cost function"
  Modelica.StateGraph.TransitionWithSignal Off(enableTimer=true, waitTime=0)
  Modelica.StateGraph.Step shutDown(
                                   nOut=1, nIn=1)
  Modelica.StateGraph.Transition transition7(                  waitTime=0.1,
      enableTimer=true)
  Modelica.Blocks.Logical.Not not2
  Modelica.Blocks.Interfaces.BooleanInput OnOff_external
    "External on/off switch"
  Modelica.Blocks.Sources.BooleanExpression booleanExpression4(y=noEvent(abs(
        setCapacity) > 30))
  Modelica.Blocks.Logical.And and1
  Modelica.StateGraph.Transition reset(enableTimer=true, waitTime=60)
protected
  Modelica.Blocks.Interfaces.BooleanOutput calc_active
    "Indicator that cost calculation in cost function is active"
public
  Modelica.Blocks.Discrete.ZeroOrderHold zeroOrderHold(samplePeriod=3600)
  Modelica.Blocks.Interfaces.RealInput minCapacityInput if maxCapacityExternal
    "Input for external minimum capacity"
equation

  if maxCapacityExternal then
    //connect(maxCapacity,maxCapacityInternal);
    minCapacityInternal = zeroOrderHold.y;
  else
   minCapacityInternal = minCapacity;
  end if;

  connect(newMessage.inPort, waiting.outPort[1])
  connect(newMessage.outPort, message.inPort[1])
  connect(adjustHeat.outPort[1], transition2.inPort)
  connect(send, uDPSend_adapted.trigger)
  connect(booleanExpression.y, transitionWithSignal.condition)
  connect(computeProposal.inPort[1], transitionWithSignal.outPort)
  connect(booleanExpression1.y, transitionWithSignal1.condition)
  connect(adjustHeat.inPort[1], transitionWithSignal1.outPort)
  connect(transition1.inPort, computeProposal.outPort[1])
  connect(sendProposal.inPort[1], transition1.outPort)

  connect(getMessageID.y[1], integerChange.u)
  connect(integerChange.y, newMessage.condition)
  connect(sendProposal.outPort[1], transitionWithSignal1.inPort)
  connect(transitionWithSignal2.condition, booleanExpression2.y)

  connect(transitionWithSignal2.inPort, sendProposal.outPort[2])
  connect(message.outPort[1], transitionWithSignal.inPort)

  connect(booleanExpression3.y, not1.u)
  connect(transitionWithSignal3.condition, not1.y)
  connect(transitionWithSignal3.inPort, message.outPort[2])

  connect(composeNotUnderstood.inPort[1], transitionWithSignal3.outPort)
  connect(composeNotUnderstood.outPort[1], transition3.inPort)
  connect(transition3.outPort, sendNotUnderstood.inPort[1])
  connect(transition4.inPort, sendNotUnderstood.outPort[1])

// The algorithm section contains the logic of the broker, describing the
// actions taken during each active state of the agent
algorithm

  when noEvent(waiting.active) then
    currentCapacityDiscrete := currentCapacity;
    calcCapacity := setCapacity;
    costCurrent := calcCost;

  end when;

  // ExternalshutDown
  when noEvent(shutDown.active) then
    setCapacity :=0;
    setCapacityOut := setCapacity;
  end when;

  // Compute costs for the requested amount of heat
  when noEvent(computeProposal.active) then

    if get_content.y[1] >0 then

      if noEvent(((setCapacity+get_content.y[1]) >= maxCapacity)) then

        if noEvent(setCapacity > (maxCapacity-1)) then
          content.u[1] := 0;
          content.u[2] := 0;
          performative.u[1] := 17;
          Modelica.Utilities.Streams.print("ColdProducerAgent "+ String(name)+ " refuses proposal due to maximum capacity.");
        else
          totalRequest := maxCapacity;
          calcCapacity := totalRequest;
          calc_active := true;
          costNew := calcCost;
          content.u[2] := maxCapacity - setCapacity;
          performative.u[1] := 13; //propose
          costDifference := costNew - costCurrent;
          content.u[1] :=  costDifference;
          Modelica.Utilities.Streams.print("ColdProducerAgent "+ String(name)+ " proposes adjustment of " + String(content.u[2]) + " W " + "for a price of "+String(content.u[1])+".");
        end if;

      else
        totalRequest := setCapacity+get_content.y[1];
        calcCapacity := totalRequest;
        calc_active := true;
        costNew := calcCost;
        content.u[2] := get_content.y[1];
        performative.u[1] := 13; //propose
        costDifference := costNew - costCurrent;
        content.u[1] :=  costDifference;
        Modelica.Utilities.Streams.print("ColdProducerAgent "+ String(name)+ " proposes adjustment of " + String(content.u[2]) + " W " + "for a price of "+String(content.u[1])+".");

      end if;

    else

      if noEvent(((setCapacity+get_content.y[1]) <= minCapacityInternal)) then
        if noEvent(setCapacity < minCapacityInternal+10) then
          totalRequest := 0;
          calcCapacity := 0;
          calc_active := true;
          costNew := calcCost;
          content.u[2] := 0;
          performative.u[1] := 17; //refuse
          content.u[1] := 0;
          Modelica.Utilities.Streams.print("ColdProducerAgent "+ String(name)+ " refuses proposal due to minimum capacity.");
        else

          totalRequest := 0;
          calcCapacity := totalRequest;
          calc_active := true;
          costNew := calcCost;
          content.u[2] := minCapacityInternal - setCapacity;
          performative.u[1] := 13; //propose
          costDifference := costNew - costCurrent;
          content.u[1] :=  costDifference;
          Modelica.Utilities.Streams.print("ColdProducerAgent "+ String(name)+ " proposes adjustment of " + String(content.u[2]) + " W " + "for a price of "+String(content.u[1])+".");
        end if;

      else
        totalRequest := setCapacity+get_content.y[1];
        calcCapacity := totalRequest;
        calc_active := true;
        costNew := calcCost;
        content.u[2] := get_content.y[1];
        performative.u[1] := 13; //propose
        costDifference := costNew - costCurrent;
        content.u[1] :=  costDifference;
        Modelica.Utilities.Streams.print("ColdProducerAgent "+ String(name)+ " proposes adjustment of " + String(content.u[2]) + " W " + "for a price of "+String(content.u[1])+".");
      end if;

    end if;

    uDPSend_adapted.receiver := getsender.y[1];
    receiver.u[1] := getsender.y[1];
    ontology.u[1] := 1;
    reply_to.u[1] := name;
    sender.u[1] :=name;
    messageID.u[1] := name*name + integer(time);

    calc_active := false;

  end when;

// Adjust heat according to the confirmation by the broker, send confirmation
  when noEvent(adjustHeat.active) then

    setCapacity := setCapacity + get_content.y[1];
    setCapacityOut :=setCapacity;
    content.u[1] := 0;
    content.u[2] := 0;
    performative.u[1] := 5; //"confirm"

    uDPSend_adapted.receiver := getsender.y[1];
    receiver.u[1] := getsender.y[1];
    ontology.u[1] := 1;
    reply_to.u[1] := name;
    sender.u[1] :=name;
    messageID.u[1] := name*name + integer(time);
    Modelica.Utilities.Streams.print("ColdProducerAgent "+ String(name)+ " confirms the adjustment of " + String(get_content.y[1]) + " W of heat. The setpoint is now " + String(setCapacity) +"W.");

  end when;

// Confirm the receiving of the reject
  when noEvent(confirm.active) then
    uDPSend_adapted.receiver := getsender.y[1];
    receiver.u[1] := getsender.y[1];
    performative.u[1] := 5;
    sender.u[1] :=name;
    content.u[1] := 0;
    content.u[2] := 0;

  end when;

// Send out "not understood" message, if message has unknown performative
  when noEvent(composeNotUnderstood.active) then
    performative.u[1] := 11; //"not understood"
    content.u[1] := 0;
    content.u[2] := 0;
    messageID.u[1] := name*name + integer(time);
  end when;

equation
  connect(transition2.outPort, sendConfirmation.inPort[1])
  connect(sendConfirmation.outPort[1], transition5.inPort)
  connect(transition5.outPort, waiting.inPort[2])

  connect(send, or2.y)
  connect(or2.u2, or1.y)
  connect(sendNotUnderstood.active, or2.u1)
  connect(sendConfirmation.active, or1.u1)

  connect(sendProposal.active, or1.u2)

  connect(confirm.inPort[1], transitionWithSignal2.outPort)
  connect(transition6.inPort, confirm.outPort[1])
  connect(transition6.outPort, sendConfirmation.inPort[2])
  connect(transition4.outPort, waiting.inPort[1])
  connect(not2.u, OnOff_external)
  connect(Off.inPort, waiting.outPort[2])
  connect(Off.outPort, shutDown.inPort[1])
  connect(shutDown.outPort[1], transition7.inPort)
  connect(transition7.outPort, waiting.inPort[3])
  connect(not2.y, and1.u1)
  connect(and1.y, Off.condition)
  connect(booleanExpression4.y, and1.u2)
  connect(reset.inPort, sendProposal.outPort[3])
  connect(reset.outPort, waiting.inPort[4])
  connect(minCapacityInput, zeroOrderHold.u)

  if  maxCapacityExternal then
    connect(minCapacityInput, zeroOrderHold.u)
  else
    zeroOrderHold.u = 0;
  end if;
end ColdProducerAgent;


Name of the corresponding broker-agent.

within AixLib.Controls.HVACAgentBasedControl.Agents;
model ConsumerAgent
  extends BaseClasses.PartialAgent(
    name=10001,
    uDPSend_adapted(userBufferSize=100000, autoBufferSize=true),
    uDPReceive_adapted(userBufferSize=100000, autoBufferSize=true));

  parameter Integer broker = 10003 "Name of the corresponding broker-agent";
  parameter Real sampleStartTime = 0 "Time when the agent makes first request";
  parameter Real sampleTriggerTime = 60
    "Time difference between two calls for adjustment [s]";

  Modelica.Blocks.Sources.SampleTrigger sampleTrigger(           startTime=
        sampleStartTime, period=sampleTriggerTime)

  Modelica.StateGraph.InitialStep waiting(       nOut=2, nIn=3)
  Modelica.StateGraph.TransitionWithSignal newMessage
  Modelica.Blocks.Math.IntegerChange integerChange
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal
  Modelica.StateGraph.Step composeRequest(nOut=1, nIn=3)
  Modelica.StateGraph.Transition requestNoted(enableTimer=true, waitTime=
        0.1)
  Modelica.StateGraph.StepWithSignal sendRequest(nOut=2, nIn=1)
  Modelica.StateGraph.TransitionWithSignal newMessage1 "confirmation"
  Modelica.StateGraph.Transition repeat(enableTimer=true, waitTime=10)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression1(y=noEvent(
        getperformative.y[1] == 5))
  Modelica.StateGraph.Step state(nIn=1, nOut=2)
  Modelica.StateGraph.TransitionWithSignal rightMessage "confirmation"
  Modelica.StateGraph.Transition repeat1(enableTimer=true, waitTime=10)
  Modelica.StateGraph.Step composeNotUnderstood(nIn=1, nOut=1)
  Modelica.StateGraph.Transition transition2(enableTimer=true, waitTime=0.1)
  Modelica.StateGraph.StepWithSignal sendNotUnderstood(nOut=1, nIn=1)
  Modelica.StateGraph.Transition transition4(enableTimer=true, waitTime=0.1)
  Modelica.Blocks.Logical.Or or2

  Modelica.StateGraph.Step composeConfirm(nOut=1, nIn=1)
  Modelica.StateGraph.StepWithSignal sendConfirm(nOut=1, nIn=1)
  Modelica.StateGraph.Transition confirmNoted(enableTimer=true, waitTime=
        0.1)
  Modelica.StateGraph.Transition transition1(enableTimer=true, waitTime=0.1)
  Modelica.Blocks.Logical.Or or3
  Modelica.StateGraph.Step waitForInform(        nIn=1, nOut=2)
  Modelica.StateGraph.TransitionWithSignal rightMessage1 "confirmation"
  Modelica.Blocks.Sources.BooleanExpression booleanExpression2(y=
        getperformative.y[1] == 8)
  Modelica.Blocks.Interfaces.RealInput demand
    "Input for the demand estimation of the consumer (e.g. output of a PID element)"
  Modelica.Blocks.Logical.And and1
  Modelica.Blocks.Sources.BooleanExpression booleanExpression(y=(abs(demand)
         >= 20))
  Modelica.StateGraph.Transition reset(enableTimer=true, waitTime=180)
algorithm
  when noEvent(waiting.active) then
      content.u[1] := 0;
      content.u[2] := 0;
  end when;

  when noEvent(composeRequest.active) then
      content.u[1] := demand; //temporary function
      content.u[2] := 0;
      performative.u[1]:= 19;
      sender.u[1]:=name;
      receiver.u[1]:= broker;
      reply_to.u[1] := name;
      ontology.u[1] := 1;
      uDPSend_adapted.receiver := broker;
      messageID.u[1] := name*name + integer(time);
      Modelica.Utilities.Streams.print("ConsumerAgent "+ String(name)+ " requests " + String(content.u[1]) + " W of heat from Broker "+ String(broker)+".");
  end when;

  // Send out "not understood" message, if message has unknown performative
  when noEvent(composeNotUnderstood.active) then
    content.u[1] := 0;
    content.u[2] := 0;
    performative.u[1] := 11; //"not understood"
    sender.u[1] := name;
    receiver.u[1] := getsender.y[1];
    uDPSend_adapted.receiver :=  getsender.y[1];
    ontology.u[1] := getontology.y[1];
    messageID.u[1] := name*name + integer(time);
  end when;

  // Confirm the information by broker
  when noEvent(composeConfirm.active) then
    content.u[1] := get_content.y[1];
    content.u[2] := get_content.y[2];
    performative.u[1] := 5; //"confirm"
    receiver.u[1] := broker;
    reply_to.u[1] := name;
    ontology.u[1] := 1;
    uDPSend_adapted.receiver := broker;
    messageID.u[1] := name*name + integer(time);
    Modelica.Utilities.Streams.print("ConsumerAgent "+ String(name)+ " confirms the request of " + String(content.u[2]) + " W of heat " + "for a price of "+String(content.u[1])+".");
  end when;

equation

  connect(integerChange.u, getMessageID.y[1])
  connect(transitionWithSignal.inPort, waiting.outPort[1])
  connect(composeRequest.inPort[1], transitionWithSignal.outPort)
  connect(requestNoted.inPort, composeRequest.outPort[1])
  connect(requestNoted.outPort, sendRequest.inPort[1])
  connect(newMessage1.inPort, sendRequest.outPort[1])
  connect(repeat.outPort, composeRequest.inPort[2])
  connect(repeat.inPort, sendRequest.outPort[2])
  connect(integerChange.y, newMessage1.condition)
  connect(state.inPort[1], newMessage1.outPort)
  connect(repeat1.outPort, composeRequest.inPort[3])

  connect(repeat1.inPort, state.outPort[2])
  connect(rightMessage.inPort, state.outPort[1])
  connect(booleanExpression1.y, rightMessage.condition)

  connect(newMessage.inPort, waiting.outPort[2])
  connect(newMessage.condition, newMessage1.condition)

  connect(composeNotUnderstood.inPort[1], newMessage.outPort)
  connect(composeNotUnderstood.outPort[1], transition2.inPort)
  connect(transition2.outPort, sendNotUnderstood.inPort[1])
  connect(sendNotUnderstood.outPort[1], transition4.inPort)
  connect(transition4.outPort, waiting.inPort[2])
  connect(sendRequest.active, or2.u1)
  connect(sendNotUnderstood.active, or2.u2)

  connect(confirmNoted.inPort, composeConfirm.outPort[1])
  connect(confirmNoted.outPort, sendConfirm.inPort[1])
  connect(sendConfirm.outPort[1], transition1.inPort)
  connect(transition1.outPort, waiting.inPort[1])
  connect(or3.u1, sendConfirm.active)
  connect(or2.y, or3.u2)

  connect(or3.y, uDPSend_adapted.trigger)
  connect(waitForInform.outPort[1], rightMessage1.inPort)
  connect(booleanExpression2.y, rightMessage1.condition)
  connect(rightMessage.outPort, waitForInform.inPort[1])
  connect(rightMessage1.outPort, composeConfirm.inPort[1])
  connect(and1.u2, sampleTrigger.y)
  connect(booleanExpression.y, and1.u1)
  connect(and1.y, transitionWithSignal.condition)
  connect(waitForInform.outPort[2],reset. inPort)
  connect(reset.outPort, waiting.inPort[3])
end ConsumerAgent;


maximum capacity for heatgeneration.

within AixLib.Controls.HVACAgentBasedControl.Agents;
model HeatProducerAgent
  extends BaseClasses.PartialAgent;
  parameter Real maxCapacity = 100000 "maximum capacity for heatgeneration";
  parameter Real minCapacity = 0 "minimum capacity for heatgeneration";
  Real costCurrent(start=40) "Real variable to define costCurrent";
  Real costNew(start=0) "Real variable to define costNew";
  Real setCapacity(start=2000) "Real variable to define setCapacity";
  Real costDifference(start=0) "Real variable to define costDifference";
  Real totalRequest(start=0) "Real variable to define totalRequest";
  Real currentCapacityDiscrete(start=2000) "Real variable to define currentCapacityDiscrete";
  Real maxCapacityInternal "Real variable to define maxCapacityInternal";
  Real calcCapacityInternal(start=1) "Real variable to define calcCapacityInternal";
  parameter Boolean maxCapacityExternal=false "Real variable to define maxCapacityExternal";

// CostFunction related components

// This section contains the blocks for the state-machine logic of the agent
  Modelica.StateGraph.InitialStep waiting(       nOut=2, nIn=4)
  Modelica.StateGraph.TransitionWithSignal newMessage
  Modelica.StateGraph.Step message(nOut=2, nIn=1)
  Modelica.StateGraph.Step adjustHeat(nIn=1, nOut=1)
  Modelica.StateGraph.TransitionWithSignal
                                 transition2(
      enableTimer=true)

  Modelica.StateGraph.Step computeProposal(nIn=1, nOut=1)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression(y=noEvent(
        getperformative.y[1] == 4))
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal(
             waitTime=0.5, enableTimer=false)
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal1(
                        waitTime=0.5, enableTimer=false)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression1(y=noEvent(
        getperformative.y[1] == 1 and integerChange.y))
  Modelica.StateGraph.Transition transition1(                  waitTime=0.1,
      enableTimer=true)

  Modelica.StateGraph.StepWithSignal sendProposal(nOut=3, nIn=1)
  Modelica.Blocks.Math.IntegerChange integerChange
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal2(
                        waitTime=0.5, enableTimer=false)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression2(y=noEvent(
        getperformative.y[1] == 18 and integerChange.y))
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal3(
                                                                enableTimer=
       true, waitTime=0.5)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression3(y=noEvent(
        getperformative.y[1] == 4))
  Modelica.Blocks.Logical.Not not1
  Modelica.StateGraph.Step composeNotUnderstood(nIn=1, nOut=1)
  Modelica.StateGraph.Transition transition3(enableTimer=true, waitTime=1)

  Modelica.StateGraph.StepWithSignal sendNotUnderstood(nOut=1, nIn=1)
  Modelica.StateGraph.Transition transition4(enableTimer=true, waitTime=1)
  Modelica.Blocks.Logical.Or or1
  Modelica.Blocks.Interfaces.RealInput currentCapacity
    "Input for current capacity of device"
  Modelica.Blocks.Interfaces.RealOutput setCapacityOut
    "Output for set capacity of device"

  Modelica.StateGraph.StepWithSignal sendConfirmation(        nIn=2, nOut=1)
  Modelica.StateGraph.Transition transition5(                  waitTime=0.1,
      enableTimer=true)
  Modelica.Blocks.Logical.Or or2

public
  Modelica.StateGraph.Step confirm(nIn=1, nOut=1)
  Modelica.StateGraph.Transition transition6(
      enableTimer=true, waitTime=2)
  Modelica.Blocks.Interfaces.RealOutput calcCapacity
    "Output to connect with cost function"
  Modelica.Blocks.Interfaces.RealInput calcCost
    "Input to connect with cost function"
  Modelica.Blocks.Interfaces.BooleanInput OnOff_external
    "External on/off switch"
  Modelica.StateGraph.Step shutDown(
                                   nOut=1, nIn=1)
  Modelica.StateGraph.TransitionWithSignal Off
  Modelica.Blocks.Logical.Not not2
  Modelica.StateGraph.Transition transition7(                  waitTime=0.1,
      enableTimer=true)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression4(y=noEvent(abs(
        setCapacity) > 30))
  Modelica.Blocks.Logical.And and1
  Modelica.StateGraph.Transition reset(enableTimer=true, waitTime=60)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression5(y=setCapacityOut >=
        get_content.y[1])
  Modelica.Blocks.Interfaces.RealInput maxCapacityInput if maxCapacityExternal
    "Input for external maximum capacity"
  Modelica.Blocks.Discrete.ZeroOrderHold zeroOrderHold(samplePeriod=3600)
  Modelica.Blocks.Sources.RealExpression realExpression(y=calcCapacityInternal)
equation
  if maxCapacityExternal then
    // connect(maxCapacity,maxCapacityInternal);
    maxCapacityInternal = zeroOrderHold.y;
  else
    maxCapacityInternal = maxCapacity;
  end if;

  connect(newMessage.inPort, waiting.outPort[1])
  connect(newMessage.outPort, message.inPort[1])
  connect(adjustHeat.outPort[1], transition2.inPort)
  connect(booleanExpression.y, transitionWithSignal.condition)
  connect(computeProposal.inPort[1], transitionWithSignal.outPort)
  connect(booleanExpression1.y, transitionWithSignal1.condition)
  connect(adjustHeat.inPort[1], transitionWithSignal1.outPort)
  connect(transition1.inPort, computeProposal.outPort[1])
  connect(sendProposal.inPort[1], transition1.outPort)

  connect(getMessageID.y[1], integerChange.u)
  connect(integerChange.y, newMessage.condition)
  connect(sendProposal.outPort[1], transitionWithSignal1.inPort)
  connect(transitionWithSignal2.condition, booleanExpression2.y)

  connect(transitionWithSignal2.inPort, sendProposal.outPort[2])
  connect(message.outPort[1], transitionWithSignal.inPort)

  connect(booleanExpression3.y, not1.u)
  connect(transitionWithSignal3.condition, not1.y)
  connect(transitionWithSignal3.inPort, message.outPort[2])

  connect(composeNotUnderstood.inPort[1], transitionWithSignal3.outPort)
  connect(composeNotUnderstood.outPort[1], transition3.inPort)
  connect(transition3.outPort, sendNotUnderstood.inPort[1])
  connect(transition4.inPort, sendNotUnderstood.outPort[1])

// The algorithm section contains the logic of the broker, describing the
// actions taken during each active state of the agent
algorithm

  when noEvent(waiting.active) then
    currentCapacityDiscrete := currentCapacity;
    calcCapacityInternal := setCapacity;
    costCurrent := calcCost;

  end when;

  // ExternalshutDown
  when noEvent(shutDown.active) then
    setCapacity :=0;
    setCapacityOut := setCapacity;
  end when;

  // Compute costs for the requested amount of heat
  when noEvent(computeProposal.active) then

    if get_content.y[1] >0 then

      if noEvent(((setCapacity+get_content.y[1]) >= maxCapacityInternal)) then

        if noEvent(setCapacity > (maxCapacityInternal-1)) then
          content.u[1] := 0;
          content.u[2] := 0;
          performative.u[1] := 17;
          Modelica.Utilities.Streams.print("HeatProducerAgent "+ String(name)+ " refuses proposal due to maximum capacity.");
        else
          totalRequest := maxCapacityInternal;
          calcCapacityInternal := totalRequest;
          costNew := calcCost;
          content.u[2] := maxCapacityInternal - setCapacity;
          performative.u[1] := 13; //propose
          costDifference := costNew - costCurrent;
          content.u[1] :=  costDifference;
          Modelica.Utilities.Streams.print("HeatProducerAgent "+ String(name)+ " proposes adjustment of " + String(content.u[2]) + " W " + "for a price of "+String(content.u[1])+".");
        end if;

      else
        totalRequest := setCapacity+get_content.y[1];
        calcCapacityInternal := totalRequest;
        costNew := calcCost;
        content.u[2] := get_content.y[1];
        performative.u[1] := 13; //propose
        costDifference := costNew - costCurrent;
        content.u[1] :=  costDifference;
        Modelica.Utilities.Streams.print("HeatProducerAgent "+ String(name)+ " proposes adjustment of " + String(content.u[2]) + " W " + "for a price of "+String(content.u[1])+".");

      end if;

    else

      if noEvent(((setCapacity+get_content.y[1]) <= minCapacity)) then
        if noEvent(setCapacity < 0+1) then
          totalRequest := 0;
          calcCapacityInternal := 0;
          costNew := calcCost;
          content.u[2] := 0;
          performative.u[1] := 17; //refuse
          content.u[1] := 0;
          Modelica.Utilities.Streams.print("HeatProducerAgent "+ String(name)+ " refuses proposal due to minimum capacity.");
        else

          totalRequest := 0;
          calcCapacityInternal := totalRequest;
          costNew := calcCost;
          content.u[2] := minCapacity - setCapacity;
          performative.u[1] := 13; //propose
          costDifference := costNew - costCurrent;
          content.u[1] :=  costDifference;
          Modelica.Utilities.Streams.print("HeatProducerAgent "+ String(name)+ " proposes adjustment of " + String(content.u[2]) + " W " + "for a price of "+String(content.u[1])+".");
        end if;

      else
        totalRequest := setCapacity+get_content.y[1];
        calcCapacityInternal := totalRequest;
        costNew := calcCost;
        content.u[2] := get_content.y[1];
        performative.u[1] := 13; //propose
        costDifference := costNew - costCurrent;
        content.u[1] :=  costDifference;
        Modelica.Utilities.Streams.print("HeatProducerAgent "+ String(name)+ " proposes adjustment of " + String(content.u[2]) + " W " + "for a price of "+String(content.u[1])+".");
      end if;

    end if;

    uDPSend_adapted.receiver := getsender.y[1];
    receiver.u[1] := getsender.y[1];
    ontology.u[1] := 1;
    reply_to.u[1] := name;
    sender.u[1] :=name;
    messageID.u[1] := name*name + integer(time);

  end when;

// Adjust heat according to the confirmation by the broker, send confirmation
  when (adjustHeat.active) then

    setCapacity := setCapacity + get_content.y[1];
    setCapacityOut :=setCapacity;
    content.u[1] := 0;
    content.u[2] := 0;
    performative.u[1] := 5; //"confirm"

    uDPSend_adapted.receiver := getsender.y[1];
    receiver.u[1] := getsender.y[1];
    ontology.u[1] := 1;
    reply_to.u[1] := name;
    sender.u[1] :=name;
    messageID.u[1] := name*name + integer(time);
    Modelica.Utilities.Streams.print("HeatProducerAgent "+ String(name)+ " confirms the adjustment of " + String(get_content.y[1]) + " W of heat. The setpoint is now " + String(setCapacityOut) +"W.");

  end when;

// Confirm the receiving of the reject
  when noEvent(confirm.active) then
    uDPSend_adapted.receiver := getsender.y[1];
    receiver.u[1] := getsender.y[1];
    performative.u[1] := 5;
    sender.u[1] :=name;
    content.u[1] := 0;
    content.u[2] := 0;

  end when;

// Send out "not understood" message, if message has unknown performative
  when noEvent(composeNotUnderstood.active) then
    uDPSend_adapted.receiver := getsender.y[1];
    receiver.u[1] := getsender.y[1];
    performative.u[1] := 11; //"not understood"
    content.u[1] := 0;
    content.u[2] := 0;
    messageID.u[1] := name*name + integer(time);
    sender.u[1] :=name;
  end when;

equation

  connect(transition2.outPort, sendConfirmation.inPort[1])
  connect(sendConfirmation.outPort[1], transition5.inPort)
  connect(transition5.outPort, waiting.inPort[2])

  connect(sendNotUnderstood.active, or2.u1)
  connect(sendConfirmation.active, or1.u1)

  connect(sendProposal.active, or1.u2)

  connect(confirm.inPort[1], transitionWithSignal2.outPort)
  connect(transition6.inPort, confirm.outPort[1])
  connect(transition6.outPort, sendConfirmation.inPort[2])
  connect(transition4.outPort, waiting.inPort[1])

  /* connect(calcCapacity, calcCapacity) */
  connect(OnOff_external, not2.u)
  connect(Off.inPort, waiting.outPort[2])
  connect(shutDown.inPort[1], Off.outPort)
  connect(transition7.inPort, shutDown.outPort[1])
  connect(transition7.outPort, waiting.inPort[3])
  connect(and1.u2, booleanExpression4.y)
  connect(and1.u1, not2.y)
  connect(and1.y, Off.condition)
  connect(reset.inPort, sendProposal.outPort[3])

  connect(reset.outPort, waiting.inPort[4])
  connect(or1.y, or2.u2)
  connect(or2.y, uDPSend_adapted.trigger)
  connect(booleanExpression5.y, transition2.condition)
  if  maxCapacityExternal then
    connect(maxCapacityInput, zeroOrderHold.u)
  else
    zeroOrderHold.u = 0;
  end if;
  connect(realExpression.y, calcCapacity)
end HeatProducerAgent;


Name of the corresponding broker-agent.

within AixLib.Controls.HVACAgentBasedControl.Agents;
model IntermediateAgent
  extends BaseClasses.PartialAgent;
  parameter Integer broker = 10003 "Name of the corresponding broker-agent";
  parameter Real maxCapacity = 10000 "maximum capacity";
  Integer currentClient(start=0) "Integer variable to define currentClient";
  Real currentCost( start= 0) "Real variable to define currentCost";
  Real setCapacity(start=0) "Real variable to define setCapacity";
  Real newCost(start=0) "Real variable to define newCost";
  Real ownCost(start=0) "Real variable to define ownCost";

// CostFunction related components

// This section contains the blocks for the state-machine logic of the agent
  Modelica.StateGraph.InitialStep waiting(nOut=2, nIn=5)
  Modelica.StateGraph.TransitionWithSignal newMessage
  Modelica.StateGraph.Step message(nOut=2, nIn=1)

  Modelica.StateGraph.Step passOnCall(nIn=1, nOut=1)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression(y=noEvent(
        getperformative.y[1] == 4))
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal(
             waitTime=0.5, enableTimer=false)
  Modelica.StateGraph.Transition transition1(                  waitTime=0.1,
      enableTimer=true)

  Modelica.StateGraph.StepWithSignal sendCall(nOut=2, nIn=1)
  Modelica.Blocks.Math.IntegerChange integerChange
  Modelica.StateGraph.TransitionWithSignal transitionWithSignal3(
                                                                enableTimer=
       true, waitTime=0.5)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression3(y=noEvent(
        getperformative.y[1] == 4))
  Modelica.Blocks.Logical.Not not1
  Modelica.StateGraph.Step composeNotUnderstood(nIn=1, nOut=1)
  Modelica.StateGraph.Transition transition3(enableTimer=true, waitTime=1)

  Modelica.StateGraph.StepWithSignal sendNotUnderstood(nOut=1, nIn=1)
  Modelica.StateGraph.Transition transition4(enableTimer=true, waitTime=1)

  Modelica.StateGraph.TransitionWithSignal fromTopBroker(waitTime=0.5,
      enableTimer=false)
  Modelica.StateGraph.TransitionWithSignal newMessage1
  Modelica.StateGraph.Step check(nIn=1, nOut=1)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression4(y=noEvent((
        getperformative.y[1] == 8) and (getsender.y[1] == broker)))
  Modelica.StateGraph.Step passOnInformation(nIn=1, nOut=1)
  Modelica.StateGraph.Transition transition7(                  waitTime=0.1,
      enableTimer=true)
  Modelica.StateGraph.StepWithSignal sendInformation(nOut=2, nIn=1)
  Modelica.StateGraph.TransitionWithSignal newMessage2
  Modelica.StateGraph.Step check1(nIn=1, nOut=1)
  Modelica.StateGraph.TransitionWithSignal fromBottomBroker(waitTime=0.5,
      enableTimer=false)
  Modelica.StateGraph.Step passOnConfirmation(nIn=1, nOut=1)
  Modelica.StateGraph.Transition transition8(                  waitTime=0.1,
      enableTimer=true)
  Modelica.StateGraph.StepWithSignal sendConfirmation(
                                                     nOut=1, nIn=1)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression1(y=noEvent((
        getsender.y[1] == currentClient)))
  Modelica.StateGraph.Transition transition2(                  waitTime=0.1,
      enableTimer=true)
  Modelica.StateGraph.Step confirmToBottom(nIn=1, nOut=1)
  Modelica.StateGraph.Transition transition5(                  waitTime=0.1,
      enableTimer=true)
  Modelica.StateGraph.StepWithSignal sendConfirmation1(
                                                     nOut=1, nIn=1)
  Modelica.StateGraph.Transition transition6(                  waitTime=0.1,
      enableTimer=true)
  Modelica.Blocks.Logical.Or or1
  Modelica.Blocks.Logical.Or or2
  Modelica.Blocks.Logical.Or or3
  Modelica.Blocks.Logical.Or or4
  Modelica.Blocks.Interfaces.RealOutput calcCapacity
    "Output to connect with cost function"
  Modelica.Blocks.Interfaces.RealInput calcCost
    "Input to connect with cost function"
  Modelica.Blocks.Interfaces.RealInput currentCapacity
    "Input for current capacity of device"
  Modelica.Blocks.Interfaces.RealOutput setCapacityOut(start=0.001)
    "Output for set capacity of device"
  Modelica.StateGraph.Transition reset(enableTimer=true, waitTime=60)
  Modelica.StateGraph.Transition reset1(
                                       enableTimer=true, waitTime=60)
  Modelica.Blocks.Interfaces.BooleanInput OnOff_external
    "External on/off switch"
  Modelica.Blocks.Sources.BooleanExpression booleanExpression2(y=noEvent(abs(
        setCapacity) > 30))
  Modelica.Blocks.Logical.And and1
  Modelica.StateGraph.Step shutDown(
                                   nOut=1, nIn=1)
  Modelica.StateGraph.Transition transition9(                  waitTime=0.1,
      enableTimer=true)
  Modelica.StateGraph.TransitionWithSignal Off
  Modelica.Blocks.Logical.Not not2
equation

  connect(newMessage.inPort, waiting.outPort[1])
  connect(newMessage.outPort, message.inPort[1])
  connect(booleanExpression.y, transitionWithSignal.condition)
  connect(passOnCall.inPort[1], transitionWithSignal.outPort)
  connect(transition1.inPort, passOnCall.outPort[1])
  connect(sendCall.inPort[1], transition1.outPort)

  connect(getMessageID.y[1], integerChange.u)
  connect(integerChange.y, newMessage.condition)

  connect(message.outPort[1], transitionWithSignal.inPort)

  connect(booleanExpression3.y, not1.u)
  connect(transitionWithSignal3.condition, not1.y)
  connect(transitionWithSignal3.inPort, message.outPort[2])

  connect(composeNotUnderstood.inPort[1], transitionWithSignal3.outPort)
  connect(composeNotUnderstood.outPort[1], transition3.inPort)
  connect(transition3.outPort, sendNotUnderstood.inPort[1])
  connect(transition4.inPort, sendNotUnderstood.outPort[1])

// The algorithm section contains the logic of the broker, describing the
// actions taken during each active state of the agent
algorithm

  when waiting.active then
    currentClient := 0;
    calcCapacity := setCapacity;
    currentCost := calcCost;

  end when;

  // ExternalshutDown
  when noEvent(shutDown.active) then
    setCapacity :=0;
    setCapacityOut := setCapacity;
  end when;

  // Compute costs for the requested amount of heat
  when passOnCall.active then
    currentClient := getsender.y[1];
    performative.u[1] := 19;
    sender.u[1] := name;
    receiver.u[1] := broker;
    reply_to.u[1] := name;
    content.u[1] := get_content.y[1];
    content.u[2] := get_content.y[2];
    ontology.u[1] := getontology.y[1];
    uDPSend_adapted.receiver := broker;
    messageID.u[1] := name*name + integer(time);
    Modelica.Utilities.Streams.print("IntermediateAgent "+ String(name)+ " got a call from bottom broker " + String(currentClient) + " and passes it on to top broker " + String(broker) +".");
  end when;

  when passOnInformation.active then
    performative.u[1] := 13;
    sender.u[1] := name;
    reply_to.u[1] := name;
    receiver.u[1] := currentClient;
    uDPSend_adapted.receiver := currentClient;
    calcCapacity := get_content.y[2];
    newCost :=calcCost;
    ownCost := newCost -currentCost;
    content.u[1] := get_content.y[1]+ownCost;
    content.u[2] := get_content.y[2];
    ontology.u[1] := getontology.y[1];
    messageID.u[1] := name*name + integer(time);
    Modelica.Utilities.Streams.print("IntermediateAgent "+ String(name)+ " got an information from top broker " + String(broker) + " and passes it on as a proposal to bottom broker " + String(currentClient) +" after adding own costs of " + String(ownCost) +".");
  end when;

  when passOnConfirmation.active then
    if getperformative.y[1] == 1 then
      performative.u[1] := 5;
      Modelica.Utilities.Streams.print("IntermediateAgent "+ String(name)+ " got an accept proposal from " + String(currentClient) + " and passes it on as a confirmation to top broker " + String(broker) +".");
    else
      performative.u[1] := 3;
      Modelica.Utilities.Streams.print("IntermediateAgent "+ String(name)+ " got an reject proposal from " + String(currentClient) + " and passes it on as a cancel to top broker " + String(broker) +".");
    end if;

      sender.u[1] := name;
      receiver.u[1] := broker;
      reply_to.u[1] := name;
      uDPSend_adapted.receiver := broker;
      content.u[1] := get_content.y[2];
      content.u[2] := get_content.y[1];
      ontology.u[1] := getontology.y[1];
      messageID.u[1] := name*name + integer(time);

  end when;

  when confirmToBottom.active then
    performative.u[1] := 5;
    sender.u[1] := name;
    reply_to.u[1] := name;
    receiver.u[1] := currentClient;
    uDPSend_adapted.receiver := currentClient;
    content.u[1] := get_content.y[2];
    content.u[2] := get_content.y[1];
    ontology.u[1] := getontology.y[1];
    messageID.u[1] := name*name + integer(time);
    if getperformative.y[1] == 1 then
      Modelica.Utilities.Streams.print("IntermediateAgent "+ String(name)+ " confirms the adjustment of " + String(get_content.y[1]) + " W of heat.");
      setCapacity := max(min(setCapacity+get_content.y[1],maxCapacity),0);
      setCapacityOut := setCapacity;
    end if;
  end when;

// Send out "not understood" message, if message has unknown performative
  when composeNotUnderstood.active then
    performative.u[1] := 11; //"not understood"
    content.u[1] := 0;
    content.u[2] := 0;
    messageID.u[1] := name*name + integer(time);
  end when;

equation

  connect(transition4.outPort, waiting.inPort[1])

  connect(sendCall.outPort[1], newMessage1.inPort)
  connect(newMessage1.outPort, check.inPort[1])
  connect(check.outPort[1], fromTopBroker.inPort)
  connect(fromTopBroker.outPort, passOnInformation.inPort[1])
  connect(passOnInformation.outPort[1], transition7.inPort)
  connect(transition7.outPort, sendInformation.inPort[1])
  connect(sendInformation.outPort[1], newMessage2.inPort)
  connect(newMessage2.outPort, check1.inPort[1])
  connect(check1.outPort[1], fromBottomBroker.inPort)
  connect(fromBottomBroker.outPort, passOnConfirmation.inPort[1])
  connect(passOnConfirmation.outPort[1], transition8.inPort)
  connect(transition8.outPort, sendConfirmation.inPort[1])
  connect(booleanExpression4.y, fromTopBroker.condition)
  connect(booleanExpression1.y, fromBottomBroker.condition)
  connect(sendConfirmation.outPort[1], transition2.inPort)

  connect(transition2.outPort, confirmToBottom.inPort[1])
  connect(confirmToBottom.outPort[1], transition5.inPort)
  connect(transition5.outPort, sendConfirmation1.inPort[1])
  connect(transition6.inPort, sendConfirmation1.outPort[1])
  connect(transition6.outPort, waiting.inPort[2])
  connect(newMessage1.condition, integerChange.y)
  connect(newMessage2.condition, newMessage.condition)
  connect(sendCall.active, or1.u1)
  connect(sendInformation.active, or1.u2)
  connect(sendNotUnderstood.active, or2.u2)
  connect(sendConfirmation1.active, or2.u1)
  connect(or3.u1, sendConfirmation.active)
  connect(or2.y, or3.u2)

  connect(or4.u2, or3.y)
  connect(or4.y, uDPSend_adapted.trigger)
  connect(or4.u1, or1.y)
  connect(reset.inPort, sendCall.outPort[2])
  connect(sendInformation.outPort[2], reset1.inPort)
  connect(reset.outPort, waiting.inPort[3])
  connect(reset1.outPort, waiting.inPort[4])
  connect(and1.u2, booleanExpression2.y)
  connect(Off.inPort, waiting.outPort[2])
  connect(Off.outPort, shutDown.inPort[1])
  connect(shutDown.outPort[1], transition9.inPort)
  connect(and1.y, Off.condition)
  connect(transition9.outPort, waiting.inPort[5])
  connect(OnOff_external, not2.u)
  connect(not2.y, and1.u1)
end IntermediateAgent;


Number of Boolean inputs (number of other agents in the system).

within AixLib.Controls.HVACAgentBasedControl.Agents;
model MessageNotification

  parameter Integer n=1
    "Number of Boolean inputs (number of other agents in the system)";
  parameter Boolean usePoke=false
    "Mode for different type of communication (standard is false)";

  Modelica.Blocks.MathBoolean.Or receiverCollector(nu=n) if usePoke
  Modelica.Blocks.Interfaces.BooleanInput  receive[n] if usePoke
    "Input to connect with other agents"
  Modelica.Blocks.Interfaces.BooleanOutput y
    "Notification for other agents (not connected to anything)"
equation
  connect(receive,receiverCollector. u)

  if usePoke then
    connect(receiverCollector.y, y)
  else
    y = false;
  end if;
end MessageNotification;