Example use of the JSON writer. This model generates four json files,
using a single or multiple inputs and at different points in time.

within Buildings.Utilities.IO.Files.Examples;
model JSONWriter "Example use of the JSON writer"
  extends Modelica.Icons.Example;
  Buildings.Utilities.IO.Files.JSONWriter jsonWriterInitial(
    nin=3,
    fileName="InitialOutputs.json",
    outputTime=Buildings.Utilities.IO.Files.BaseClasses.OutputTime.Initial)
    "Outputs at initial time"
  Buildings.Utilities.IO.Files.JSONWriter jsonWriterCustom(
    nin=3,
    outputTime=Buildings.Utilities.IO.Files.BaseClasses.OutputTime.Custom,
    customTime=0.5,
    fileName="CustomOutputs.json",
    varKeys={"Output1","Key2","Name3"}) "Outputs at custom time"
  Buildings.Utilities.IO.Files.JSONWriter jsonWriterTerminal(
    nin=3,
    outputTime=Buildings.Utilities.IO.Files.BaseClasses.OutputTime.Terminal,
    fileName="TerminalOutputs.json") "Outputs at terminal time"
  Modelica.Blocks.Sources.Ramp ramp(
    height=1,
    duration=1,
    offset=1) "Ramp signal"
  Modelica.Blocks.Sources.Constant const(k=2) "Constant signal"
  Modelica.Blocks.Sources.Cosine cosine(amplitude=1, f=12) "Cosine signal"
  Buildings.Utilities.IO.Files.JSONWriter jsonWriterOneVar(nin=1, fileName="TerminalOutput.json")
    "Single variable output"
equation
  connect(ramp.y, jsonWriterInitial.u[1])
  connect(const.y, jsonWriterInitial.u[2])
  connect(cosine.y, jsonWriterInitial.u[3])
  connect(ramp.y, jsonWriterCustom.u[1])
  connect(ramp.y, jsonWriterTerminal.u[1])
  connect(const.y, jsonWriterCustom.u[2])
  connect(const.y, jsonWriterTerminal.u[2])
  connect(cosine.y, jsonWriterCustom.u[3])
  connect(cosine.y, jsonWriterTerminal.u[3])
  connect(const.y, jsonWriterOneVar.u[1])
end JSONWriter;


Examples package

within Buildings.Utilities.IO.Files;
package Examples "Examples package"
extends Modelica.Icons.ExamplesPackage;
end Examples;


Test model for printer.

within Buildings.Utilities.IO.Files.Examples;
model Printer "Test model for printer"
  extends Modelica.Icons.Example;
  Buildings.Utilities.IO.Files.Printer pri1(
    header="time ramp",
    nin=2,
    samplePeriod=0.1)
  Modelica.Blocks.Sources.ContinuousClock clo
  Modelica.Blocks.Sources.Ramp ram(duration=2)
  Buildings.Utilities.IO.Files.Printer pri2(
    header="time ramp",
    nin=2,
    configuration=2,
    samplePeriod=0.1)
  Buildings.Utilities.IO.Files.Printer pri3(
    header="time ramp",
    nin=2,
    configuration=3,
    samplePeriod=0.1)
equation
  connect(clo.y, pri1.x[1])
  connect(ram.y, pri1.x[2])
  connect(clo.y, pri2.x[1])
  connect(ram.y, pri2.x[2])
  connect(clo.y, pri3.x[1])
  connect(ram.y, pri3.x[2])
end Printer;


Weekly schedule example. Example and consistency test for a weekly schedule.

within Buildings.Utilities.IO.Files.Examples;
model WeeklySchedule "Weekly schedule example"
  extends Modelica.Icons.Example;
  parameter String data = "#test:
mon:0:0:10          -  3   1  -
tue,thu:20:30:59  123  -  45  -
wed                12  1   4  -" "Contents of schedule.txt";
  Buildings.Utilities.IO.Files.WeeklySchedule weeSchFil(
    columns={2,3,4,5},
    tableOnFile=true,
    fileName=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/Data/schedule.txt"),
    t_offset=1e6) "Weekly schedule example using file data source"

  Buildings.Utilities.IO.Files.WeeklySchedule weeSchStri(
    columns={2,3,4,5},
    data=data,
    t_offset=1e6) "Weekly schedule example using parameter data source"
  Diagnostics.AssertEquality assEqu[4](
    each startTime=-10000,
    each threShold=Modelica.Constants.small)
    "Trigger an assertion if the outputs differ"
equation
  connect(weeSchFil.y, assEqu.u1)
  connect(weeSchStri.y, assEqu.u2)
end WeeklySchedule;


Weekly schedule example that outputs 1 from 7:00 to 19:00 on week-days, and 0 otherwise. Example of a weekly schedule that outputs 1 from 7:00 to 19:00 on week-days, and 0 otherwise

within Buildings.Utilities.IO.Files.Examples;
model WeeklySchedule7to19
  "Weekly schedule example that outputs 1 from 7:00 to 19:00 on week-days, and 0 otherwise"
  extends Modelica.Icons.Example;

  Buildings.Utilities.IO.Files.WeeklySchedule sch
end WeeklySchedule7to19;


within Buildings.Utilities.IO.Files.Examples;
package BaseClasses "Package with base classes for Buildings.Utilities.IO.Files.Examples"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Base model for CSV reader and writer example. Partial model that contains a step function and cosine signal.

within Buildings.Utilities.IO.Files.Examples.BaseClasses;
model PartialCSV "Base model for CSV reader and writer example"
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Cosine cos(f=0.345) "Cosine"
  Modelica.Blocks.Sources.Step step(startTime=5) "Step function"
end PartialCSV;


within Buildings.Utilities.IO.Files;
package Validation "Collection of models that validate the models that access files"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


Weekly schedule example. Example for a weekly schedule that reads the schedule data from a file.
There are two file readers, one reading a file with Windows line endings and the other with Linux line endings.

within Buildings.Utilities.IO.Files.Validation;
model WeeklyScheduleWindowsLineEndings "Weekly schedule example"
  extends Modelica.Icons.Example;
  parameter String data = "double tab1(3,5) #test:
mon:0:0:10          -  3   1  -
tue,thu:20:30:59  123  -  45  -
wed                12  1   4  -" "Contents of schedule.txt";
  Buildings.Utilities.IO.Files.WeeklySchedule weeSchLin(
    columns={2,3,4,5},
    tableOnFile=true,
    fileName=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/Data/schedule.txt"),
    t_offset=1e6) "Weekly schedule example using file data source"

  Buildings.Utilities.IO.Files.WeeklySchedule weeSchWin(
    columns={2,3,4,5},
    tableOnFile=true,
    fileName=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/Data/scheduleWindows.txt"),
    t_offset=1e6) "Weekly schedule example using parameter data source"
  Diagnostics.AssertEquality assEqu[4](
    each startTime=-10000,
    each threShold=Modelica.Constants.small)
    "Trigger an assertion if the outputs differ"
equation
  connect(weeSchLin.y, assEqu.u1)
  connect(weeSchWin.y, assEqu.u2)
end WeeklyScheduleWindowsLineEndings;


Package to call Python functions

within Buildings.Utilities.IO;
package Python_3_8 "Package to call Python functions"
  extends Modelica.Icons.VariantsPackage;
end Python_3_8;


Block that exchanges a vector of real values with a Python function. Block that exchanges data with a Python function that does not need to pass
an object from one call to the next.

within Buildings.Utilities.IO.Python_3_8;
model Real_Real
  "Block that exchanges a vector of real values with a Python function"
  extends Modelica.Blocks.Interfaces.DiscreteBlock(
    startTime=0,
    firstTrigger(fixed=true, start=false));

  parameter String moduleName
    "Name of the python module that contains the function";
  parameter String functionName=moduleName "Name of the python function";

  parameter Integer nDblWri(min=1) "Number of double values to write to Python";
  parameter Integer nDblRea(min=1)
    "Number of double values to be read from the Python";
  parameter Integer flag = 0
    "Flag for double values (0: use current value, 1: use average over interval, 2: use integral over interval)";
  final parameter Integer flaDblWri[nDblWri] = fill(flag, nDblWri)
    "Flag for double values (0: use current value, 1: use average over interval, 2: use integral over interval)";

  parameter Boolean passPythonObject = false
    "Set to true if the Python function returns and receives an object, see User's Guide";

  Modelica.Blocks.Interfaces.RealInput uR[nDblWri]
    "Real inputs to be sent to Python"
  Modelica.Blocks.Interfaces.RealOutput yR[nDblRea]
    "Real outputs received from Python"

  Real uRInt[nDblWri] "Value of integral";
  Real uRIntPre[nDblWri] "Value of integral at previous sampling instance";
  Real uRWri[nDblWri] "Value to be sent to Python";
  Real uRWri_temp[nDblWri] "Internal value";
protected
  Buildings.Utilities.IO.Python_3_8.Functions.BaseClasses.PythonObject pytObj=
    Buildings.Utilities.IO.Python_3_8.Functions.BaseClasses.PythonObject()
    "Python object, used to avoid instantiating Python in each call, and to pass python object if passPythonObject=true";
initial equation
   uRWri    =  pre(uR);
   uRWri_temp = pre(uR);
   uRInt    =  zeros(nDblWri);
   uRIntPre =  zeros(nDblWri);
   for i in 1:nDblWri loop
     assert(flaDblWri[i]>=0 and flaDblWri[i]<=2,
        "Parameter flaDblWri out of range for " + String(i) + "-th component.");
   end for;
   // The assignment of yR avoids the warning
   // "initial conditions for variables of type Real are not fully specified".
   // At startTime, the sampleTrigger is true and hence this value will
   // be overwritten.
   yR = zeros(nDblRea);
equation
   for i in 1:nDblWri loop
      der(uRInt[i]) = if (flaDblWri[i] > 0) then uR[i] else 0;
   end for;

  when {sampleTrigger} then
     // Compute value that will be sent to Python
      for i in 1:nDblWri loop
        if (flaDblWri[i] == 0) then
          uRWri_temp[i] = pre(uR[i]);
          uRWri[i] = pre(uR[i]);                 // Send the current value.
        else
          if (time > 0) then
            uRWri_temp[i] = uRInt[i] - pre(uRIntPre[i]); // Integral over the sampling interval
            if (flaDblWri[i] == 2) then
              uRWri[i] = uRWri_temp[i];
            else
              uRWri[i] = uRWri_temp[i]/samplePeriod;  // Average value over the sampling interval
            end if;
          else
            uRWri[i] = pre(uR[i]);
            uRWri_temp[i] = pre(uR[i]);
          end if;
        end if;
      end for;
    // Exchange data
    yR = Buildings.Utilities.IO.Python_3_8.Functions.exchange(
      moduleName=moduleName,
      functionName=functionName,
      dblWri=uRWri,
      intWri={0},
      nDblWri=nDblWri,
      nDblRea=nDblRea,
      nIntWri=0,
      nIntRea=0,
      nStrWri=0,
      strWri={""},
      pytObj=pytObj,
      passPythonObject = passPythonObject);
    // Store current value of integral
    uRIntPre= uRInt;
  end when;
end Real_Real;


User's Guide

within Buildings.Utilities.IO.Python_3_8;
package UsersGuide "User's Guide"
  extends Modelica.Icons.Information;
end UsersGuide;


Kalman filter implemented in Python and called from Modelica. This example demonstrates the implementation of a Kalman filter
in Python.
The model generates a uniform random number, which is computed
in the Python file KalmanFilter.py by the function
random(seed).
This random number is added to a sine wave and then sent to
the function filter(u) in the above Python file.
The function filter(u) implements a Kalman filter that estimates and returns
the state.
The function saves its temporary variables to a file called
tmp-kalman.json.

within Buildings.Utilities.IO.Python_3_8.Examples;
model KalmanFilter
  "Kalman filter implemented in Python and called from Modelica"
  extends Modelica.Icons.Example;
  Python_3_8.Real_Real ran(
    nDblWri=1,
    nDblRea=1,
    functionName="random",
    moduleName="KalmanFilter",
    samplePeriod=samplePeriod) "Generate a random number in Python"
  Modelica.Blocks.Sources.ContinuousClock clock
  Python_3_8.Real_Real kalFil(
    moduleName="KalmanFilter",
    functionName="filter",
    nDblWri=1,
    nDblRea=1,
    samplePeriod=samplePeriod) "Kalman filter in Python"

  parameter Modelica.Units.SI.Time samplePeriod=0.001
    "Sample period of component";
  Modelica.Blocks.Sources.Sine sine(f=1)      "Sine wave"
  Modelica.Blocks.Math.Add add
    "Addition of signals before sending it to the Kalman filter"
