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;


Set temperature by the user.

within AixLib.Controls.HVACAgentBasedControl.Agents;
model RoomAgent
  extends BaseClasses.PartialAgent(
    name=10001,
    uDPSend_adapted(userBufferSize=100000, autoBufferSize=true),
    uDPReceive_adapted(userBufferSize=100000, autoBufferSize=true));
  parameter Real T_set = 273.15+20 "Set temperature by the user";
  parameter Integer broker = 10003 "Name of the corresponding broker-agent";
  parameter Real startTime = 0 "Time when the agent makes first request";
  parameter Real threshold = 2
    "Temperature threshold difference when agent gets active";
  parameter Real sampleTriggerTime = 60
    "Time difference between two calls for adjustment [s]";
  parameter Real P=50 "Proportional factor for load estimation";
  parameter Real Kd = 30000 "Derivative factor for load estimation";
  parameter Real G=1 "Gain for the load estimation";

  Modelica.Blocks.Interfaces.RealInput T "Room temperature"

  Modelica.Blocks.Math.Add add(k2=-1)
  Modelica.Blocks.Logical.GreaterThreshold T_too_high(threshold=threshold)
  Modelica.Blocks.Math.Add add1(k2=-1)
  Modelica.Blocks.Logical.GreaterThreshold T_too_low(threshold=threshold)
  Modelica.Blocks.Sources.SampleTrigger sampleTrigger(           startTime=
        startTime, period=sampleTriggerTime)
  Modelica.Blocks.Logical.Or or1

  Modelica.Blocks.Logical.And actionTrigger
  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=1)
  Modelica.StateGraph.StepWithSignal sendRequest(nOut=2, nIn=1)
  Modelica.StateGraph.TransitionWithSignal newMessage1 "confirmation"
  Modelica.StateGraph.Transition repeat(enableTimer=true, waitTime=
        100000000)
  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=
        100000000000.0)
  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.Logical.Or or2

protected
  Modelica.Blocks.Interfaces.RealOutput T_ref

public
  Modelica.StateGraph.Step composeConfirm(nOut=1, nIn=1)
  Modelica.StateGraph.StepWithSignal sendConfirm(nOut=1, nIn=1)
  Modelica.StateGraph.Transition confirmNoted(enableTimer=true, waitTime=1)
  Modelica.StateGraph.Transition transition1(enableTimer=true, waitTime=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=noEvent(
        getperformative.y[1] == 8))
  Modelica.Blocks.Continuous.Derivative derivative
  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] := G*(P*add1.y+Kd*derivative.y); //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("RoomAgent "+ 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("RoomAgent "+ String(name)+ " confirms the request of " + String(content.u[2]) + " W of heat " + "for a price of "+String(content.u[1])+".");
  end when;

equation
  T_ref = T_set;

  connect(T, add.u1)
  connect(add.u2, T_ref)
  connect(add.y, T_too_high.u)
  connect(add1.u2, add.u1)
  connect(add1.u1, T_ref)
  connect(T_too_low.u, add1.y)
  connect(T_too_low.y, or1.u2)

  connect(T_too_high.y, or1.u1)

  connect(T_ref, T_ref)
  connect(actionTrigger.u2, sampleTrigger.y)
  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(actionTrigger.y, transitionWithSignal.condition)
  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(derivative.u, add1.y)
  connect(or1.y, actionTrigger.u1)
  connect(waitForInform.outPort[2], reset.inPort)
  connect(reset.outPort, waiting.inPort[3])
end RoomAgent;


Name of the agent (five-digit number, eg. 10001).

