CombiTable1D

block CombiTable1D "Table look-up in one dimension (matrix/file) with n inputs and n outputs"
    extends Modelica.Blocks.Interfaces.MIMOs(final n = size(columns, 1));

    parameter Boolean tableOnFile = false "= true, if table is defined on file or in function usertab"
        annotation (Dialog(group = "Table data definition"));
    parameter Real table[:,:] = fill(0, 0, 2) "Table matrix (grid = first column; e.g., table=[0, 0; 1, 1; 2, 4])"
        annotation (Dialog(
            group = "Table data definition",
            enable = not tableOnFile));
    parameter String tableName = "NoName" "Table name on file or in function usertab (see docu)"
        annotation (Dialog(
            group = "Table data definition",
            enable = tableOnFile));
    parameter String fileName = "NoName" "File where matrix is stored"
        annotation (Dialog(
            group = "Table data definition",
            enable = tableOnFile,
            loadSelector(
                filter = "Text files (*.txt);;MATLAB MAT-files (*.mat)",
                caption = "Open file in which table is present")));
    parameter Boolean verboseRead = true "= true, if info message that file is loading is to be printed"
        annotation (Dialog(
            group = "Table data definition",
            enable = tableOnFile));
    parameter Integer columns[:] = 2:size(table, 2) "Columns of table to be interpolated"
        annotation (Dialog(group = "Table data interpretation"));
    parameter Modelica.Blocks.Types.Smoothness smoothness = Modelica.Blocks.Types.Smoothness.LinearSegments "Smoothness of table interpolation"
        annotation (Dialog(group = "Table data interpretation"));
    parameter Modelica.Blocks.Types.Extrapolation extrapolation = Modelica.Blocks.Types.Extrapolation.LastTwoPoints "Extrapolation of data outside the definition range"
        annotation (Dialog(group = "Table data interpretation"));
    parameter Boolean verboseExtrapolation = false "= true, if warning messages are to be printed if table input is outside the definition range"
        annotation (Dialog(
            group = "Table data interpretation",
            enable = extrapolation == Modelica.Blocks.Types.Extrapolation.LastTwoPoints or extrapolation == Modelica.Blocks.Types.Extrapolation.HoldLastPoint));
    final parameter Real u_min = Internal.getTable1DAbscissaUmin(tableID) "Minimum abscissa value defined in table";
    final parameter Real u_max = Internal.getTable1DAbscissaUmax(tableID) "Maximum abscissa value defined in table";
protected
    parameter Modelica.Blocks.Types.ExternalCombiTable1D tableID = Modelica.Blocks.Types.ExternalCombiTable1D(if tableOnFile then tableName else "NoName", if tableOnFile and fileName <> "NoName" and not Modelica.Utilities.Strings.isEmpty(fileName) then fileName else "NoName", table, columns, smoothness, extrapolation, if tableOnFile then verboseRead else false) "External table object";

    function readTableData = Modelica.Blocks.Tables.Internal.readTable1DData "Read table data from text or MATLAB MAT-file";