equation
 // Delete the temporary file generated by the Python file
 // at the start and end of the simulation.
 when {initial(), terminal()} then
    Modelica.Utilities.Files.remove("tmp-kalman.json");
 end when;

  connect(clock.y, ran.uR[1])

  connect(add.y, kalFil.uR[1])
  connect(ran.yR[1], add.u2)
  connect(sine.y, add.u1)
end KalmanFilter;


within Buildings.Utilities.IO.Python_3_8;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Simple room model implemented in Python that outputs the temperature and the energy. This example demonstrates the implementation of a simple room model
that is implemented in the Python module Resources/Python-Sources/SimpleRoom.py.
The Python model computes a first-order response to the room model.
It returns the current room air temperature and the energy consumed during the simulation.
The Python module also passes an object from one call to the next. This object
contains the past room temperature, energy and time when the function was called,
stored as a Python dictionary.
This illustrates how Python data structures can be passed between function calls,
thereby enabling for example to call some (memory-intensive) machine learning program,
implemented in Python, from a Modelica block that may then pass the output of this program
to a controller.

within Buildings.Utilities.IO.Python_3_8.Examples;
model SimpleRoom
  "Simple room model implemented in Python that outputs the temperature and the energy"
  extends Modelica.Icons.Example;
  Buildings.Utilities.Time.ModelTime modTim "Model time"

  Python_3_8.Real_Real pyt(
    moduleName="SimpleRoom",
    functionName="doStep",
    nDblRea=2,
    nDblWri=4,
    samplePeriod=60,
    passPythonObject=true) "Python interface"
  Modelica.Blocks.Sources.Constant T0(k=293.15) "Initial temperature"
  Modelica.Blocks.Routing.Multiplex4 mul "Multiplex"
  Controls.OBC.CDL.Conversions.BooleanToReal onOff(realTrue=1.2)
    "On off control"
  Modelica.Blocks.Sources.Sine TAmb(
    amplitude=5,
    offset=283.15,
    y(unit="K", displayUnit="degC"),
    f=1/86400,
    phase=-1.5707963267949) "Ambient temperature"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub1 "Inputs different"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis onOffCon(
    final uLow=-1,
    final uHigh=1)
    "On/off control"
equation
  connect(mul.u1[1], T0.y)
  connect(modTim.y, mul.u4[1])
  connect(mul.y, pyt.uR)
  connect(onOff.y, mul.u3[1])
  connect(TAmb.y, mul.u2[1])
  connect(onOffCon.y, onOff.u)
  connect(pyt.yR[1], sub1.u2)
  connect(T0.y, sub1.u1)
  connect(sub1.y, onOffCon.u)
end SimpleRoom;


Function that communicates with Python

within Buildings.Utilities.IO.Python_3_8.Functions;
impure function exchange "Function that communicates with Python"
  extends Modelica.Icons.Function;

  input String moduleName
    "Name of the python module that contains the function";
  input String functionName=moduleName "Name of the python function";
  input BaseClasses.PythonObject pytObj "Memory that holds the Python object";
  input Boolean passPythonObject
    "Set to true if the Python function returns and receives an object, see User's Guide";

  input Real    dblWri[max(1, nDblWri)] "Double values to write";
  input Integer intWri[max(1, nIntWri)] "Integer values to write";
  input String  strWri[max(1, nStrWri)] "String values to write";

  input Integer nDblWri(min=0) "Number of double values to write";
  input Integer nDblRea(min=0) "Number of double values to read";

  input Integer nIntWri(min=0) "Number of integer values to write";
  input Integer nIntRea(min=0) "Number of integer values to read";

  input Integer nStrWri(min=0) "Number of strings to write";
//  input Integer nStrRea(min=0) "Number of strings to read";
//  input Integer strLenRea(min=0)
//    "Maximum length of each string that is read. If exceeded, the simulation stops with an error";

  output Real    dblRea[max(1, nDblRea)] "Double values returned by Python";
  output Integer intRea[max(1, nIntRea)] "Integer values returned by Python";
protected
  String pytPatOld "Old value of PYTHONPATH environment variable";
  String pytPatBuildings "PYTHONPATH of Buildings library";
  String pytPat "Value of PYTHONPATH environment variable";
  Boolean havePytPat "true if PYTHONPATH is already set by the user";
  package P
    constant String filNam = "modelica://Buildings/legal.html"
        "Name to a file of the Buildings library";
    constant String buiLibFil = Modelica.Utilities.Files.loadResource(uri=filNam) "Absolute path to filNam";
  end P;
  String searchString = "legal.html" "String to be replaced";
algorithm
 // Get the directory to Buildings/Resources/Python-Sources
 pytPatBuildings := Modelica.Utilities.Strings.replace(
   string=P.buiLibFil,
   searchString=searchString,
   replaceString="Resources/Python-Sources");

 // Update the PYTHONPATH variable
 (pytPatOld, havePytPat) :=Modelica.Utilities.System.getEnvironmentVariable("PYTHONPATH");
 if havePytPat then
   if Modelica.Utilities.Strings.find(pytPatOld, pytPatBuildings) == 0 then
     // The new python path is not yet in the environment variable, add it.
     pytPat:=pytPatOld + ":" + pytPatBuildings;
   else
     // The new python path is already in the variable.
     pytPat:=pytPatOld;
   end if;
 else
   pytPat := pytPatBuildings;
 end if;
 // Call the exchange function
 (dblRea, intRea) :=BaseClasses.exchange(
    moduleName=moduleName,
    functionName=functionName,
    pytObj=pytObj,
    passPythonObject=passPythonObject,
    pythonPath=pytPat,
    dblWri=dblWri,
    intWri=intWri,
    strWri=strWri,
    nDblWri=nDblWri,
    nDblRea=nDblRea,
    nIntWri=nIntWri,
    nIntRea=nIntRea,
    nStrWri=nStrWri);
end exchange;


Package with functions that call Python

within Buildings.Utilities.IO.Python_3_8;
package Functions "Package with functions that call Python"
  extends Modelica.Icons.BasesPackage;
end Functions;


Package with functions that call Python

within Buildings.Utilities.IO.Python_3_8.Functions;
package BaseClasses "Package with functions that call Python"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Test model for exchange function. This example calls various functions in the Python module testFunctions.py.
It tests whether arguments and return values are passed correctly.
The functions in  testFunctions.py are very simple in order to test
whether they compute correctly, and whether the data conversion between Modelica and
Python is implemented correctly.
Each call to Python is followed by an assert statement which terminates
the simulation if the return value is different from the expected value.

within Buildings.Utilities.IO.Python_3_8.Functions.Examples;
model Exchange "Test model for exchange function"
  extends Modelica.Icons.Example;

  parameter Boolean passPythonObject = false
    "Set to true if the Python function returns and receives an object, see User's Guide";

  parameter Real    yR1[1](each fixed=false) "Real function value";
  parameter Integer yI1[1](each fixed=false) "Integer function value";
  parameter Real    yR2[2](each fixed=false) "Real function value";
  parameter Integer yI2[2](each fixed=false) "Integer function value";

protected
  model M "Class that contains the Python object"
    Buildings.Utilities.IO.Python_3_8.Functions.BaseClasses.PythonObject pytObj=
        Buildings.Utilities.IO.Python_3_8.Functions.BaseClasses.PythonObject()
      "Instance of Python object";
  end M;

  M[8] m "Array with instances of Python objects";

initial algorithm
  yR1 := Buildings.Utilities.IO.Python_3_8.Functions.exchange(
    moduleName="testFunctions",
    functionName="r1_r1",
    pytObj=m[1].pytObj,
    passPythonObject=passPythonObject,
    dblWri={2.0},
    intWri={0},
    nDblWri=1,
    nDblRea=1,
    nIntWri=0,
    nIntRea=0,
    nStrWri=0,
    strWri={""});
    assert(abs(4-yR1[1]) < 1e-5, "Error in function r1_r1");

  yR1 := Buildings.Utilities.IO.Python_3_8.Functions.exchange(
    moduleName="testFunctions",
    functionName="r2_r1",
    pytObj=m[2].pytObj,
    passPythonObject=passPythonObject,
    dblWri={2.0,3.0},
    intWri={0},
    nDblWri=2,
    nDblRea=1,
    nIntWri=0,
    nIntRea=0,
    nStrWri=0,
    strWri={""});
    assert(abs(6-yR1[1]) < 1e-5, "Error in function r2_r1");

  yR2 := Buildings.Utilities.IO.Python_3_8.Functions.exchange(
    moduleName="testFunctions",
    functionName="r1_r2",
    pytObj=m[3].pytObj,
    passPythonObject=passPythonObject,
    dblWri={2.0},
    intWri={0},
    nDblWri=1,
    nDblRea=2,
    nIntWri=0,
    nIntRea=0,
    nStrWri=0,
    strWri={""});
  assert(abs(yR2[1]-2) + abs(yR2[2]-4) < 1E-5, "Error in function r1_r2");

  // In the call below, yR1 is a dummy variable, as exchange returns (Real[1], Integer[1])
  (yR1,yI1) := Buildings.Utilities.IO.Python_3_8.Functions.exchange(
    moduleName="testFunctions",
    functionName="i1_i1",
    pytObj=m[4].pytObj,
    passPythonObject=passPythonObject,
    dblWri={0.0},
    intWri={3},
    nDblWri=0,
    nDblRea=0,
    nIntWri=1,
    nIntRea=1,
    nStrWri=0,
    strWri={""});
  assert((6-yI1[1]) < 1e-5, "Error in function i1_i1");

  // In the call below, yR1 is a dummy variable, as exchange returns (Real[1], Integer[2])
  (yR1,yI2) := Buildings.Utilities.IO.Python_3_8.Functions.exchange(
    moduleName="testFunctions",
    functionName="i1_i2",
    pytObj=m[5].pytObj,
    passPythonObject=passPythonObject,
    dblWri={0.0},
    intWri={2},
    nDblWri=0,
    nDblRea=0,
    nIntWri=1,
    nIntRea=2,
    nStrWri=0,
    strWri={""});
  assert(abs(yI2[1]-2) + abs(yI2[2]-4) < 1E-5, "Error in function i1_i2");

  yR2 := Buildings.Utilities.IO.Python_3_8.Functions.exchange(
    moduleName="testFunctions",
    functionName="r1i1_r2",
    pytObj=m[6].pytObj,
    passPythonObject=passPythonObject,
    dblWri={0.3},
    intWri={2},
    nDblWri=1,
    nDblRea=2,
    nIntWri=1,
    nIntRea=0,
    nStrWri=0,
    strWri={""});
  assert(abs(yR2[1]-0.6) + abs(yI2[2]-4) < 1E-5, "Error in function r1i1_r2");

  // From Modelica, write a number to a text file, and from Python, read the text file
  // and return the number.
  Modelica.Utilities.Streams.print(string="1.23", fileName="tmp-TestPythonInterface.txt");
  yR1 := Buildings.Utilities.IO.Python_3_8.Functions.exchange(
    moduleName="testFunctions",
    functionName="s2_r1",
    pytObj=m[7].pytObj,
    passPythonObject=passPythonObject,
    dblWri={0.0},
    intWri={0},
    nDblWri=0,
    nDblRea=1,
    nIntWri=0,
    nIntRea=0,
    nStrWri=2,
    strWri={"tmp-TestPythonInterface","txt"});
   assert(abs(yR1[1]-1.23) < 1E-5, "Error in function s2_r1");

  (yR2,yI1) := Buildings.Utilities.IO.Python_3_8.Functions.exchange(
    moduleName="testFunctions",
    functionName="r1i1_r2i1",
    pytObj=m[8].pytObj,
    passPythonObject=passPythonObject,
    dblWri={0.3},
    intWri={2},
    nDblWri=1,
    nDblRea=2,
    nIntWri=1,
    nIntRea=1,
    nStrWri=0,
    strWri={""});
  assert(abs(yR2[1]-0.6) + abs(yR2[2]-4) < 1E-5, "Error in function r1i1_r2i1");
  assert(abs(yI1[1]-3) == 0, "Error in function r1i1_r2i1");
end Exchange;


Test model for exchange function with memory. This example calls various functions in the Python module testFunctions.py.
It tests whether arguments and return values are passed correctly.
The functions in  testFunctions.py are very simple in order to test
whether they compute correctly, and whether the data conversion between Modelica and
Python is implemented correctly.
Each call to Python is followed by an assert statement which terminates
the simulation if the return value is different from the expected value.

within Buildings.Utilities.IO.Python_3_8.Functions.Examples;
model ExchangeWithPassPythonObject
  "Test model for exchange function with memory"
  extends Modelica.Icons.Example;

  parameter Boolean passPythonObject = true
    "Set to true if the Python function returns and receives an object, see User's Guide";
  Buildings.Utilities.IO.Python_3_8.Functions.BaseClasses.PythonObject pytObj=
      Buildings.Utilities.IO.Python_3_8.Functions.BaseClasses.PythonObject();

  parameter Real yR1[1](each fixed=false) "Real function value";
  parameter Real yR2[1](each fixed=false) "Real function value";