within AixLib.Controls.HVACAgentBasedControl.BaseClasses;
partial model PartialAgent
  parameter Integer name "Name of the agent (five-digit number, eg. 10001)";
  parameter Boolean usePoke=false
    "Use Modelica internal communication for inbox update";
  parameter Real sampleRate=5
    "Sample time for inbox update (used if usePoke=false)";

  outer HVACAgentBasedControl.Agents.MessageNotification messageNotification
 if usePoke;

  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.Packager packager
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.AddReal content(nu=1, n=2)
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.GetReal get_content(nu=
       1, n=2)
  Modelica_DeviceDrivers.Blocks.Communication.UDPReceive
                     uDPReceive_adapted(port_recv=name,
    enableExternalTrigger= if usePoke then true else false,
    sampleTime= if usePoke then 10e20 else sampleRate)
  UDPSend_adapted                                       uDPSend_adapted
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.AddInteger sender(nu=1)
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.AddInteger receiver(nu=
       1)
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.AddInteger reply_to(nu=
       1)
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.AddReal    ontology(nu=1)
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.GetInteger
    getperformative(nu=1)
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.GetInteger getsender(
      nu=1)
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.GetInteger getreceiver(
      nu=1)
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.GetInteger getreply_to(
      nu=1)
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.GetReal    getontology(nu=1)
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.AddInteger performative(nu=1)
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.GetInteger getMessageID
  Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.AddInteger messageID(nu=1)
  inner Modelica.StateGraph.StateGraphRoot stateGraphRoot
  SendSample                                       sendSample
                                                     if usePoke
  Modelica.Blocks.Interfaces.BooleanOutput sendOut if usePoke
    "Turns true when the sending unit of the agent is active"
equation

  if usePoke then
  connect(messageNotification.y, uDPReceive_adapted.trigger);
  end if;
  connect(sender.pkgOut[1], receiver.pkgIn)
  connect(receiver.pkgOut[1], reply_to.pkgIn)
  connect(reply_to.pkgOut[1], content.pkgIn)
  connect(content.pkgOut[1], ontology.pkgIn)
  connect(getperformative.pkgIn, uDPReceive_adapted.pkgOut)
  connect(getperformative.pkgOut[1], getsender.pkgIn)
  connect(getsender.pkgOut[1], getreceiver.pkgIn)
  connect(getreceiver.pkgOut[1], getreply_to.pkgIn)
  connect(getreply_to.pkgOut[1], get_content.pkgIn)
  connect(get_content.pkgOut[1], getontology.pkgIn)
  connect(performative.pkgIn, packager.pkgOut)
  connect(performative.pkgOut[1], sender.pkgIn)
  connect(getontology.pkgOut[1], getMessageID.pkgIn)
  connect(ontology.pkgOut[1], messageID.pkgIn)
  connect(messageID.pkgOut[1], uDPSend_adapted.pkgIn)
  connect(sendSample.u, uDPSend_adapted.send)
  connect(sendOut, sendSample.y)
end PartialAgent;


Input to connect with ProducerAgent.

within AixLib.Controls.HVACAgentBasedControl.BaseClasses;
partial model PartialCostFunction

  Modelica.Blocks.Interfaces.RealInput capacity
    "Input to connect with ProducerAgent"
  Modelica.Blocks.Interfaces.RealOutput cost
    "Output to connect with ProducerAgent"
equation
end PartialCostFunction;


Input connected to boolean output of UDPSend_adapted.

within AixLib.Controls.HVACAgentBasedControl.BaseClasses;
model SendSample

  Modelica.Blocks.MathBoolean.Or or1(nu=4)
  Modelica.Blocks.MathBoolean.OnDelay onDelay4(delayTime=0.1)
  Modelica.Blocks.MathBoolean.OnDelay onDelay5(delayTime=0.2)
  Modelica.Blocks.MathBoolean.OnDelay onDelay6(delayTime=0.5)
  Modelica.Blocks.MathBoolean.OnDelay onDelay7(delayTime=1)
  Modelica.Blocks.Interfaces.BooleanInput u
    "Input connected to boolean output of UDPSend_adapted"
  Modelica.Blocks.Interfaces.BooleanOutput y
    "Output connected to sendOut of PartialAgent"
  Modelica.Blocks.Logical.Edge edge1
  Modelica.Blocks.Logical.Edge edge2
  Modelica.Blocks.Logical.Edge edge3
  Modelica.Blocks.Logical.Edge edge4
equation
  connect(onDelay4.u, u)
  connect(or1.y, y)
  connect(edge1.u, onDelay4.y)
  connect(onDelay5.y, edge2.u)
  connect(onDelay6.y, edge3.u)
  connect(onDelay7.y, edge4.u)
  connect(onDelay5.u, u)
  connect(onDelay6.u, u)
  connect(onDelay7.u, u)
  connect(edge1.y, or1.u[1])
  connect(edge2.y, or1.u[2])
  connect(edge3.y, or1.u[3])
  connect(edge4.y, or1.u[4])
end SendSample;


