CombiTable1Ds

block CombiTable1Ds "Table look-up in one dimension (matrix/file) with one input and n outputs"
    extends Modelica.Blocks.Interfaces.SIMO(final nout = 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";
equation
    if verboseExtrapolation and (extrapolation == Modelica.Blocks.Types.Extrapolation.LastTwoPoints or extrapolation == Modelica.Blocks.Types.Extrapolation.HoldLastPoint) then 
        assert(noEvent(u_min <= u), "\nExtrapolation warning: The value u (=" + String(u) + ") 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 <= u_max), "\nExtrapolation warning: The value u (=" + String(u) + ") must be less or equal\nthan the maximum abscissa value u_max (=" + String(u_max) + ") defined in the table.\n", level = AssertionLevel.warning);
    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:nout loop
            y[i] = Internal.getTable1DValueNoDer(tableID, i, u);
        end for;
    elseif smoothness == Modelica.Blocks.Types.Smoothness.LinearSegments then 
        for i in 1:nout loop
            y[i] = Internal.getTable1DValueNoDer2(tableID, i, u);
        end for;
    else 
        for i in 1:nout loop
            y[i] = Internal.getTable1DValue(tableID, i, u);
        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\n2 output signals are present and that the first output interpolates\nvia column 2 and the second output interpolates via column 4 of the\ntable 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<blockquote><pre>\ntable = [0,  0;\n         1,  1;\n         2,  4;\n         4, 16]\nIf, 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></blockquote>\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<blockquote><pre>\nsmoothness = 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           = 6: Modified Akima interpolation: Smooth interpolation by cubic\n                Hermite splines such that der(y) is continuous, also if\n                extrapolated. Additionally, overshoots and edge cases of the\n                original Akima interpolation method are avoided.\n</pre></blockquote></li>\n<li>First and second <strong>derivatives</strong> are provided, with exception of the following two smoothness options.\n<ol>\n<li>No derivatives are provided for interpolation by constant segments.</li>\n<li>No second derivative is provided for linear interpolation.</li>\n</ol></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<blockquote><pre>\nextrapolation = 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></blockquote></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<blockquote><pre>\ntableName is \"NoName\" or has only blanks,\nfileName  is \"NoName\" or has only blanks.\n</pre></blockquote></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<blockquote><pre>\nsave tables.mat tab1 tab2 tab3\n</pre></blockquote>\n    or Scilab by command\n<blockquote><pre>\nsavematfile tables.mat tab1 tab2 tab3\n</pre></blockquote>\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<blockquote><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></blockquote>\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}})}));
end CombiTable1Ds;