initial equation
  yR1 = Buildings.Utilities.IO.Python_3_8.Functions.exchange(
    moduleName="testFunctions",
    functionName="r1_r1PassPythonObject",
    dblWri={2.0},
    intWri={0},
    nDblWri=1,
    nDblRea=1,
    nIntWri=0,
    nIntRea=0,
    nStrWri=0,
    strWri={""},
    pytObj=pytObj,
    passPythonObject=passPythonObject);
  assert(abs(3-yR1[1]) < 1e-5, "Error in function r1_r1PassPythonObject");

  // Invoke the same function with the same Python object.
  // Hence, pytObj is reused.
  yR2 = Buildings.Utilities.IO.Python_3_8.Functions.exchange(
    moduleName="testFunctions",
    functionName="r1_r1PassPythonObject",
    dblWri=yR1,
    intWri={0},
    nDblWri=1,
    nDblRea=1,
    nIntWri=0,
    nIntRea=0,
    nStrWri=0,
    strWri={""},
    pytObj=pytObj,
    passPythonObject=passPythonObject);
    assert(abs(16-yR2[1]) < 1e-5, "Error in function r1_r1PassPythonObject");
end ExchangeWithPassPythonObject;


within Buildings.Utilities.IO.Python_3_8.Functions;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Block that allows a signal to overwritten by an FMU input. This block enables the overwriting of a control signal by an external program,
as well as reading of its meta-data, without the need to explicitly propogate
the external input or activation switch to a top-level model.

within Buildings.Utilities.IO.SignalExchange;
block Overwrite "Block that allows a signal to overwritten by an FMU input"
  extends Modelica.Blocks.Interfaces.SISO;

  parameter String description "Description of the signal being overwritten";

  final parameter Boolean boptestOverwrite = true
    "Parameter that is used by tools to search for overwrite block in models";

  Modelica.Blocks.Logical.Switch swi
    "Switch between external signal and direct feedthrough signal"
  Modelica.Blocks.Sources.RealExpression uExt "External input signal"
  Modelica.Blocks.Sources.BooleanExpression activate
    "Block to activate use of external signal"

equation
  connect(activate.y, swi.u2)
  connect(swi.u3, u)
  connect(uExt.y, swi.u1)
  connect(swi.y, y)
end Overwrite;


External Signal Exchange Package

within Buildings.Utilities.IO;
package SignalExchange "External Signal Exchange Package"
  extends Modelica.Icons.Package;
end SignalExchange;


Block that allows a signal to be read as an FMU output. This block enables the reading of a signal and its meta-data by an external
program without the need to explicitly propogate the signal to a top-level model.

within Buildings.Utilities.IO.SignalExchange;
model Read "Block that allows a signal to be read as an FMU output"
  extends Modelica.Blocks.Routing.RealPassThrough;

  parameter String description "Description of the signal being read";

  parameter SignalTypes.SignalsForKPIs KPIs = SignalTypes.SignalsForKPIs.None
    "Tag with the type of signal for the calculation of the KPIs";

  parameter String zone = "1" if (
    KPIs==Buildings.Utilities.IO.SignalExchange.SignalTypes.SignalsForKPIs.AirZoneTemperature or
    KPIs==Buildings.Utilities.IO.SignalExchange.SignalTypes.SignalsForKPIs.RadiativeZoneTemperature or
    KPIs==Buildings.Utilities.IO.SignalExchange.SignalTypes.SignalsForKPIs.OperativeZoneTemperature or
    KPIs==Buildings.Utilities.IO.SignalExchange.SignalTypes.SignalsForKPIs.RelativeHumidity or
    KPIs==Buildings.Utilities.IO.SignalExchange.SignalTypes.SignalsForKPIs.CO2Concentration)
    "Zone designation, required if KPIs is AirZoneTemperature,
    RadiativeZoneTemperature, OperativeZoneTemperature, RelativeHumidity,
    or CO2Concentration"

  final parameter Boolean boptestRead = true
    "Parameter that is used by tools to search for read block in models";
end Read;


Implements typical weather measurements with signal exchange blocks. This block enables the reading of weather measurements and their meta-data by an external
program without the need to explicitly propagate the signal to a top-level model.
This block utilizes a number of pre-configured instances of

Buildings.Utilities.IO.SignalExchange.Read

within Buildings.Utilities.IO.SignalExchange;
model WeatherStation
  "Implements typical weather measurements with signal exchange blocks"
  Buildings.BoundaryConditions.WeatherData.Bus weaBus "Weather data"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaTDryBul(
    description="Outside drybulb temperature measurement",
    y(final unit="K"))
    "Outside drybulb temperature measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaRelHum(
    description="Outside relative humidity measurement",
    y(final unit="1"))
    "Outside relative humidity measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaWinSpe(
    description="Wind speed measurement",
    y(final unit="m/s"))
    "Wind speed measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaWinDir(
    description="Wind direction measurement",
    y(final unit="rad"))
    "Wind direction measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaHGloHor(
    description="Global horizontal solar irradiation measurement",
    y(final unit="W/m2"))
    "Global horizontal solar irradiation measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaNTot(
    description="Sky cover measurement",
    y(final unit="1"))
    "Sky cover measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaPAtm(
    description="Atmospheric pressure measurement",
    y(final unit="Pa"))
    "Atmospheric pressure measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaHDifHor(
    description="Horizontal diffuse solar radiation measurement",
    y(final unit="W/m2"))
    "Horizontal diffuse solar radiation measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaCeiHei(
    description="Cloud cover ceiling height measurement",
    y(final unit="m"))
    "Cloud cover ceiling height measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaTWetBul(
    description="Wet bulb temperature measurement",
    y(final unit="K"))
    "Wet bulb temperature measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaTDewPoi(
    description="Dew point temperature measurement",
    y(final unit="K"))
    "Dew point temperature measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaTBlaSky(
    description="Black-body sky temperature measurement",
    y(final unit="K"))
    "Black-body sky temperature measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaHHorIR(
    description="Horizontal infrared irradiation measurement",
    y(final unit="W/m2"))
    "Horizontal infrared irradiation measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaHDirNor(
    description="Direct normal radiation measurement",
    y(final unit="W/m2"))
    "Direct normal radiation measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaCloTim(
    description="Day number with units of seconds",
    y(final unit="s"))
    "Day number with units of seconds"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaSolAlt(
    description="Solar altitude angle measurement",
    y(final unit="rad"))
    "Solar altitude angle measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaNOpa(
    description="Opaque sky cover measurement",
    y(final unit="1"))
    "Opaque sky cover measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaLat(
    description="Latitude of the location",
    y(final unit="rad"))
    "Latitude of the location"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaLon(
    description="Longitude of the location",
    y(final unit="rad"))
    "Longitude of the location"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaSolDec(
    description="Solar declination angle measurement",
    y(final unit="rad"))
    "Solar declination angle measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaSolHouAng(
    description="Solar hour angle measurement",
    y(final unit="rad"))
    "Solar hour angle measurement"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaSolTim(
    description="Solar time",
    y(final unit="s"))
    "Solar time"
  Buildings.Utilities.IO.SignalExchange.Read reaWeaSolZen(
    description="Solar zenith angle measurement",
    y(final unit="rad"))
    "Solar zenith angle measurement"
equation
  connect(weaBus.TDryBul, reaWeaTDryBul.u)
  connect(weaBus.relHum, reaWeaRelHum.u)
  connect(weaBus.winSpe, reaWeaWinSpe.u)
  connect(weaBus.winDir, reaWeaWinDir.u)
  connect(weaBus.HGloHor, reaWeaHGloHor.u)
  connect(weaBus.nTot, reaWeaNTot.u)
  connect(weaBus.pAtm, reaWeaPAtm.u)
  connect(weaBus.HDifHor, reaWeaHDifHor.u)
  connect(weaBus.HDirNor, reaWeaHDirNor.u)
  connect(weaBus.HHorIR, reaWeaHHorIR.u)
  connect(weaBus.TBlaSky, reaWeaTBlaSky.u)
  connect(weaBus.TDewPoi, reaWeaTDewPoi.u)
  connect(weaBus.TWetBul, reaWeaTWetBul.u)
  connect(weaBus.ceiHei, reaWeaCeiHei.u)
  connect(weaBus.cloTim, reaWeaCloTim.u)
  connect(weaBus.lat, reaWeaLat.u)
  connect(weaBus.lon, reaWeaLon.u)
  connect(weaBus.nOpa, reaWeaNOpa.u)
  connect(weaBus.solAlt, reaWeaSolAlt.u)
  connect(weaBus.solDec, reaWeaSolDec.u)
  connect(weaBus.solHouAng, reaWeaSolHouAng.u)
  connect(weaBus.solTim, reaWeaSolTim.u)
  connect(weaBus.solZen, reaWeaSolZen.u)
end WeatherStation;


Uses signal exchange block for a first order dynamic system. This example uses the signal exchange blocks in an original model,

Buildings.Utilities.IO.SignalExchange.Examples.BaseClasses.OriginalModel
along with a corresponding model that would result if the original model were
compiled with the BOPTEST parser,
Buildings.Utilities.IO.SignalExchange.Examples.BaseClasses.ExportedModel
to demonstrate the overwriting of either setpoint or actuator control signals
and reading of signals.

within Buildings.Utilities.IO.SignalExchange.Examples;
model FirstOrder
  "Uses signal exchange block for a first order dynamic system"
  extends Modelica.Icons.Example;

  BaseClasses.ExportedModel expMod
  Modelica.Blocks.Sources.Constant uSet(k=2)
  Modelica.Blocks.Sources.BooleanStep actSet(startTime=50)
  Modelica.Blocks.Sources.BooleanStep actAct(startTime=100)
  Modelica.Blocks.Sources.Constant uAct(k=3)

equation
  connect(uSet.y, expMod.oveWriSet_u)
  connect(actSet.y, expMod.oveWriSet_activate)
  connect(actAct.y, expMod.oveWriAct_activate)
  connect(uAct.y, expMod.oveWriAct_u)
end FirstOrder;


within Buildings.Utilities.IO.SignalExchange;
package Examples "This package contains examples for the signal exchange block"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Example use of WeatherStation. This example uses the weather station signal exchange block,

Buildings.Utilities.IO.SignalExchange.WeatherStation
along with a TMY weather data reader.

within Buildings.Utilities.IO.SignalExchange.Examples;
model WeatherStation "Example use of WeatherStation"
  extends Modelica.Icons.Example;
  Buildings.Utilities.IO.SignalExchange.WeatherStation weaSta "Weather station"
  BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
        Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos"))
    "Weather data reader"
equation

  connect(weaDat.weaBus, weaSta.weaBus)
end WeatherStation;


Model to be exported as an FMU. This is an example of a model that would be compiled in BOPTEST if the
original model were using the signal exchange blocks. Note that inputs
are added to activate and set values of control signals that can be overwritten
and outputs are added to read signals from the read blocks.

within Buildings.Utilities.IO.SignalExchange.Examples.BaseClasses;
model ExportedModel "Model to be exported as an FMU"
  extends Modelica.Blocks.Icons.Block;

  Modelica.Blocks.Interfaces.RealInput oveWriSet_u "Signal for overwrite block for set point"
  Modelica.Blocks.Interfaces.BooleanInput oveWriSet_activate "Activation for overwrite block for set point"
  Modelica.Blocks.Interfaces.RealInput oveWriAct_u "Signal for overwrite block for actuator signal"
  Modelica.Blocks.Interfaces.BooleanInput oveWriAct_activate "Activation for overwrite block for actuator signal"

  Modelica.Blocks.Interfaces.RealOutput rea = mod.rea.y
    "Measured state variable"

  BaseClasses.OriginalModel mod(
      oveWriSet(
        uExt(
          y=oveWriSet_u),
        activate(
          y=oveWriSet_activate)),
      oveWriAct(
        uExt(
          y=oveWriAct_u),
        activate(
          y=oveWriAct_activate))) "Original model"
end ExportedModel;


Original model. This is a model of a first order dynamic system with feedback control.
Signal exchange blocks are implemented to overwrite either the setpoint or
actuator control signals as well as read the output of the first order
system.