A block for sending UDP datagrams.

within AixLib.Controls.HVACAgentBasedControl.BaseClasses;
model UDPSend_adapted "A block for sending UDP datagrams"
  import Modelica_DeviceDrivers;
  extends Modelica_DeviceDrivers.Utilities.Icons.BaseIcon;
  extends Modelica_DeviceDrivers.Utilities.Icons.UDPconnection;
  import Modelica_DeviceDrivers.Packaging.SerialPackager;
  import Modelica_DeviceDrivers.Communication.UDPSocket;

  // Parameter Modelica.SIunits.Period sampleTime=0.01
  //  "Sample time for update";
  parameter Boolean autoBufferSize = true
    "true, buffer size is deduced automatically, otherwise set it manually."
  parameter Integer userBufferSize=16*1024
    "Buffer size of message data in bytes (if not deduced automatically)."
  parameter String IPAddress="127.0.0.1" "IP address of remote UDP server"
  Real port_send "Target port of the receiving UDP server"
  Modelica_DeviceDrivers.Blocks.Interfaces.PackageIn pkgIn
    "Port for the data to send"
protected
  UDPSocket socket = UDPSocket(0);
  Integer bufferSize;
  Real dummy;
public
  Modelica.Blocks.Interfaces.BooleanInput trigger
    "Input to start the sending procedure"
  Modelica.Blocks.Interfaces.RealInput receiver
    "Input for receiving agent name"
  Modelica.Blocks.Interfaces.BooleanOutput send
    "Turns true when a message is send"
equation
  port_send = receiver;
  when initial() then
    pkgIn.userPkgBitSize = if autoBufferSize then -1 else userBufferSize*8;
    pkgIn.autoPkgBitSize = 0;
    bufferSize = if autoBufferSize then Modelica_DeviceDrivers.Packaging.SerialPackager_.getBufferSize(pkgIn.pkg) else userBufferSize;
  end when;
  pkgIn.backwardTrigger = trigger;
  // pkgIn.backwardTrigger = noEvent(sample(0, sampleTime));
  when noEvent(trigger) then
    dummy = AixLib.Controls.HVACAgentBasedControl.BaseClasses.Internal.sendToUDP(
      socket,
      IPAddress,
      port_send,
      pkgIn.pkg,
      bufferSize,
      pkgIn.dummy);
  end when;
  connect(trigger, send)
end UDPSend_adapted;


<span style=\

within AixLib.Controls.HVACAgentBasedControl;
package CostFunctions
  extends Modelica.Icons.VariantsPackage;
end CostFunctions;


Price per kWh of fuel. Overview

within AixLib.Controls.HVACAgentBasedControl.CostFunctions.Economic;
model Constant_Economic_Cost
  extends HVACAgentBasedControl.BaseClasses.PartialCostFunction;
  parameter Real p = 0.30 "Price per kWh of fuel";
  parameter Real eta = 0.95 "thermal efficiency of the device";

equation
  cost = (p/eta) * capacity;
end Constant_Economic_Cost;


Price per kWh of fuel. Overview

within AixLib.Controls.HVACAgentBasedControl.CostFunctions.Economic;
model PV_Variable_Economic_Cost
  extends HVACAgentBasedControl.BaseClasses.PartialCostFunction;
  parameter Real p = 0.30 "Price per kWh of fuel";
  parameter Real eta = 0.95 "thermal efficiency of the device";
  parameter Real rad_treshold = 310 "Treshold when electricity is free";

  Modelica.Blocks.Interfaces.RealInput rad "Input for solar radiation"
  Modelica.Blocks.Logical.GreaterEqualThreshold
                                             lessEqualThreshold(threshold=
        rad_treshold)
  Modelica.Clocked.RealSignals.Sampler.SampleClocked sample1
  Modelica.Clocked.ClockSignals.Clocks.PeriodicRealClock periodicClock1(period=
        300)
  Modelica.Clocked.RealSignals.Sampler.Hold hold1(y_start=100)
  Modelica.Blocks.Math.Product product
  Modelica.Blocks.Logical.Switch switch1
  Modelica.Blocks.Sources.RealExpression realExpression(y=(p/eta))
  Modelica.Blocks.Sources.RealExpression realExpression1(y=0.0001)
  Modelica.Blocks.Interfaces.BooleanOutput electricity_free
    "Indicator if electricity is considered free"