equation
    if verboseExtrapolation and (extrapolation == Modelica.Blocks.Types.Extrapolation.LastTwoPoints or extrapolation == Modelica.Blocks.Types.Extrapolation.HoldLastPoint) then 
        for i in 1:n loop
            assert(noEvent(u_min <= u[i]), "\nExtrapolation warning: The value u[" + String(i) + "] (=" + String(u[i]) + ") must be greater or equal\nthan the minimum abscissa value u_min (=" + String(u_min) + ") defined in the table.\n", level = AssertionLevel.warning);
            assert(noEvent(u[i] <= u_max), "\nExtrapolation warning: The value u[" + String(i) + "] (=" + String(u[i]) + ") must be less or equal\nthan the maximum abscissa value u_max (=" + String(u_max) + ") defined in the table.\n", level = AssertionLevel.warning);
        end for;
    end if;
    if tableOnFile then 
        assert(tableName <> "NoName", "tableOnFile = true and no table name given");
    else 
        assert(0 < size(table, 1) and 0 < size(table, 2), "tableOnFile = false and parameter table is an empty matrix");
    end if;
    if smoothness == Modelica.Blocks.Types.Smoothness.ConstantSegments then 
        for i in 1:n loop
            y[i] = Internal.getTable1DValueNoDer(tableID, i, u[i]);
        end for;
    else 
        for i in 1:n loop
            y[i] = Internal.getTable1DValue(tableID, i, u[i]);
        end for;
    end if;

    annotation (
        Documentation(info = "<html>\n<p>\n<strong>Univariate constant</strong>, <strong>linear</strong> or <strong>cubic Hermite\nspline interpolation</strong> in <strong>one</strong> dimension of a\n<strong>table</strong>.\nVia parameter <strong>columns</strong> it can be defined how many columns of the\ntable are interpolated. If, e.g., columns={2,4}, it is assumed that 2 input\nand 2 output signals are present and that the first output interpolates\nthe first input via column 2 and the second output interpolates the\nsecond input via column 4 of the table matrix.\n</p>\n<p>\nThe grid points and function values are stored in a matrix \"table[i,j]\",\nwhere the first column \"table[:,1]\" contains the grid points and the\nother columns contain the data to be interpolated. Example:\n</p>\n<pre>\n   table = [0,  0;\n            1,  1;\n            2,  4;\n            4, 16]\n   If, e.g., the input u = 1.0, the output y =  1.0,\n       e.g., the input u = 1.5, the output y =  2.5,\n       e.g., the input u = 2.0, the output y =  4.0,\n       e.g., the input u =-1.0, the output y = -1.0 (i.e., extrapolation).\n</pre>\n<ul>\n<li>The interpolation interval is found by a binary search where the interval used in the\n    last call is used as start interval.</li>\n<li>Via parameter <strong>smoothness</strong> it is defined how the data is interpolated:\n<pre>\n  smoothness = 1: Linear interpolation\n             = 2: Akima interpolation: Smooth interpolation by cubic Hermite\n                  splines such that der(y) is continuous, also if extrapolated.\n             = 3: Constant segments\n             = 4: Fritsch-Butland interpolation: Smooth interpolation by cubic\n                  Hermite splines such that y preserves the monotonicity and\n                  der(y) is continuous, also if extrapolated.\n             = 5: Steffen interpolation: Smooth interpolation by cubic Hermite\n                  splines such that y preserves the monotonicity and der(y)\n                  is continuous, also if extrapolated.\n</pre></li>\n<li>Values <strong>outside</strong> of the table range, are computed by\n    extrapolation according to the setting of parameter <strong>extrapolation</strong>:\n<pre>\n  extrapolation = 1: Hold the first or last value of the table,\n                     if outside of the table scope.\n                = 2: Extrapolate by using the derivative at the first/last table\n                     points if outside of the table scope.\n                     (If smoothness is LinearSegments or ConstantSegments\n                     this means to extrapolate linearly through the first/last\n                     two table points.).\n                = 3: Periodically repeat the table data (periodical function).\n                = 4: No extrapolation, i.e. extrapolation triggers an error\n</pre></li>\n<li>If the table has only <strong>one row</strong>, the table value is returned,\n    independent of the value of the input signal.</li>\n<li>The grid values (first column) have to be strictly increasing.</li>\n</ul>\n<p>\nThe table matrix can be defined in the following ways:\n</p>\n<ol>\n<li>Explicitly supplied as <strong>parameter matrix</strong> \"table\",\n    and the other parameters have the following values:\n<pre>\n   tableName is \"NoName\" or has only blanks,\n   fileName  is \"NoName\" or has only blanks.\n</pre></li>\n<li><strong>Read</strong> from a <strong>file</strong> \"fileName\" where the matrix is stored as\n    \"tableName\". Both text and MATLAB MAT-file format is possible.\n    (The text format is described below).\n    The MAT-file format comes in four different versions: v4, v6, v7 and v7.3.\n    The library supports at least v4, v6 and v7 whereas v7.3 is optional.\n    It is most convenient to generate the MAT-file from FreeMat or MATLAB&reg;\n    by command\n<pre>\n   save tables.mat tab1 tab2 tab3\n</pre>\n    or Scilab by command\n<pre>\n   savematfile tables.mat tab1 tab2 tab3\n</pre>\n    when the three tables tab1, tab2, tab3 should be used from the model.<br>\n    Note, a fileName can be defined as URI by using the helper function\n    <a href=\"modelica://Modelica.Utilities.Files.loadResource\">loadResource</a>.</li>\n<li>Statically stored in function \"usertab\" in file \"usertab.c\".\n    The matrix is identified by \"tableName\". Parameter\n    fileName = \"NoName\" or has only blanks. Row-wise storage is always to be\n    preferred as otherwise the table is reallocated and transposed.\n    See the <a href=\"modelica://Modelica.Blocks.Tables\">Tables</a> package\n    documentation for more details.</li>\n</ol>\n<p>\nWhen the constant \"NO_FILE_SYSTEM\" is defined, all file I/O related parts of the\nsource code are removed by the C-preprocessor, such that no access to files takes place.\n</p>\n<p>\nIf tables are read from a text file, the file needs to have the\nfollowing structure (\"-----\" is not part of the file content):\n</p>\n<pre>\n-----------------------------------------------------\n#1\ndouble tab1(5,2)   # comment line\n  0   0\n  1   1\n  2   4\n  3   9\n  4  16\ndouble tab2(5,2)   # another comment line\n  0   0\n  2   2\n  4   8\n  6  18\n  8  32\n-----------------------------------------------------\n</pre>\n<p>\nNote, that the first two characters in the file need to be\n\"#1\" (a line comment defining the version number of the file format).\nAfterwards, the corresponding matrix has to be declared\nwith type (= \"double\" or \"float\"), name and actual dimensions.\nFinally, in successive rows of the file, the elements of the matrix\nhave to be given. The elements have to be provided as a sequence of\nnumbers in row-wise order (therefore a matrix row can span several\nlines in the file and need not start at the beginning of a line).\nNumbers have to be given according to C syntax (such as 2.3, -2, +2.e4).\nNumber separators are spaces, tab (\\t), comma (,), or semicolon (;).\nSeveral matrices may be defined one after another. Line comments start\nwith the hash symbol (#) and can appear everywhere.\nText files should either be ASCII or UTF-8 encoded, where UTF-8 encoded strings are only allowed in line comments and an optional UTF-8 BOM at the start of the text file is ignored.\nOther characters, like trailing non comments, are not allowed in the file.\n</p>\n<p>\nMATLAB is a registered trademark of The MathWorks, Inc.\n</p>\n</html>"),
        Icon(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Line(points = {
                    {-60, 40}, 
                    {-60, -40}, 
                    {60, -40}, 
                    {60, 40}, 
                    {30, 40}, 
                    {30, -40}, 
                    {-30, -40}, 
                    {-30, 40}, 
                    {-60, 40}, 
                    {-60, 20}, 
                    {60, 20}, 
                    {60, 0}, 
                    {-60, 0}, 
                    {-60, -20}, 
                    {60, -20}, 
                    {60, -40}, 
                    {-60, -40}, 
                    {-60, 40}, 
                    {60, 40}, 
                    {60, -40}}), 
                Line(points = {
                    {0, 40}, 
                    {0, -40}}), 
                Rectangle(
                    fillColor = {255, 215, 136},
                    fillPattern = FillPattern.Solid,
                    extent = {
                        {-60, 20}, 
                        {-30, 40}}), 
                Rectangle(
                    fillColor = {255, 215, 136},
                    fillPattern = FillPattern.Solid,
                    extent = {
                        {-60, 0}, 
                        {-30, 20}}), 
                Rectangle(
                    fillColor = {255, 215, 136},
                    fillPattern = FillPattern.Solid,
                    extent = {
                        {-60, -20}, 
                        {-30, 0}}), 
                Rectangle(
                    fillColor = {255, 215, 136},
                    fillPattern = FillPattern.Solid,
                    extent = {
                        {-60, -40}, 
                        {-30, -20}})}),
        Diagram(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Rectangle(
                    extent = {
                        {-60, 60}, 
                        {60, -60}},
                    fillColor = {235, 235, 235},
                    fillPattern = FillPattern.Solid,
                    lineColor = {0, 0, 255}), 
                Line(
                    points = {
                        {-100, 0}, 
                        {-58, 0}},
                    color = {0, 0, 255}), 
                Line(
                    points = {
                        {60, 0}, 
                        {100, 0}},
                    color = {0, 0, 255}), 
                Text(
                    extent = {
                        {-100, 100}, 
                        {100, 64}},
                    textString = "Univariate constant, linear or cubic Hermite spline table interpolation",
                    lineColor = {0, 0, 255}), 
                Line(
                    points = {
                        {-54, 40}, 
                        {-54, -40}, 
                        {54, -40}, 
                        {54, 40}, 
                        {28, 40}, 
                        {28, -40}, 
                        {-28, -40}, 
                        {-28, 40}, 
                        {-54, 40}, 
                        {-54, 20}, 
                        {54, 20}, 
                        {54, 0}, 
                        {-54, 0}, 
                        {-54, -20}, 
                        {54, -20}, 
                        {54, -40}, 
                        {-54, -40}, 
                        {-54, 40}, 
                        {54, 40}, 
                        {54, -40}},
                    color = {0, 0, 0}), 
                Line(points = {
                    {0, 40}, 
                    {0, -40}}), 
                Rectangle(
                    extent = {
                        {-54, 40}, 
                        {-28, 20}},
                    fillColor = {255, 255, 0},
                    fillPattern = FillPattern.Solid), 
                Rectangle(
                    extent = {
                        {-54, 20}, 
                        {-28, 0}},
                    fillColor = {255, 255, 0},
                    fillPattern = FillPattern.Solid), 
                Rectangle(
                    extent = {
                        {-54, 0}, 
                        {-28, -20}},
                    fillColor = {255, 255, 0},
                    fillPattern = FillPattern.Solid), 
                Rectangle(
                    extent = {
                        {-54, -20}, 
                        {-28, -40}},
                    fillColor = {255, 255, 0},
                    fillPattern = FillPattern.Solid), 
                Text(
                    extent = {
                        {-50, 54}, 
                        {-32, 42}},
                    textString = "u[1]/[2]",
                    lineColor = {0, 0, 255}), 
                Text(
                    extent = {
                        {-24, 54}, 
                        {0, 42}},
                    textString = "y[1]",
                    lineColor = {0, 0, 255}), 
                Text(
                    extent = {
                        {-2, -40}, 
                        {30, -54}},
                    textString = "columns",
                    lineColor = {0, 0, 255}), 
                Text(
                    extent = {
                        {2, 54}, 
                        {26, 42}},
                    textString = "y[2]",
                    lineColor = {0, 0, 255})}));
end CombiTable1D;