within Buildings.Utilities.IO.SignalExchange.Examples.BaseClasses;
model OriginalModel "Original model"
  extends Modelica.Blocks.Icons.Block;

  Modelica.Blocks.Sources.Constant TSet(k=1) "Set point"

  Modelica.Blocks.Continuous.LimPID conPI(
    controllerType=Modelica.Blocks.Types.SimpleController.PI,
    yMax=10) "Controller"

  Modelica.Blocks.Continuous.FirstOrder firOrd(
    T=1,
    initType=Modelica.Blocks.Types.Init.InitialOutput)
    "First order element"

  Overwrite oveWriSet(
    description="First order system control setpoint",
    u(min=-10,
      max=10,
      unit="1")) "Overwrite block for setpoint"

  Overwrite oveWriAct(description="First order system input",
    u(min=-10,
      max=10,
      unit="1")) "Overwrite block for actuator signal"

  Read rea(
    description="First order system output",
    KPIs=Buildings.Utilities.IO.SignalExchange.SignalTypes.SignalsForKPIs.None)
    "Measured state variable"

equation
  connect(TSet.y, oveWriSet.u)
  connect(oveWriSet.y, conPI.u_s)
  connect(conPI.y, oveWriAct.u)
  connect(oveWriAct.y, firOrd.u)
  connect(firOrd.y, rea.u)
  connect(rea.y, conPI.u_m)
end OriginalModel;


within Buildings.Utilities.IO.SignalExchange.Examples;
package BaseClasses "Contains base classes for signal exchange examples"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Package with signal type definitions

within Buildings.Utilities.IO.SignalExchange;
package SignalTypes "Package with signal type definitions"
 extends Modelica.Icons.TypesPackage;
end SignalTypes;


Average of a vector. This block outputs the average of the vector.

within Buildings.Utilities.Math;
block Average "Average of a vector"
  extends Modelica.Blocks.Interfaces.MISO;
equation
 y = Buildings.Utilities.Math.Functions.average(u=u, nin=nin);
end Average;


Bessel function of the first kind of order 0, J0. This block computes the bessel function of the first kind of order 0, J0.

within Buildings.Utilities.Math;
block BesselJ0 "Bessel function of the first kind of order 0, J0"
  extends Modelica.Blocks.Interfaces.SISO;
equation
  y = Buildings.Utilities.Math.Functions.besselJ0(x=u);
end BesselJ0;


Bessel function of the first kind of order 1, J1. This block computes the bessel function of the first kind of order 1, J1.

within Buildings.Utilities.Math;
block BesselJ1 "Bessel function of the first kind of order 1, J1"
  extends Modelica.Blocks.Interfaces.SISO;
equation
  y = Buildings.Utilities.Math.Functions.besselJ1(x=u);
end BesselJ1;


Bessel function of the second kind of order 0, Y0. This block computes the bessel function of the second kind of order 0, Y0.

within Buildings.Utilities.Math;
block BesselY0 "Bessel function of the second kind of order 0, Y0"
  extends Modelica.Blocks.Interfaces.SISO;
equation
  y = Buildings.Utilities.Math.Functions.besselY0(x=u);
end BesselY0;


Bessel function of the second kind of order 1, Y1. This block computes the bessel function of the second kind of order 1, Y1.

within Buildings.Utilities.Math;
block BesselY1 "Bessel function of the second kind of order 1, Y1"
  extends Modelica.Blocks.Interfaces.SISO;
equation
  y = Buildings.Utilities.Math.Functions.besselY1(x=u);
end BesselY1;


Bicubic function. This block computes

within Buildings.Utilities.Math;
block Bicubic "Bicubic function"
  extends Modelica.Blocks.Interfaces.SI2SO;
 input Real a[10] "Coefficients";
equation
  y =  Buildings.Utilities.Math.Functions.bicubic(a=a, x1=u1, x2=u2);
end Bicubic;


Binomial function. This block computes the binomial coefficient \"n choose k\".

within Buildings.Utilities.Math;
block Binomial "Binomial function"
  extends Modelica.Blocks.Interfaces.IntegerSO;
  Modelica.Blocks.Interfaces.IntegerInput n "Size of set"
  Modelica.Blocks.Interfaces.IntegerInput k "Size of subsets"
equation
  y = Buildings.Utilities.Math.Functions.binomial(n=n, k=k);
end Binomial;


Biquadratic function. This block computes

within Buildings.Utilities.Math;
block Biquadratic "Biquadratic function"
  extends Modelica.Blocks.Interfaces.SI2SO;
  parameter Real a[6] "Coefficients";
equation
  y =  Buildings.Utilities.Math.Functions.biquadratic(a=a, x1=u1, x2=u2);
end Biquadratic;


Boolean signal replicator. This block replicates the boolean input signal to an array of nout identical output signals.

within Buildings.Utilities.Math;
block BooleanReplicator "Boolean signal replicator"
  extends Modelica.Blocks.Icons.BooleanBlock;
  parameter Integer nout=1 "Number of outputs";
  Modelica.Blocks.Interfaces.BooleanInput u "Connector of boolean input signal"
  Modelica.Blocks.Interfaces.BooleanOutput y[nout]
    "Connector of boolean output signals"
equation
  y = Buildings.Utilities.Math.Functions.booleanReplicator(u=u, nout=nout);
end BooleanReplicator;


Exponential integral function, E1. This block computes the exponential integral, E1.

within Buildings.Utilities.Math;
block ExponentialIntegralE1 "Exponential integral function, E1"
  extends Modelica.Blocks.Interfaces.SISO;
equation
  y = Buildings.Utilities.Math.Functions.exponentialIntegralE1(x=u);
end ExponentialIntegralE1;


Factorial function. This block computes the factorial of the integer input, <i>y=n!</i>.

within Buildings.Utilities.Math;
block Factorial "Factorial function"
  extends Modelica.Blocks.Interfaces.IntegerSO;
  Modelica.Blocks.Interfaces.IntegerInput u "Connector of integer input signal"
equation
  y = Buildings.Utilities.Math.Functions.factorial(n=u);
end Factorial;


Falling factorial function. This block computes the falling factorial, y = nḵ.

within Buildings.Utilities.Math;
block FallingFactorial "Falling factorial function"
  extends Modelica.Blocks.Interfaces.IntegerSO;
  Modelica.Blocks.Interfaces.IntegerInput n "Integer number"
  Modelica.Blocks.Interfaces.IntegerInput k "Falling factorial power"
equation
  y = Buildings.Utilities.Math.Functions.fallingFactorial(n=n, k=k);
end FallingFactorial;


Integer signal replicator. This block replicates the integer input signal to an array of nout identical output signals.

within Buildings.Utilities.Math;
block IntegerReplicator "Integer signal replicator"
  extends Modelica.Blocks.Icons.IntegerBlock;
  parameter Integer nout=1 "Number of outputs";
  Modelica.Blocks.Interfaces.IntegerInput u "Connector of integer input signal"
  Modelica.Blocks.Interfaces.IntegerOutput y[nout]
    "Connector of integer output signals"
equation
  y = Buildings.Utilities.Math.Functions.integerReplicator(u=u, nout=nout);
end IntegerReplicator;


Output the integral of the input signal. This model is similar to

Modelica.Blocks.Continuous.Integrator
except that it optionally allows to reset the output y
of the integrator.

within Buildings.Utilities.Math;
block IntegratorWithReset "Output the integral of the input signal"
  extends Modelica.Blocks.Interfaces.SISO(y(start=y_start));

  parameter Real k(unit="1")=1 "Integrator gain";

  /* InitialState is the default, because it was the default in Modelica 2.2
     and therefore this setting is backward compatible
  */
  parameter Modelica.Blocks.Types.Init initType=Modelica.Blocks.Types.Init.InitialState
    "Type of initialization (1: no init, 2: steady state, 3,4: initial output)"

  parameter Real y_start=0 "Initial or guess value of output (= state)"

  parameter Buildings.Types.Reset reset = Buildings.Types.Reset.Disabled
    "Type of integrator reset";

  parameter Real y_reset = 0
    "Value to which integrator is reset, used if reset = Buildings.Types.Reset.Parameter"

  Modelica.Blocks.Interfaces.RealInput y_reset_in
    if reset == Buildings.Types.Reset.Input
    "Input signal for state to which integrator is reset, enabled if reset = Buildings.Types.Reset.Input"

  Modelica.Blocks.Interfaces.BooleanInput trigger
    if reset <> Buildings.Types.Reset.Disabled
    "Resets the integrator output when trigger becomes true"
protected
  Modelica.Blocks.Interfaces.RealInput y_reset_internal
   "Internal connector for integrator reset"

  Modelica.Blocks.Interfaces.BooleanInput trigger_internal
    "Needed to use conditional connector trigger";

initial equation
  if initType == Modelica.Blocks.Types.Init.SteadyState then
     der(y) = 0;
  elseif initType == Modelica.Blocks.Types.Init.InitialState or
         initType == Modelica.Blocks.Types.Init.InitialOutput then
    y = y_start;
  end if;

equation
  der(y) = k*u;

  // Equations for integrator reset
  connect(trigger, trigger_internal);
  connect(y_reset_in, y_reset_internal);

  if reset <> Buildings.Types.Reset.Input then
    y_reset_internal = y_reset;
  end if;

  if reset == Buildings.Types.Reset.Disabled then
    trigger_internal = false;
  else
    when trigger_internal then
      reinit(y, y_reset_internal);
    end when;
  end if;
end IntegratorWithReset;


Output the cubic hermite spline interpolation of the input signal on the given curve. This block outputs the value on a cubic hermite spline through the given
support points and their spline derivatives at these points, using the function

Buildings.Utilities.Math.Functions.interpolate.

within Buildings.Utilities.Math;
block Interpolate
  "Output the cubic hermite spline interpolation of the input signal on the given curve"
  extends Modelica.Blocks.Interfaces.SISO;

  parameter Real[:] xd "x-axis support points";
  parameter Real[size(xd, 1)] yd "y-axis support points";
  parameter Real[size(xd, 1)] d "Derivatives at the support points";
equation
  y = Buildings.Utilities.Math.Functions.interpolate(u=u, xd=xd, yd=yd, d=d);
end Interpolate;


Function that approximates 1/x by a twice continuously differentiable function. Function that approximates y=1 ⁄ x inside the interval -δ ≤ x ≤ δ. The approximation is twice continuously differentiable with a bounded derivative on the whole real line.

within Buildings.Utilities.Math;
block InverseXRegularized
  "Function that approximates 1/x by a twice continuously differentiable function"
  extends Modelica.Blocks.Interfaces.SISO;
  parameter Real delta(min=0) "Abscissa value below which approximation occurs";
equation
  y = Buildings.Utilities.Math.Functions.inverseXRegularized(x=u, delta=delta);
end InverseXRegularized;


Maximum element of a vector. Outputs the maximum of the vector.

within Buildings.Utilities.Math;
block Max "Maximum element of a vector"
  extends Modelica.Blocks.Interfaces.MISO;
equation
 y = max(u);
end Max;


Minimum element of a vector. Outputs the minimum of the vector.

within Buildings.Utilities.Math;
block Min "Minimum element of a vector"
  extends Modelica.Blocks.Interfaces.MISO;
equation
 y = min(u);
end Min;


within Buildings.Utilities;
package Math "Library with functions such as for smoothing"
  extends Modelica.Icons.Package;
end Math;


Polynominal function. This block computes a polynomial of arbitrary order. The polynomial has the form

within Buildings.Utilities.Math;
block Polynomial "Polynominal function"
  extends Modelica.Blocks.Interfaces.SISO;
 parameter Real a[:] "Coefficients";
equation
  y = Buildings.Utilities.Math.Functions.polynomial(a=a, x=u);
end Polynomial;


Power function that is linearized below a user-defined threshold.

within Buildings.Utilities.Math;
block PowerLinearized
  "Power function that is linearized below a user-defined threshold"
  extends Modelica.Blocks.Interfaces.SISO;
  parameter Real n "Exponent";
  parameter Real x0 "Abscissa value below which linearization occurs";

equation
  y = Buildings.Utilities.Math.Functions.powerLinearized(x=u, n=n, x0=x0);
end PowerLinearized;


Function that is quadratic in first argument and linear in second argument. Block for function quadraticLinear, which computes

within Buildings.Utilities.Math;
block QuadraticLinear
  "Function that is quadratic in first argument and linear in second argument"
  extends Modelica.Blocks.Interfaces.SI2SO;
  parameter Real a[6] "Coefficients";
equation
  y = Buildings.Utilities.Math.Functions.quadraticLinear(a=a, x1=u1, x2=u2);
end QuadraticLinear;


Power function, regularized near zero, but nonzero value for x=0. Block that approximates y=|x|n where 0 < n < 2
so that

within Buildings.Utilities.Math;
block RegNonZeroPower
  "Power function, regularized near zero, but nonzero value for x=0"
  extends Modelica.Blocks.Interfaces.SISO;
  parameter Real n "Exponent";
  parameter Real delta = 0.01 "Abscissa value where transition occurs";
equation
  y = Buildings.Utilities.Math.Functions.regNonZeroPower(x=u, n=n, delta=delta);