equation

  connect(sample1.u, rad)
  connect(periodicClock1.y, sample1.clock)
  connect(sample1.y, hold1.u)
  connect(hold1.y, lessEqualThreshold.u)
  connect(capacity, product.u2)
  connect(switch1.u2, lessEqualThreshold.y)
  connect(switch1.y, product.u1)
  connect(product.y, cost)
  connect(lessEqualThreshold.y, electricity_free)
  connect(switch1.u1, realExpression1.y)
  connect(switch1.u3, realExpression.y)
end PV_Variable_Economic_Cost;


Exergy reference temperature.

within AixLib.Controls.HVACAgentBasedControl.CostFunctions.Exergy;
model Boiler_ExergyDestruction
  extends HVACAgentBasedControl.BaseClasses.PartialCostFunction;
  parameter Real T_0 = 298.15 "Exergy reference temperature";
  parameter Real eta = 0.84 "Overall efficiency of the boiler";

  Real m_flow "mass flow";

  Modelica.Blocks.Interfaces.RealInput T_in
  Modelica.Blocks.Interfaces.RealInput T_out

equation
  m_flow = capacity/(4182*(T_out-T_in));
  cost= -capacity - (m_flow*T_0*4182*log(T_in/T_out)) + 0.9257 * capacity/eta;
end Boiler_ExergyDestruction;


Exergy reference temperature.

within AixLib.Controls.HVACAgentBasedControl.CostFunctions.Exergy;
model Boiler_ExergyDestruction_Simplified
  extends HVACAgentBasedControl.BaseClasses.PartialCostFunction;
  parameter Real T_0 = 298.15 "Exergy reference temperature";
  parameter Real eta = 0.84 "Overall efficiency of the boiler";

  Modelica.Blocks.Math.Division division
  Modelica.Blocks.Sources.RealExpression realExpression(y=eta)
  Modelica.Blocks.Math.Division division1
  Modelica.Blocks.Sources.RealExpression realExpression1(y=T_0)
  Modelica.Blocks.Math.Add add(k2=-1)
  Modelica.Blocks.Sources.RealExpression realExpression3(y=1)
  Modelica.Blocks.Math.Product product
  Modelica.Blocks.Math.Add add1(k2=-1)
  Modelica.Blocks.Math.Gain gain(k=0.9257)
  Modelica.Blocks.Interfaces.RealInput T_circuit
  Modelica.Blocks.Math.Max min
  Modelica.Blocks.Sources.RealExpression realExpression2(y=274.15)
equation
  connect(division.u2, realExpression.y)
  connect(division1.u1, realExpression1.y)
  connect(division1.y, add.u2)
  connect(add.u1, realExpression3.y)
  connect(add.y, product.u1)
  connect(capacity, product.u2)
  connect(division.u1, product.u2)
  connect(product.y, add1.u2)
  connect(add1.y, cost)
  connect(division.y, gain.u)
  connect(gain.y, add1.u1)
  connect(min.y, division1.u2)
  connect(min.u1, realExpression2.y)
  connect(min.u2, T_circuit)
end Boiler_ExergyDestruction_Simplified;


Exergy reference temperature.

within AixLib.Controls.HVACAgentBasedControl.CostFunctions.Exergy;
model HeatingRod_ExergyDestruction
  extends HVACAgentBasedControl.BaseClasses.PartialCostFunction;
  parameter Real T_0 = 298.15 "Exergy reference temperature";
  parameter Real eta = 0.97 "Overall efficiency of the boiler";

  Real T_in "Inlet temperature";

  Modelica.Blocks.Interfaces.RealInput T_below
    "Temperature of the storage water layer below the heating rod"
  Modelica.Blocks.Interfaces.RealInput m_flow(start=0.5, fixed=true)

equation
  T_in = T_below;

  cost= -(m_flow*T_0*4182*log(T_in/(T_in+capacity/(4182*m_flow))));
end HeatingRod_ExergyDestruction;


Exergy reference temperature.