end RegNonZeroPower;


Once continuously differentiable approximation to exp(-|x|) in interval |x| < delta. Function to provide a once continuously differentiable approximation to <i>exp(- |x| )</i> in the interval <i>|x| for some positive δ </i>

within Buildings.Utilities.Math;
block SmoothExponential
  "Once continuously differentiable approximation to exp(-|x|) in interval |x| < delta"
  extends Modelica.Blocks.Interfaces.SISO;
  parameter Real delta "Transition point where approximation occurs";
equation
  y = Buildings.Utilities.Math.Functions.smoothExponential(x=u, delta=delta);
end SmoothExponential;


Twice continuously differentiable approximation to the Heaviside function. Twice Lipschitz continuously differentiable approximation to the Heaviside(.,.) function.
See Example
Buildings.Utilities.Math.Examples.SmoothHeaviside.

within Buildings.Utilities.Math;
block SmoothHeaviside
  "Twice continuously differentiable approximation to the Heaviside function"
  extends Modelica.Blocks.Interfaces.SISO;
 parameter Real delta(min=Modelica.Constants.eps) "Width of transition interval";
equation
  y = Buildings.Utilities.Math.Functions.smoothHeaviside(x=u, delta=delta);
end SmoothHeaviside;


Once continuously differentiable approximation to the limit function. Once continuously differentiable approximation to the limit(.,.) function.
The output is bounded to be in [lower, upper].

within Buildings.Utilities.Math;
block SmoothLimit
  "Once continuously differentiable approximation to the limit function"
 extends Modelica.Blocks.Interfaces.SISO;
 parameter Real deltaX "Width of transition interval";
 parameter Real upper "Upper limit";
 parameter Real lower "Lower limit";
equation
  y = Buildings.Utilities.Math.Functions.smoothLimit(u, lower, upper, deltaX);
end SmoothLimit;


Once continuously differentiable approximation to the maximum function. Once continuously differentiable approximation to the <i>max(.,.)</i> function.

within Buildings.Utilities.Math;
block SmoothMax
  "Once continuously differentiable approximation to the maximum function"
  extends Modelica.Blocks.Interfaces.SI2SO;
 parameter Real deltaX "Width of transition interval";
equation
  y =  Buildings.Utilities.Math.Functions.smoothMax(x1=u1, x2=u2, deltaX=deltaX);
end SmoothMax;


Once continuously differentiable approximation to the minimum function. Once continuously differentiable approximation to the <i>min(.,.)</i> function.

within Buildings.Utilities.Math;
block SmoothMin
  "Once continuously differentiable approximation to the minimum function"
  extends Modelica.Blocks.Interfaces.SI2SO;
  parameter Real deltaX "Width of transition interval";
equation
  y = Buildings.Utilities.Math.Functions.smoothMin(x1=u1, x2=u2, deltaX=deltaX);
end SmoothMin;


Block for splice function opertation. This block implements
Buildings.Utilities.Math.Functions.spliceFunction, which provides a continuously differentiable transition between two arguments.

within Buildings.Utilities.Math;
block Splice "Block for splice function opertation"
  extends Modelica.Blocks.Icons.Block;

  Modelica.Blocks.Interfaces.RealInput x "Independent value"
  Modelica.Blocks.Interfaces.RealInput u1 "Argument of u > 0 (pos)"
  Modelica.Blocks.Interfaces.RealInput u2 "Argument of u < 0 (neg)"
  Modelica.Blocks.Interfaces.RealOutput y "Smoothed value"
parameter Real deltax "Half width of transition interval";
equation
  y=Buildings.Utilities.Math.Functions.spliceFunction(
    pos=u1,
    neg= u2,
    x= x,
    deltax= deltax);
end Splice;


Integration using the trapezoidal rule. This function computes a definite integral using the trapezoidal rule.

within Buildings.Utilities.Math;
model TrapezoidalIntegration "Integration using the trapezoidal rule"
  extends Modelica.Blocks.Interfaces.MISO;
  parameter Integer N "Number of integrand points";
  parameter Real deltaX "Width of interval for Trapezoidal integration";
equation
  y = Buildings.Utilities.Math.Functions.trapezoidalIntegration(N=N, f=u, deltaX=deltaX);
end TrapezoidalIntegration;


Test model for average function. This model tests the implementation of

Buildings.Utilities.Math.Average.

within Buildings.Utilities.Math.Examples;
model Average "Test model for average function"
  extends Modelica.Icons.Example;
  Buildings.Utilities.Math.Average average(nin=2)
  Modelica.Blocks.Sources.Ramp x1(duration=1)
  Modelica.Blocks.Sources.Ramp x2(
    height=2,
    duration=1,
    offset=2)
  Modelica.Blocks.Routing.Multiplex2 multiplex2_1
equation
  connect(x1.y, multiplex2_1.u1[1])
  connect(x2.y, multiplex2_1.u2[1])
  connect(multiplex2_1.y, average.u)
end Average;


Test model for besselJ0 function . This model tests the implementation of

Buildings.Utilities.Math.BesselJ0.

within Buildings.Utilities.Math.Examples;
model BesselJ0 "Test model for besselJ0 function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x(duration=30, height=30) "Real signal"
  Buildings.Utilities.Math.BesselJ0 J0 "Bessel function J0"
equation
  connect(x.y, J0.u)
end BesselJ0;


Test model for besselJ1 function . This model tests the implementation of

Buildings.Utilities.Math.BesselJ1.

within Buildings.Utilities.Math.Examples;
model BesselJ1 "Test model for besselJ1 function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x(duration=30, height=30) "Real signal"
  Buildings.Utilities.Math.BesselJ1 J1 "Bessel function J1"
equation
  connect(x.y, J1.u)
end BesselJ1;


Test model for besselY0 function . This model tests the implementation of

Buildings.Utilities.Math.BesselY0.

within Buildings.Utilities.Math.Examples;
model BesselY0 "Test model for besselY0 function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x(duration=30, height=30) "Real signal"
  Buildings.Utilities.Math.BesselY0 Y0 "Bessel function Y0"
equation
  connect(x.y, Y0.u)
end BesselY0;


Test model for besselY1 function . This model tests the implementation of

Buildings.Utilities.Math.BesselY1.

within Buildings.Utilities.Math.Examples;
model BesselY1 "Test model for besselY1 function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x(duration=30, height=30) "Real signal"
  Buildings.Utilities.Math.BesselY1 Y1 "Bessel function Y1"
equation
  connect(x.y, Y1.u)
end BesselY1;


Test model for bicubic function. This model tests the implementation of

Buildings.Utilities.Math.Bicubic.

within Buildings.Utilities.Math.Examples;
model Bicubic "Test model for bicubic function"
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x1(duration=1)
  Modelica.Blocks.Sources.Ramp x2(
    height=2,
    duration=1,
    offset=2)
  Buildings.Utilities.Math.Bicubic bicubic(a={1,2,3,4,5,6,7,8,9,10})
equation

  connect(x1.y, bicubic.u1)
  connect(x2.y, bicubic.u2)
end Bicubic;


Test model for binomial function . This model tests the implementation of

Buildings.Utilities.Math.Binomial.

within Buildings.Utilities.Math.Examples;
model Binomial "Test model for binomial function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp k(
    startTime=0.5,
    height=10.4,
    duration=10.4) "Real signal"
  Modelica.Blocks.Math.RealToInteger rea2Int "Convert to rounded integer"
  Buildings.Utilities.Math.Binomial bin "Binomial coefficient"
  Modelica.Blocks.Sources.IntegerConstant n(k=15) "Size of set"
equation
  connect(k.y, rea2Int.u)
  connect(rea2Int.y, bin.k)
  connect(n.y, bin.n)
end Binomial;


Test model for biquadratic function. This model tests the implementation of

Buildings.Utilities.Math.Biquadratic.

within Buildings.Utilities.Math.Examples;
model Biquadratic "Test model for biquadratic function"
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x1(duration=1)
  Modelica.Blocks.Sources.Ramp x2(
    height=2,
    duration=1,
    offset=2)
  Buildings.Utilities.Math.Biquadratic biquadratic(a={1,2,3,4,5,6})
equation

  connect(x1.y, biquadratic.u1)
  connect(x2.y, biquadratic.u2)
end Biquadratic;


Test model for boolean replicator. This model tests the implementation of

Buildings.Utilities.Math.BooleanReplicator.

within Buildings.Utilities.Math.Examples;
model BooleanReplicator "Test model for boolean replicator"

  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.BooleanTable booTab(table={100,200,400,500})
    "Boolean input signal"
  Buildings.Utilities.Math.BooleanReplicator booRep(nout=
       4) "Replicates boolean values"
equation
  connect(booTab.y, booRep.u)
end BooleanReplicator;


Test model for exponentialIntegralE1 function . This model tests the implementation of

Buildings.Utilities.Math.ExponentialIntegralE1.

within Buildings.Utilities.Math.Examples;
model ExponentialIntegralE1
  "Test model for exponentialIntegralE1 function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x(duration=30, height=30) "Real signal"
  Buildings.Utilities.Math.ExponentialIntegralE1 E1 "Exponential integral E1"
equation
  connect(x.y, E1.u)
end ExponentialIntegralE1;


Test model for factorial function . This model tests the implementation of

Buildings.Utilities.Math.Factorial.

within Buildings.Utilities.Math.Examples;
model Factorial "Test model for factorial function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x(
    startTime=0.5,
    height=12.4,
    duration=12.4) "Real signal"
  Buildings.Utilities.Math.Factorial fac "Factorial"
  Modelica.Blocks.Math.RealToInteger rea2Int "Conversion to rounded integer"
equation
  connect(rea2Int.y, fac.u)
  connect(x.y, rea2Int.u)
end Factorial;


Test model for falling factorial function . This model tests the implementation of

Buildings.Utilities.Math.FallingFactorial.

within Buildings.Utilities.Math.Examples;
model FallingFactorial "Test model for falling factorial function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp k(
    startTime=0.5,
    height=10.4,
    duration=10.4) "Real signal"
  Modelica.Blocks.Math.RealToInteger rea2Int "Conversion to rounded integer"
  Buildings.Utilities.Math.FallingFactorial falFac "Falling factorial"
  Modelica.Blocks.Sources.IntegerConstant n(k=13) "Falling factorial power"
equation
  connect(k.y, rea2Int.u)
  connect(rea2Int.y, falFac.k)
  connect(n.y, falFac.n)
end FallingFactorial;


Test model for integer replicator. This model tests the implementation of

Buildings.Utilities.Math.IntegerReplicator.

within Buildings.Utilities.Math.Examples;
model IntegerReplicator "Test model for integer replicator"

  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.IntegerTable intTab(table=[0,1;1, 4;1.5, 5;2, 6])
    "Integer input signal"
  Buildings.Utilities.Math.IntegerReplicator intRep(nout=
       2) "Replicates integer values"
equation
  connect(intTab.y, intRep.u)
end IntegerReplicator;


Test model for integrator with reset. This model tests the implementation of

Buildings.Utilities.Math.IntegratorWithReset
with and without reset, and with different start values
and reset values.

within Buildings.Utilities.Math.Examples;
model IntegratorWithReset "Test model for integrator with reset"
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Constant cons(k=10) "Constant as source term"

  Buildings.Utilities.Math.IntegratorWithReset intWitRes1(
    y_start=5, reset=Buildings.Types.Reset.Parameter,
    k=0.5,
    y_reset=2)                                      "Integrator with reset"

  Buildings.Utilities.Math.IntegratorWithReset intWitRes2(
    y_reset=10,
    y_start=-5,
    reset=Buildings.Types.Reset.Input,
    k=0.5)     "Integrator with reset and y_reset = 2"
  Modelica.Blocks.Sources.BooleanPulse booleanPulse(width=50, period=0.2)
    "Boolean pulse"
  Buildings.Utilities.Math.IntegratorWithReset intNoReset(
    reset=Buildings.Types.Reset.Disabled,
    k=0.5,
    y_start=1)
    "Integrator without reset"
  Modelica.Blocks.Sources.SampleTrigger sampleTrigger(period=0.2)
    "Sample trigger"
  Modelica.Blocks.Sources.Ramp ramp(
    height=-1,
    duration=1,
    offset=-2) "Ramp as a source term"
  Buildings.Utilities.Math.IntegratorWithReset intDef
    "Integrator with default values"
equation
  connect(cons.y, intWitRes1.u)
  connect(intNoReset.u, cons.y)
  connect(cons.y, intWitRes2.u)
  connect(sampleTrigger.y, intWitRes1.trigger)
  connect(booleanPulse.y, intWitRes2.trigger)
  connect(ramp.y, intWitRes2.y_reset_in)
  connect(cons.y, intDef.u)
end IntegratorWithReset;


Example model of the Interpolate block. This example is the same as

Buildings.Utilities.Math.Functions.Examples.Interpolate
except that the block is used in place of the function.

within Buildings.Utilities.Math.Examples;
model Interpolate "Example model of the Interpolate block"
  extends Modelica.Icons.Example;

  parameter Real table[:,:]=[-50,-0.08709; -25,-0.06158; -10,-0.03895; -5,-0.02754;
    -3,-0.02133; -2,-0.01742; -1,-0.01232; 0,0; 1,0.01232; 2,0.01742; 3,0.02133;
    4.5,0.02613; 50,0.02614]
    "Table of mass flow rate in kg/s (second column) as a function of pressure difference in Pa (first column)";
  parameter Real[:] xd=table[:,1] "x-axis support points";
  parameter Real[size(xd, 1)] yd=table[:,2] "y-axis support points";
  parameter Real[size(xd, 1)] d =
    Buildings.Utilities.Math.Functions.splineDerivatives(
      x=xd,
      y=yd,
      ensureMonotonicity=true) "Derivatives at the support points";

  Buildings.Utilities.Math.Interpolate int(
    xd=xd,
    yd=yd,
    d=d) "Interpolate block"
  Modelica.Blocks.Sources.Ramp ramp(
    duration=500,
    height=100,
    offset=-50) "Ramp from -50Pa to +50Pa"

equation
  connect(ramp.y, int.u)
end Interpolate;


Test model for inverseXRegularized function . This model tests the implementation of

Buildings.Utilities.Math.InverseXRegularized.

within Buildings.Utilities.Math.Examples;
model InverseXRegularized "Test model for inverseXRegularized function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x1(duration=1,
    height=2,
    offset=-1)
  Buildings.Utilities.Math.InverseXRegularized inverseXRegularized(delta=0.1)
equation
  connect(x1.y, inverseXRegularized.u)
end InverseXRegularized;


within Buildings.Utilities.Math;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Test model for ploynominal function . This model tests the implementation of

Buildings.Utilities.Math.Polynomial.

within Buildings.Utilities.Math.Examples;
model Polynomial "Test model for ploynominal function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x1(duration=1)
  Buildings.Utilities.Math.Polynomial polynominal(a={1,2})
equation
  connect(x1.y, polynominal.u)
end Polynomial;


Test model for powerLinearized function . This model tests the implementation of

Buildings.Utilities.Math.PowerLinearized.

within Buildings.Utilities.Math.Examples;
model PowerLinearized "Test model for powerLinearized function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x1(duration=1)
  Buildings.Utilities.Math.PowerLinearized powerLinearized(n=2, x0=0.5)
equation
  connect(x1.y, powerLinearized.u)
end PowerLinearized;


Test model for quadraticLinear function . This model tests the implementation of

Buildings.Utilities.Math.QuadraticLinear.

within Buildings.Utilities.Math.Examples;
model QuadraticLinear "Test model for quadraticLinear function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x1(duration=1)
  Buildings.Utilities.Math.QuadraticLinear quadraticLinear(a={1,2,3,4,5,6})
  Modelica.Blocks.Sources.Ramp x2(
    duration=1,
    offset=2,
    height=5)
equation
  connect(x2.y, quadraticLinear.u2)
  connect(x1.y, quadraticLinear.u1)
end QuadraticLinear;


Test model for regNonZeroPower function . This model tests the implementation of

Buildings.Utilities.Math.RegNonZeroPower.

within Buildings.Utilities.Math.Examples;
model RegNonZeroPower "Test model for regNonZeroPower function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x1(duration=1)
  Buildings.Utilities.Math.RegNonZeroPower regNonZeroPower(n=0.5)
equation
  connect(x1.y, regNonZeroPower.u)
end RegNonZeroPower;


Test model for smooth min and smooth max functions. This model tests the implementation of blocks that approximate non-differentiable functions
by smooth functions.

within Buildings.Utilities.Math.Examples;
model SmoothBlocks "Test model for smooth min and smooth max functions"
  extends Modelica.Icons.Example;
  SmoothMax smoMax(deltaX=0.5)
  Modelica.Blocks.Math.Max max
  Modelica.Blocks.Sources.Sine sine(f=8)
  Modelica.Blocks.Sources.Sine sine1(f=1)
  Diagnostics.AssertEquality assEquMax(threShold=0.08)
  Buildings.Utilities.Math.SmoothMin smoMin(deltaX=0.5)
  Modelica.Blocks.Math.Min Min
  Diagnostics.AssertEquality assEquMin(threShold=0.08)
equation

  connect(sine.y, smoMax.u1)
  connect(sine.y, max.u1)
  connect(sine1.y, smoMax.u2)
  connect(sine1.y, max.u2)
  connect(smoMax.y, assEquMax.u1)
  connect(max.y, assEquMax.u2)
  connect(sine.y, smoMin.u1)
  connect(sine.y, Min.u1)
  connect(sine1.y, smoMin.u2)
  connect(sine1.y, Min.u2)
  connect(smoMin.y, assEquMin.u1)
  connect(Min.y, assEquMin.u2)
end SmoothBlocks;


Test model for smoothExponential function . This model tests the implementation of

Buildings.Utilities.Math.SmoothExponential.

within Buildings.Utilities.Math.Examples;
model SmoothExponential "Test model for smoothExponential function "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x1(duration=1,
    height=2,
    offset=-1)
  Buildings.Utilities.Math.SmoothExponential smoothExponential(delta=0.1)
equation
  connect(x1.y, smoothExponential.u)
end SmoothExponential;


Test model for smoothHeavisidefunction . This model tests the implementation of

Buildings.Utilities.Math.SmoothHeaviside.

within Buildings.Utilities.Math.Examples;
model SmoothHeaviside "Test model for smoothHeavisidefunction "
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Ramp x1(
    duration=1,
    height=2,
    offset=-1)
    "Ramp input signal"
  Buildings.Utilities.Math.SmoothHeaviside smoothHeaviside(delta=0.1)
  "Smooth approximation to Heaviside function"
equation
  connect(x1.y, smoothHeaviside.u)
end SmoothHeaviside;


Test model for smooth limit. This model tests the implementation of

Buildings.Utilities.Math.SmoothLimit.

within Buildings.Utilities.Math.Examples;
model SmoothLimit "Test model for smooth limit"
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Sine sine(f=8)
  Buildings.Utilities.Math.SmoothLimit smoLim(
    deltaX=0.001,
    upper=0.5,
    lower=0) "Smooth limit"
equation

  connect(sine.y, smoLim.u)
end SmoothLimit;


Test model for smooth minimum. This model tests the implementation of

Buildings.Utilities.Math.SmoothMin.

within Buildings.Utilities.Math.Examples;
model SmoothMin "Test model for smooth minimum"
  extends Modelica.Icons.Example;
  Buildings.Utilities.Math.SmoothMin smoLim[2](deltaX={0.1,0.02}) "Smooth limit"
  Modelica.Blocks.Sources.Ramp ramp(height=1, duration=1) "Ramp input"
  Modelica.Blocks.Sources.Constant const(k=0.5) "Constant input"
equation

  connect(ramp.y, smoLim[1].u1)
  connect(smoLim[2].u1, ramp.y)
  connect(const.y, smoLim[1].u2)
  connect(const.y, smoLim[2].u2)
end SmoothMin;


Test model for splice. This model tests the implementation of

Buildings.Utilities.Math.Splice

within Buildings.Utilities.Math.Examples;
model Splice "Test model for splice"
  extends Modelica.Icons.Example;
  Buildings.Utilities.Math.Splice splice(deltax=0.2)
  Modelica.Blocks.Sources.Sine sine(f=0.5)
  Modelica.Blocks.Sources.Constant const1(k=-0.5)
  Modelica.Blocks.Sources.Constant const(k=0.5)
equation

  connect(sine.y, splice.x)
  connect(const1.y, splice.u2)
  connect(const.y, splice.u1)
end Splice;


Test model for functions that take a vector as argument. This model tests the implementation of functions that take a vector as an argument.

within Buildings.Utilities.Math.Examples;
model VectorFunctions "Test model for functions that take a vector as argument"
  extends Modelica.Icons.Example;

  Buildings.Utilities.Math.Min minVec(
                   nin=3)
  Modelica.Blocks.Sources.Sine sine(f=6)
  Modelica.Blocks.Sources.Sine sine1(f=8)
  Modelica.Blocks.Sources.Sine sine2(f=10)
  Buildings.Utilities.Math.Max maxVec(
                   nin=3)
  Buildings.Utilities.Math.Average aveVec(
                       nin=3)
equation
  connect(sine.y, minVec.u[1])
  connect(sine1.y, minVec.u[2])
  connect(sine2.y, minVec.u[3])
  connect(sine.y, maxVec.u[1])
  connect(sine1.y, maxVec.u[2])
  connect(sine2.y, maxVec.u[3])
  connect(sine.y, aveVec.u[1])
  connect(sine1.y, aveVec.u[2])
  connect(sine2.y, aveVec.u[3])
end VectorFunctions;


Function for cubic hermite spline interpolation of table data. This function returns the value on a cubic hermite spline through the given support points
and provided spline derivatives at these points.
The spline derivatives at the support points can be computed using

Buildings.Utilities.Math.Functions.splineDerivatives.
The support points must be monotonically increasing.
Outside the provided support points, the function returns a linear extrapolation with
the same slope as the cubic spline has at the respective support point.

within Buildings.Utilities.Math.Functions;
function interpolate
  "Function for cubic hermite spline interpolation of table data"
  extends Modelica.Icons.Function;

  input Real u "Independent variable";
  input Real[:] xd "x-axis support points";
  input Real[size(xd, 1)] yd "y-axis support points";
  input Real[size(xd, 1)] d "Derivatives at the support points";

  output Real z "Dependent variable with monotone interpolation";

protected
  Integer i "Integer to select data interval";

algorithm
  i := 1;
  for j in 1:size(xd, 1) - 1 loop
    if u > xd[j] then
      i := j;
    end if;
  end for;

  z :=Buildings.Utilities.Math.Functions.cubicHermiteLinearExtrapolation(
      x=u,
      x1=xd[i],
      x2=xd[i + 1],
      y1=yd[i],
      y2=yd[i + 1],
      y1d=d[i],
      y2d=d[i + 1]);
end interpolate;


Package with mathematical functions

within Buildings.Utilities.Math;
package Functions "Package with mathematical functions"
  extends Modelica.Icons.VariantsPackage;
end Functions;


within Buildings.Utilities.Math.Functions;
function regStep
  "Approximation of a general step, such that the approximation is continuous and differentiable"
  extends Modelica.Icons.Function;
  input Real x "Abscissa value";
  input Real y1 "Ordinate value for x > 0";
  input Real y2 "Ordinate value for x < 0";
  input Real x_small(min=0) = 1e-5
    "Approximation of step for -x_small <= x <= x_small; x_small >= 0 required";
  output Real y "Ordinate value to approximate y = if x > 0 then y1 else y2";
algorithm
  y := smooth(1, if x >  x_small then y1 else
                 if x < -x_small then y2 else
                 if x_small > 0 then (x/x_small)*((x/x_small)^2 - 3)*(y2-y1)/4 + (y1+y2)/2 else (y1+y2)/2);

In the region -x_small < x < x_small a 2nd order polynomial is used
for a smooth transition from y1 to y2.

"));
end regStep;


Argument of x > 0. Function to provide a once continuously differentiable transition between
to arguments.

within Buildings.Utilities.Math.Functions;
function spliceFunction
  extends Modelica.Icons.Function;
    input Real pos "Argument of x > 0";
    input Real neg "Argument of x < 0";
    input Real x "Independent value";
    input Real deltax "Half width of transition interval";
    output Real out "Smoothed value";
protected
    constant Real lim = 0.9999999999;
    Real scaledX1;
    Real y;
    constant Real asin1 = Modelica.Math.asin(1);
algorithm
    scaledX1 := x/deltax;
    if scaledX1 <= -lim then
      out := neg;
    elseif scaledX1 >= lim then
      out := pos;
    else
      y := (Modelica.Math.tanh(Modelica.Math.tan(scaledX1*asin1)) + 1)/2;
      out := pos*y + (1 - y)*neg;
    end if;
end spliceFunction;


Function to compute the derivatives for cubic hermite spline interpolation. This function computes the derivatives at the support points xi
that can be used as input for evaluating a cubic hermite spline.

within Buildings.Utilities.Math.Functions;
function splineDerivatives
  "Function to compute the derivatives for cubic hermite spline interpolation"
  extends Modelica.Icons.Function;
  input Real x[:] "Support point, strictly increasing";
  input Real y[size(x, 1)] "Function values at x";
  input Boolean ensureMonotonicity=isMonotonic(y, strict=false)
    "Set to true to ensure monotonicity of the cubic hermite";
  output Real d[size(x, 1)] "Derivative at the support points";