within AixLib.Controls.HVACAgentBasedControl.CostFunctions.Exergy;
model HeatingRod_ExergyDestruction_Simplified
  extends HVACAgentBasedControl.BaseClasses.PartialCostFunction;
  parameter Real T_0 = 298.15 "Exergy reference temperature";
  parameter Real eta = 1 "Overall efficiency of the boiler";

  Modelica.Blocks.Math.Division division
  Modelica.Blocks.Sources.RealExpression realExpression(y=eta)
  Modelica.Blocks.Math.Division division1
  Modelica.Blocks.Sources.RealExpression realExpression1(y=T_0)
  Modelica.Blocks.Math.Add add(k2=-1)
  Modelica.Blocks.Sources.RealExpression realExpression3(y=1)
  Modelica.Blocks.Math.Product product
  Modelica.Blocks.Math.Add add1(k2=-1)
  Modelica.Blocks.Math.Gain gain(k=1)
  Modelica.Blocks.Interfaces.RealInput T_circuit
  Modelica.Blocks.Math.Max min
  Modelica.Blocks.Sources.RealExpression realExpression2(y=274.15)
equation
  connect(division.u2, realExpression.y)
  connect(division1.u1, realExpression1.y)
  connect(division1.y, add.u2)
  connect(add.u1, realExpression3.y)
  connect(add.y, product.u1)
  connect(capacity, product.u2)
  connect(division.u1, product.u2)
  connect(product.y, add1.u2)
  connect(add1.y, cost)
  connect(division.y, gain.u)
  connect(gain.y, add1.u1)
  connect(min.y, division1.u2)
  connect(min.u1, realExpression2.y)
  connect(min.u2, T_circuit)
end HeatingRod_ExergyDestruction_Simplified;


Exergy reference temperature.

within AixLib.Controls.HVACAgentBasedControl.CostFunctions.Exergy;
model HeatPump_ExergyDestruction_Cooling
  extends HVACAgentBasedControl.BaseClasses.PartialCostFunction;
  parameter Real T_0 = 298.15 "Exergy reference temperature";

  parameter Real tablePower[:, :] = fill(0.0, 0, 2)
    "table matrix (grid u1 = first column, grid u2 = first row; e.g., table=[0,0;0,1])";
  parameter Real tableHeatFlowCondenser[:, :] = fill(0.0, 0, 2)
    "table matrix (grid u1 = first column, grid u2 = first row; e.g., table=[0,0;0,1])";

  Real COP "Cooefficient of performance";

  Modelica.Blocks.Sources.RealExpression realExpression(y=1 - (1/COP))
  Modelica.Blocks.Math.Add add1(k2=+1)
  Modelica.Blocks.Math.Add add2(k2=-1)
  Modelica.Blocks.Math.Add add4(k2=-1)
  Modelica.Blocks.Math.Division division1
  Modelica.Blocks.Sources.RealExpression realExpression1(y=T_0)
  Modelica.Blocks.Interfaces.RealInput T_cold
  Modelica.Blocks.Sources.RealExpression realExpression2(y=1)
  Modelica.Blocks.Math.Product product
  Modelica.Blocks.Interfaces.RealInput T_hot
  Modelica.Blocks.Math.Division division2
  Modelica.Blocks.Sources.RealExpression realExpression3(y=T_0)
  Modelica.Blocks.Sources.RealExpression realExpression4(y=1)
  Modelica.Blocks.Math.Add add5(k2=-1)
  Modelica.Blocks.Math.Product product1
  Modelica.Blocks.Math.Division division3
  Modelica.Blocks.Sources.RealExpression realExpression5(y=COP)
  Modelica.Blocks.Math.Division division4
  Modelica.Blocks.Math.Add add3(k2=-1)
  Modelica.Blocks.Tables.CombiTable2Ds PowerTable(table=tablePower)
  Modelica.Blocks.Tables.CombiTable2Ds HeatFlowCondenserTable(table=
        tableHeatFlowCondenser)