protected
  Integer n=size(x, 1) "Number of data points";
  Real delta[n - 1] "Slope of secant line between data points";
  Real alpha "Coefficient to ensure monotonicity";
  Real beta "Coefficient to ensure monotonicity";
  Real tau "Coefficient to ensure monotonicity";

algorithm
  if (n>1) then
    assert(x[1] < x[n], "x must be strictly increasing.
  Received x[1] = " + String(x[1]) + "
           x[" + String(n) + "] = " + String(x[n]));
  // Check data
    assert(isMonotonic(x, strict=true),
      "x-values must be strictly increasing or decreasing.");
    if ensureMonotonicity then
      assert(isMonotonic(y, strict=false),
        "If ensureMonotonicity=true, y-values must be strictly increasing or decreasing.");
    end if;
  end if;

  // Compute derivatives at the support points
  if n == 1 then
    // only one data point
    d[1] :=0;
  elseif n == 2 then
    // linear function
    d[1] := (y[2] - y[1])/(x[2] - x[1]);
    d[2] := d[1];
  else
    // Slopes of the secant lines between i and i+1
    for i in 1:n - 1 loop
      delta[i] := (y[i + 1] - y[i])/(x[i + 1] - x[i]);
    end for;
    // Initial values for tangents at the support points.
    // End points use one-sided derivatives
    d[1] := delta[1];
    d[n] := delta[n - 1];

    for i in 2:n - 1 loop
      d[i] := (delta[i - 1] + delta[i])/2;
    end for;

  end if;
  // Ensure monotonicity
  if n > 2 and ensureMonotonicity then
    for i in 1:n - 1 loop
      if (abs(delta[i]) < Modelica.Constants.small) then
        d[i] := 0;
        d[i + 1] := 0;
      else
        alpha := d[i]/delta[i];
        beta := d[i + 1]/delta[i];
        // Constrain derivative to ensure monotonicity in this interval
        if (alpha^2 + beta^2) > 9 then
          tau := 3/(alpha^2 + beta^2)^(1/2);
          d[i] := delta[i]*alpha*tau;
          d[i + 1] := delta[i]*beta*tau;
        end if;
      end if;
    end for;
  end if;
end splineDerivatives;


within Buildings.Utilities.Math.Functions;
package BaseClasses "Package with base classes for Buildings.Utilities.Math.Functions"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Test case for Bessel function J0. This example demonstrates the use of the function for Bessel functions of the
first kind of order 0, <i>J0</i>.

within Buildings.Utilities.Math.Functions.Examples;
model BesselJ0 "Test case for Bessel function J0"
  extends Modelica.Icons.Example;

  Real J0 "Bessel function J0";

equation

  J0 = Buildings.Utilities.Math.Functions.besselJ0(time);
end BesselJ0;


Test case for Bessel function J1. This example demonstrates the use of the function for Bessel functions of the
first kind of order 1, <i>J1</i>.

within Buildings.Utilities.Math.Functions.Examples;
model BesselJ1 "Test case for Bessel function J1"
  extends Modelica.Icons.Example;

  Real J1 "Bessel function J1";

equation
  J1 = Buildings.Utilities.Math.Functions.besselJ1(time);
end BesselJ1;


Test case for Bessel function Y0. This example demonstrates the use of the function for Bessel functions of the
second kind of order 0, <i>Y0</i>.

within Buildings.Utilities.Math.Functions.Examples;
model BesselY0 "Test case for Bessel function Y0"
  extends Modelica.Icons.Example;

  Real Y0 "Bessel function Y0";

equation
  Y0 = Buildings.Utilities.Math.Functions.besselY0(time);
end BesselY0;


Test case for Bessel function Y1. This example demonstrates the use of the function for Bessel functions of the
second kind of order 1, <i>Y1</i>.

within Buildings.Utilities.Math.Functions.Examples;
model BesselY1 "Test case for Bessel function Y1"
  extends Modelica.Icons.Example;

  Real Y1 "Bessel function Y1";

equation
  Y1 = Buildings.Utilities.Math.Functions.besselY1(time);
end BesselY1;


Test case for evaluation of binomial coefficients. This example demonstrates the use of the function for the evaluation of the
binomial coefficient \"n choose k\".

within Buildings.Utilities.Math.Functions.Examples;
model Binomial "Test case for evaluation of binomial coefficients"
  extends Modelica.Icons.Example;

  Real bin[10] "Binomial coefficient";
  Integer n "Size of set";

equation
  n = integer(if time >= 1 then floor(time) else 1);

  for k in 1:10 loop
    if n >= k then
      bin[k] = Buildings.Utilities.Math.Functions.binomial(n,k);
    else
      bin[k] = 0.0;
    end if;
  end for;
end Binomial;


Test problem for cubic hermite splines. This example demonstrates the use of the function for cubic hermite interpolation
and linear extrapolation.
The example use interpolation with two different settings: One settings
produces a monotone cubic hermite, whereas the other setting
does not enforce monotonicity.
The resulting plot should look as shown below, where for better visibility, the support points have been marked with black dots.
Notice that the red curve is monotonically increasing.

within Buildings.Utilities.Math.Functions.Examples;
model CubicHermite "Test problem for cubic hermite splines"
  extends Modelica.Icons.Example;
  parameter Real[:] xd={-1,1,5,6} "Support points";
  parameter Real[size(xd, 1)] yd={-1,1,2,10} "Support points";
  parameter Real[size(xd, 1)] d(each fixed=false)
    "Derivatives at the support points";
  parameter Real[size(xd, 1)] dMonotone(each fixed=false)
    "Derivatives at the support points";
  parameter Boolean ensureMonotonicity=true;
  Real x "Independent variable";
  Real y "Dependent variable without monotone interpolation";
  Real yMonotone "Dependent variable with monotone interpolation";
  Integer i "Integer to select data interval";
initial algorithm
  // Get the derivative values at the support points
  d := Buildings.Utilities.Math.Functions.splineDerivatives(
    x=xd,
    y=yd,
    ensureMonotonicity=false);
  dMonotone := Buildings.Utilities.Math.Functions.splineDerivatives(x=xd, y=yd,
      ensureMonotonicity=true);
algorithm
  x := xd[1] + time*1.2*(xd[size(xd, 1)] - xd[1]) - 0.5;
  // i is a counter that is used to pick the derivative of d or dMonotonic
  // that correspond to the interval that contains x
  i := 1;
  for j in 1:size(xd, 1) - 1 loop
    if x > xd[j] then
      i := j;
    end if;
  end for;
  // Extrapolate or interpolate the data
  y := Buildings.Utilities.Math.Functions.cubicHermiteLinearExtrapolation(
    x=x,
    x1=xd[i],
    x2=xd[i + 1],
    y1=yd[i],
    y2=yd[i + 1],
    y1d=d[i],
    y2d=d[i + 1]);
  yMonotone :=
    Buildings.Utilities.Math.Functions.cubicHermiteLinearExtrapolation(
    x=x,
    x1=xd[i],
    x2=xd[i + 1],
    y1=yd[i],
    y2=yd[i + 1],
    y1d=dMonotone[i],
    y2d=dMonotone[i + 1]);
end CubicHermite;


Test case for the exponential integral, E1. This example demonstrates the use of the function for the exponential integral,
<i>E1</i>.

within Buildings.Utilities.Math.Functions.Examples;
model ExponentialIntegralE1
  "Test case for the exponential integral, E1"
  extends Modelica.Icons.Example;

  Real E1 "Exponential integral E1";

equation
  E1 = Buildings.Utilities.Math.Functions.exponentialIntegralE1(time);
end ExponentialIntegralE1;


Test case for evaluation of factorials. This example demonstrates the use of the function for the evaluation of
factorials.

within Buildings.Utilities.Math.Functions.Examples;
model Factorial "Test case for evaluation of factorials"
  extends Modelica.Icons.Example;

  Integer fac "Factorial of n";
  Integer n "n";

equation
  n = integer(floor(time));
  fac = Buildings.Utilities.Math.Functions.factorial(n);
end Factorial;


Test case for evaluation of falling factorials. This example demonstrates the use of the function for the evaluation of
falling factorials.

within Buildings.Utilities.Math.Functions.Examples;
model FallingFactorial
  "Test case for evaluation of falling factorials"
  extends Modelica.Icons.Example;

  Integer falFac[10] "Falling factorial of n";
  Integer n "n";

equation
  n = integer(floor(time));

  for k in 1:10 loop
    falFac[k] = Buildings.Utilities.Math.Functions.fallingFactorial(n,k);
  end for;
end FallingFactorial;


Test model for the interpolation function. This example demonstrates the function

Buildings.Utilities.Math.Functions.interpolate.

within Buildings.Utilities.Math.Functions.Examples;
model Interpolate "Test model for the interpolation function"
  extends Modelica.Icons.Example;

  parameter Real table[:,:]=[-50,-0.08709; -25,-0.06158; -10,-0.03895; -5,-0.02754;
      -3,-0.02133; -2,-0.01742; -1,-0.01232; 0,0; 1,0.01232; 2,0.01742; 3,0.02133;
      4.5,0.02613; 50,0.02614]
      "Table of mass flow rate in kg/s (second column) as a function of pressure difference in Pa (first column)";

  Modelica.Units.SI.PressureDifference dp
    "Pressure difference";
  Modelica.Units.SI.MassFlowRate m_flow
    "Mass flow rate";

protected
  parameter Real[:] xd=table[:,1] "x-axis support points";
  parameter Real[size(xd, 1)] yd=table[:,2] "y-axis support points";
  parameter Real[size(xd, 1)] d(each fixed=false) "Derivatives at the support points";

  Modelica.Blocks.Sources.Ramp ramp(
    duration=500,
    height=100,
    offset=-50) "Ramp from -50Pa to +50Pa";
initial equation
  d = Buildings.Utilities.Math.Functions.splineDerivatives(
    x=xd,
    y=yd,
    ensureMonotonicity=true);
equation
   dp=ramp.y;
   m_flow = Buildings.Utilities.Math.Functions.interpolate(u=dp, xd=xd, yd=yd, d=d);
end Interpolate;


Model that checks the correct implementation of the 1st order derivative of InverseXRegularized. This model validates the implementation of

Buildings.Utilities.Math.Functions.inverseXRegularized
and its first order derivative

Buildings.Utilities.Math.Functions.BaseClasses.der_smoothTransition.
If the derivative implementation is wrong, the simulation will stop with an error.

within Buildings.Utilities.Math.Functions.Examples;
model InverseXDerivativeCheck
  "Model that checks the correct implementation of the 1st order derivative of InverseXRegularized"
  extends Modelica.Icons.Example;

  constant Real gain = 4 "Gain for computing the mass flow rate";

  parameter Real delta = 0.7 "Smoothing coefficient";

  Real x "Independent variable";
  Real y_comp "Comparison value";
  Real y "Dependent variable";

  Real err "Integration error";
initial equation
 y = y_comp;
equation
  x = time^3*gain;
  y = Buildings.Utilities.Math.Functions.inverseXRegularized(
    x = x,
    delta = delta);
  der(y_comp) = Buildings.Utilities.Math.Functions.BaseClasses.der_inverseXRegularized(x=x,delta=delta,x_der=der(x));
  err = y-y_comp;
  assert(abs(err) < 1E-3, "Error in implementation.");
end InverseXDerivativeCheck;


Model that checks the correct implementation of the 2nd order derivative of InverseXRegularized. This model validates the implementation of

Buildings.Utilities.Math.Functions.inverseXRegularized
and its second order derivative

Buildings.Utilities.Math.Functions.BaseClasses.der_2_smoothTransition.
If the derivative implementation is wrong, the simulation will stop with an error.

within Buildings.Utilities.Math.Functions.Examples;
model InverseXDerivative_2_Check
  "Model that checks the correct implementation of the 2nd order derivative of InverseXRegularized"
  extends Modelica.Icons.Example;
  Buildings.Utilities.Diagnostics.CheckEquality cheEqu1(
    threShold=1e-3)
    "Block for checking integration error";
  Buildings.Utilities.Diagnostics.CheckEquality cheEqu2(
    threShold=1e-3)
    "Block for checking integration error";
  constant Real gain = 4 "Gain for computing the mass flow rate";

  parameter Real delta = 0.7 "Smoothing coefficient";

  Real x "Independent variable";
  Real y_comp "Comparison value";
  Real y "Dependent variable";
  Real der_y_comp "1st order derivative of comparison value";
  Real der_y "1st order derivative of dependent variable";

  Real err "Integration error";
  Real der_err "Integration error";
initial equation
 y = y_comp;
 der_y = der_y_comp;
equation
  x = time^3*gain;
  y = Buildings.Utilities.Math.Functions.inverseXRegularized(
    x = x,
    delta = delta);

  der_y = der(y);
  der_y_comp = der(y_comp);
  der(der_y) = der(der_y_comp);
  cheEqu1.u1 = y;
  cheEqu1.u2 = y_comp;
  err = cheEqu1.y;
  cheEqu2.u1 = der_y;
  cheEqu2.u2 = der_y_comp;
  der_err = cheEqu2.y;

  assert(abs(err) < 1E-3, "Error in implementation.");
  assert(abs(der_err) < 1E-3, "Error in implementation.");
end InverseXDerivative_2_Check;


Test problem for function that replaces 1/x around the origin by a twice continuously differentiable function. This example tests the implementation of

Buildings.Utilities.Math.Functions.inverseXRegularized.

within Buildings.Utilities.Math.Functions.Examples;
model InverseXRegularized
  "Test problem for function that replaces 1/x around the origin by a twice continuously differentiable function"
  extends Modelica.Icons.Example;
  Real x "Independent variable";
  parameter Real delta = 0.5 "Small value for approximation";
  final parameter Real deltaInv = 1/delta "Inverse value of delta";

  final parameter Real a = -15*deltaInv "Polynomial coefficient";
  final parameter Real b = 119*deltaInv^2 "Polynomial coefficient";
  final parameter Real c = -361*deltaInv^3 "Polynomial coefficient";
  final parameter Real d = 534*deltaInv^4 "Polynomial coefficient";
  final parameter Real e = -380*deltaInv^5 "Polynomial coefficient";
  final parameter Real f = 104*deltaInv^6 "Polynomial coefficient";

  Real y "Function value";
  Real xInv "Function value";
  Real dy_dt "First derivative of y with respect to t";
  Real d2y_dt2 "Second derivative of y with respect to t";
equation
  x=2*time-1;
  xInv = if ( abs(x) > 0.1)   then 1 / x else 0;
  y = Buildings.Utilities.Math.Functions.inverseXRegularized(
       x=x,
       delta=delta, deltaInv=deltaInv,
       a=a, b=b, c=c, d=d, e=e, f=f);
  dy_dt=der(y);
  d2y_dt2=der(dy_dt);
end InverseXRegularized;


Tests the correct implementation of the function isMonotonic. This example tests the correct implementation of the function

Buildings.Utilities.Math.Functions.isMonotonic.
If the function is implemented incorrect, the example will stop
with an error.

within Buildings.Utilities.Math.Functions.Examples;
model IsMonotonic
  "Tests the correct implementation of the function isMonotonic"
  extends Modelica.Icons.Example;
  Real x_incStrict[3] = {0, 1, 2} "strictly increasing";
  Real x_notMon[3] = {0, 3, 2} "not monotonic";
  Real x_incWeak[4] = {0, 1, 1, 2} "weakly increasing";
  Real x_notWeak[4] = {0, 3, 3, 2} "not weakly monotonic";
  Real x_decStrict[3] = {2.5, 2, 0.1} "strictly decreasing";
  Real x_decWeak[4] = {3, 1, 1, 0.5} "weakly decreasing";

equation
// Tests with weak monotonicity
    //strictly increasing
assert(Buildings.Utilities.Math.Functions.isMonotonic(x_incStrict, strict=false),
   "Error. Function should have returned true.");
     //not monotonic
assert(false == Buildings.Utilities.Math.Functions.isMonotonic(x_notMon, strict=false),
   "Error. Function should have returned true.");
     //weakly increasing
assert(Buildings.Utilities.Math.Functions.isMonotonic(x_incWeak, strict=false),
   "Error. Function should have returned true.");
     //not weakly monotonic
assert(false == Buildings.Utilities.Math.Functions.isMonotonic(x_notWeak, strict=false),
   "Error. Function should have returned true.");

    //strictly decreasing
assert(Buildings.Utilities.Math.Functions.isMonotonic({2.5, 2, 0.1}, strict=false),
   "Error. Function should have returned true.");
     //weakly decreasing
assert(Buildings.Utilities.Math.Functions.isMonotonic({3, 1, 1, 0.5}, strict=false),
   "Error. Function should have returned true.");

// Tests with strict monotonicity
    //strictly increasing
assert(Buildings.Utilities.Math.Functions.isMonotonic(x_incStrict, strict=true),
   "Error. Function should have returned true.");
     //not monotonic
assert(false == Buildings.Utilities.Math.Functions.isMonotonic(x_notMon, strict=true),
   "Error. Function should have returned true.");
     //weakly increasing
assert(false == Buildings.Utilities.Math.Functions.isMonotonic(x_incWeak, strict=true),
   "Error. Function should have returned true.");
     //not weakly monotonic
assert(false == Buildings.Utilities.Math.Functions.isMonotonic(x_notWeak, strict=true),
   "Error. Function should have returned true.");

    //strictly decreasing
assert(Buildings.Utilities.Math.Functions.isMonotonic(x_decStrict, strict=true),
   "Error. Function should have returned true.");
     //weakly decreasing
assert(false == Buildings.Utilities.Math.Functions.isMonotonic(x_decWeak, strict=true),
   "Error. Function should have returned true.");
end IsMonotonic;


within Buildings.Utilities.Math.Functions;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Function value. This example verifies the correct implementation of

Buildings.Utilities.Math.Functions.polynomial.

within Buildings.Utilities.Math.Functions.Examples;
model Polynomial
  extends Modelica.Icons.Example;
  Real x "Function value";
equation
  x=Buildings.Utilities.Math.Functions.polynomial(x=time^3-2, a={2, 4, -4, 5});
end Polynomial;


Test problem for function that linearizes y=x^n below some threshold. This example tests the implementation of

Buildings.Utilities.Math.Functions.powerLinearized.

within Buildings.Utilities.Math.Functions.Examples;
model PowerLinearized
  "Test problem for function that linearizes y=x^n below some threshold"
  extends Modelica.Icons.Example;
  Real T4(start=300^4) "Temperature raised to 4-th power";
  Real T "Temperature";
  Real TExact "Temperature";
equation
  T = (1+500*time);
  T = Buildings.Utilities.Math.Functions.powerLinearized(x=T4, x0=243.15^4, n=0.25);
  TExact = abs(T4)^(1/4);
end PowerLinearized;


Example model using quintic Hermite spline. Demonstration of the use of a quintic Hermite spline interpolation function.

within Buildings.Utilities.Math.Functions.Examples;
model QuinticHermite "Example model using quintic Hermite spline"
  extends Modelica.Icons.Example;
  parameter Real a = 0.5 "Exponential argument coefficient";
  parameter Real x1 = 1 "Lower abscissa value";
  parameter Real x2 = 2.6 "Upper abscissa value";
  parameter Real y1 = -x1 "Lower ordinate value";

  parameter Real y1d = -1 "Lower derivative";
  parameter Real y2d = a*exp(a*x2) "Upper derivative";
  parameter Real y1dd = 0 "Lower second derivative";
  parameter Real y2dd= a^2*exp(a*x2) "Upper second derivative";

  Real x = time "Abscissa value";
  Real y "Ordinate value";
  Real dy "Time derivative of ordinate value";
  Real ddy "Second time derivative of ordinate value";
  Real y2 "Second ordinate section";

equation
  y2 = exp(a*x2);

  y= noEvent(smooth(2,if x>x2 then exp(a*x)
     elseif x<x1 then -time
     else Buildings.Utilities.Math.Functions.quinticHermite(x=x,x1=x1,x2=x2,y1=y1,y2=y2,y1d=y1d,y2d=y2d,y1dd=y1dd,y2dd=y2dd)));
  dy=der(y);
  ddy=der(dy);
end QuinticHermite;


Function value. This example tests the implementation of

Buildings.Utilities.Math.Functions.regNonZeroPower.

within Buildings.Utilities.Math.Functions.Examples;
model RegNonZeroPower
  extends Modelica.Icons.Example;
  Real y "Function value";
equation
  y=Buildings.Utilities.Math.Functions.regNonZeroPower(
                                             time, 0.3, 0.5);
end RegNonZeroPower;


Exponent. This example checks whether the function derivative
is implemented correctly. If the derivative implementation
is not correct, the model will stop with an assert statement.

within Buildings.Utilities.Math.Functions.Examples;
model RegNonZeroPowerDerivativeCheck
  extends Modelica.Icons.Example;
 parameter Real n=0.33 "Exponent";
 parameter Real delta = 0.1 "Abscissa value where transition occurs";

  Real x;
  Real y;
initial equation
   y=x;
equation
  x=Buildings.Utilities.Math.Functions.regNonZeroPower(
                                             time^3,n, delta);
  der(y)=der(x);
  assert(abs(x-y) < 1E-2, "Model has an error");
end RegNonZeroPowerDerivativeCheck;


within Buildings.Utilities.Math.Functions.Examples;
model RegNonZeroPowerDerivative_2_Check
  extends Modelica.Icons.Example;

  parameter Real n=0.33 "Exponent";

  constant Real gain = 4 "Gain for computing the mass flow rate";

  parameter Real delta = 0.7 "Smoothing coefficient";

  Real x "Independent variable";
  Real y_comp "Comparison value";
  Real y "Dependent variable";
  Real der_y_comp "1st order derivative of comparison value";
  Real der_y "1st order derivative of dependent variable";

  Real err "Integration error";
  Real der_err "Integration error";
initial equation
 y = y_comp;
 der_y = der_y_comp;
equation
  x = time^3*gain;
  y = Buildings.Utilities.Math.Functions.regNonZeroPower(
       x =     x,
       n =     n,
       delta = delta);

  der_y = der(y);
  der_y_comp = der(y_comp);
  der(der_y) = der(der_y_comp);
  err     = y-y_comp;
  der_err = der_y-der_y_comp;

  assert(abs(err) < 1E-3, "Error in implementation.");
  assert(abs(der_err) < 1E-3, "Error in implementation.");
end RegNonZeroPowerDerivative_2_Check;


Example for inlined regStep function. This example tests the implementation of

Buildings.Utilities.Math.Functions.regStep.

within Buildings.Utilities.Math.Functions.Examples;
model RegStep "Example for inlined regStep function"
  extends Modelica.Icons.Example;
  Real y "Function value";
equation
  y=Buildings.Utilities.Math.Functions.regStep(time, 1, -1, 1e-5);
end RegStep;


Example for round function. This example tests the implementation of

Buildings.Utilities.Math.Functions.round
for different values of n.
Arguments and return values are scale to simplify the show that the scaling for the rounding
is implemented correctly.

within Buildings.Utilities.Math.Functions.Examples;
model Round "Example for round function"
  extends Modelica.Icons.Example;
  Real ym2 "Function value";
  Real ym1 "Function value";
  Real y "Function value";
  Real y1 "Function value";
  Real y2 "Function value";
equation
  ym2=Buildings.Utilities.Math.Functions.round(x=time*100, n=-2)/100;
  ym1=Buildings.Utilities.Math.Functions.round(x=time*10, n=-1)/10;
  y=Buildings.Utilities.Math.Functions.round(x=time, n=0);
  y1=Buildings.Utilities.Math.Functions.round(x=time/10, n=1)*10;
  y2=Buildings.Utilities.Math.Functions.round(x=time/100, n=2)*100;
end Round;


Smoothing area. This example checks whether the function derivative
is implemented correctly. If the derivative implementation
is not correct, the model will stop with an assert statement.

within Buildings.Utilities.Math.Functions.Examples;
model SmoothExponentialDerivativeCheck
  extends Modelica.Icons.Example;

  parameter Real delta = 0.5 "Smoothing area";
  Real x "Independent variable";
  Real y "Approximate function value";
  Real y_comp "Approximate function value";

  Real ex "Exact function value";
  Real err "Error";
initial equation
   y=y_comp;
equation
  x = time^3;
  y_comp=Buildings.Utilities.Math.Functions.smoothExponential(
                                               x=x, delta=delta);
  der(y)=der(y_comp);
  err = y_comp-y;
  assert(abs(err) < 1E-2, "Model has an error");
  ex=exp(-abs(x));
end SmoothExponentialDerivativeCheck;


Test model for the derivatives of the smoothHeavisidefunction. This model tests the first and second derivative of the twice Lipschitz continuously differentiable function

Buildings.Utilities.Math.Functions.smoothHeaviside.

within Buildings.Utilities.Math.Functions.Examples;
model SmoothHeavisideDerivatives
  "Test model for the derivatives of the smoothHeavisidefunction"
  extends Modelica.Icons.Example;
  Real y = Buildings.Utilities.Math.Functions.smoothHeaviside(x=time, delta=0.2) "Function value";
  Real der_y = der(y) "First derivative";
  Real der2_y = der(der_y) "Second derivative";
equation
end SmoothHeavisideDerivatives;