equation

 COP = HeatFlowCondenserTable.y/PowerTable.y;
  connect(add1.y, add2.u1)
  connect(division1.u1, realExpression1.y)
  connect(division1.u2, T_cold)
  connect(add4.u1, realExpression2.y)
  connect(division1.y, add4.u2)
  connect(add4.y, product.u2)
  connect(realExpression3.y, division2.u1)
  connect(division2.u2, T_hot)
  connect(add5.u2, division2.y)
  connect(add5.y, product1.u2)
  connect(realExpression4.y, add5.u1)
  connect(cost, add2.y)
  connect(product1.y, add1.u1)
  connect(division3.u2, realExpression.y)
  connect(product1.u1, division3.y)
  connect(capacity, division3.u1)
  connect(realExpression5.y, division4.u2)
  connect(division4.u1, division3.y)
  connect(add2.u2, product.y)
  connect(add1.u2, division4.y)
  connect(add3.u2, division4.y)
  connect(add3.u1, division3.u1)
  connect(add3.y, product.u1)
  connect(T_hot, HeatFlowCondenserTable.u1)
  connect(T_hot, PowerTable.u1)
  connect(T_cold, PowerTable.u2)
  connect(HeatFlowCondenserTable.u2, T_cold)
end HeatPump_ExergyDestruction_Cooling;


Exergy reference temperature.

within AixLib.Controls.HVACAgentBasedControl.CostFunctions.Exergy;
model HeatPump_ExergyDestruction_Heating
  extends HVACAgentBasedControl.BaseClasses.PartialCostFunction;
  parameter Real T_0 = 298.15 "Exergy reference temperature";

  parameter Real tablePower[:, :] = fill(0.0, 0, 2)
    "table matrix (grid u1 = first column, grid u2 = first row; e.g., table=[0,0;0,1])";
  parameter Real tableHeatFlowCondenser[:, :] = fill(0.0, 0, 2)
    "table matrix (grid u1 = first column, grid u2 = first row; e.g., table=[0,0;0,1])";

  Real COP "Cooefficient of performance";

  Modelica.Blocks.Sources.RealExpression realExpression(y=COP)
  Modelica.Blocks.Math.Add add1(k2=+1)
  Modelica.Blocks.Math.Add add2(k2=-1)
  Modelica.Blocks.Math.Division division
  Modelica.Blocks.Math.Add add3(k1=-1, k2=+1)
  Modelica.Blocks.Math.Add add4(k2=-1)
  Modelica.Blocks.Math.Division division1
  Modelica.Blocks.Sources.RealExpression realExpression1(y=T_0)
  Modelica.Blocks.Interfaces.RealInput T_cold
  Modelica.Blocks.Sources.RealExpression realExpression2(y=1)
  Modelica.Blocks.Math.Product product
  Modelica.Blocks.Interfaces.RealInput T_hot
  Modelica.Blocks.Math.Division division2
  Modelica.Blocks.Sources.RealExpression realExpression3(y=T_0)
  Modelica.Blocks.Sources.RealExpression realExpression4(y=1)
  Modelica.Blocks.Math.Add add5(k2=-1)
  Modelica.Blocks.Math.Product product1
  Modelica.Blocks.Tables.CombiTable2Ds HeatFlowCondenserTable(table=
        tableHeatFlowCondenser)
  Modelica.Blocks.Tables.CombiTable2Ds PowerTable(table=tablePower)
equation
   COP = HeatFlowCondenserTable.y/PowerTable.y;
  connect(add1.y, add2.u1)
  connect(division.u2, realExpression.y)
  connect(division.u1, capacity)
  connect(add3.u2, capacity)
  connect(division.y, add3.u1)
  connect(division1.u1, realExpression1.y)
  connect(division1.u2, T_cold)
  connect(add4.u1, realExpression2.y)
  connect(division1.y, add4.u2)
  connect(add3.y, product.u1)
  connect(add4.y, product.u2)
  connect(add1.u1, division.y)
  connect(add1.u2, product.y)
  connect(realExpression3.y, division2.u1)
  connect(division2.u2, T_hot)
  connect(add5.u2, division2.y)
  connect(add5.y, product1.u2)
  connect(product1.u1, capacity)
  connect(product1.y, add2.u2)
  connect(realExpression4.y, add5.u1)
  connect(add2.y, cost)
  connect(T_hot,HeatFlowCondenserTable. u1)
  connect(T_cold,PowerTable. u2)
  connect(T_hot,PowerTable. u1)
  connect(HeatFlowCondenserTable.u2, T_cold)
end HeatPump_ExergyDestruction_Heating;


Exergy reference temperature.

within AixLib.Controls.HVACAgentBasedControl.CostFunctions.Exergy;
model MixingValveAndHEX_ExergyDestruction
  extends HVACAgentBasedControl.BaseClasses.PartialCostFunction;
  parameter Real T_0 = 298.15 "Exergy reference temperature";
  parameter Real T_circuit_hot = 273.15+80
    "Temperature of the hot water circuit";
  parameter Real m_flow_hot = 0.2 "Mass flow in the hot temperature circuit";

  Real T1(start=271.15+40) "Inlet cold temperature";
  Real T2(start=273.15+40, fixed=true) "Outlet cold temperature";
  Real T3(start=273.15+40) "Inlet hot temperature";
  Real T4(start=273.15+40) "Outlet hot temperature";
  Real m_flow_hot_actual(start=0.2);

  Modelica.Blocks.Interfaces.RealInput T_cold_in
  Modelica.Blocks.Interfaces.RealInput m_flow_cold
equation

  m_flow_hot_actual = (capacity/4000)*m_flow_hot;
  T1 = T_cold_in;
  T2 = T1 + capacity/(m_flow_cold*4182);
  T3 = T_circuit_hot;
  T4 = T3 - capacity/(m_flow_hot*4182);

  cost = - (m_flow_cold * T_0 * 4182 * log( T1/T2)) - (m_flow_hot_actual * T_0 * 4182 * log(T3/T4));
end MixingValveAndHEX_ExergyDestruction;


Exergy reference temperature.

within AixLib.Controls.HVACAgentBasedControl.CostFunctions.Exergy;
model MixingValveAndHEX_ExergyDestruction_Simplified
  extends HVACAgentBasedControl.BaseClasses.PartialCostFunction;
  parameter Real T_0 = 298.15 "Exergy reference temperature";
  Real T_hot(start=273.15+90) "Hot temperature";
  Real T_cold(start=273.15+50) "Cold temperature";

  Modelica.Blocks.Interfaces.RealInput T_cold_in
  Modelica.Blocks.Interfaces.RealInput T_hot_in
  Modelica.Blocks.Interfaces.RealInput T_cold_out
  Modelica.Blocks.Interfaces.RealInput T_hot_out
equation

  T_hot= (T_hot_in+T_hot_out)/2;
  T_cold= (T_cold_in+T_cold_out)/2;
  cost = capacity*(1-T_0/T_hot)-capacity*(1-T_0/T_cold);
end MixingValveAndHEX_ExergyDestruction_Simplified;


<span style=\

within AixLib.Controls.HVACAgentBasedControl.CostFunctions;
package Exergy
  extends Modelica.Icons.VariantsPackage;
end Exergy;


Exergy reference temperature.

within AixLib.Controls.HVACAgentBasedControl.CostFunctions.PrimaryExergy;
model Boiler_PrimaryExergyDestruction_Simplified
  extends HVACAgentBasedControl.BaseClasses.PartialCostFunction;
  parameter Real T_0 = 298.15 "Exergy reference temperature";
  parameter Real eta = 0.84 "Overall efficiency of the boiler";
  parameter Real PEF = 1.1 "Primary energy factor of the fuel";

  Modelica.Blocks.Math.Division division
  Modelica.Blocks.Sources.RealExpression realExpression(y=eta)
  Modelica.Blocks.Math.Division division1
  Modelica.Blocks.Sources.RealExpression realExpression1(y=T_0)
  Modelica.Blocks.Math.Add add(k2=-1)
  Modelica.Blocks.Sources.RealExpression realExpression3(y=1)
  Modelica.Blocks.Math.Product product
  Modelica.Blocks.Math.Add add1(k2=-1)
  Modelica.Blocks.Math.Gain gain(k=PEF*0.9257)
  Modelica.Blocks.Interfaces.RealInput T_circuit
  Modelica.Blocks.Math.Max min
  Modelica.Blocks.Sources.RealExpression realExpression2(y=274.15)
equation
  connect(division.u2, realExpression.y)
  connect(division1.u1, realExpression1.y)
  connect(division1.y, add.u2)
  connect(add.u1, realExpression3.y)
  connect(add.y, product.u1)
  connect(capacity, product.u2)
  connect(division.u1, product.u2)
  connect(product.y, add1.u2)
  connect(add1.y, cost)
  connect(division.y, gain.u)
  connect(gain.y, add1.u1)
  connect(min.y, division1.u2)
  connect(min.u1, realExpression2.y)
  connect(min.u2, T_circuit)
end Boiler_PrimaryExergyDestruction_Simplified;