public void Initialize(Mike1DData mike1DData)
        {
            // A user function factory can inject custom functions to be used in the MIKE 1D control module
            // This needs only be done once.
            UserControlFunctionFactory ucff = new UserControlFunctionFactory(mike1DData.ControlData);

            mike1DData.ControlData.UserFunctionFactories.Add(ucff);

            // Define table data, so can use the function Table2D, as for example:
            //    Table2D('Gate_1Table_1', [SensorWL], [SensorQ])
            // Below are shown two ways of defining table data:
            // 1) Add table data by creating the table2D class in code
            // 2) Read table data from csv file.

            // 1) Add table by creating table class manually and associate them with an ID.
            // Table data could be read from a file or similar, but here we insert table data directly.
            Table2D table = new Table2D();

            table.XAxis       = new double[] { 6.0, 6.5, 6.8, 7.0, 7.2, 7.5, 8.0 };
            table.YAxis       = new double[] { 0.7, 1.0, 1.3 };
            table.TableValues = new double[, ] {
                { 6.00, 6.00, 6.00 },                          // x = 6.0
                { 6.40, 6.30, 6.20 },                          // x = 6.5
                { 6.50, 6.40, 6.30 },                          // x = 6.8
                { 6.60, 6.45, 6.35 },                          // x = 7.0
                { 6.70, 6.50, 6.40 },                          // x = 7.2
                { 6.85, 6.60, 6.40 },                          // x = 7.5
                { 7.00, 6.65, 6.40 },                          // x = 8.0
            };
            mike1DData.ControlData.TableInfos.Add("Gate_1Table_1", table);

            // 2) Read table data from file. It assumes a file called ControlTables.txt exists in the folder.
            ReadControlTableFile(mike1DData, "ControlTables.txt");
        }
 /// <summary>
 /// Return an IUserFunction for the function name "Table2D"
 /// </summary>
 /// <param name="name">Name of functions</param>
 /// <param name="arguments">Argument to function</param>
 /// <param name="errors">Errors when trying to create function. Leave as null if no errors found</param>
 public IUserFunction TryCreateUserFunction(string name, IList <ITypedExpression> arguments, out IList <string> errors)
 {
     errors = null;
     switch (name)
     {
     // Check the name of the function. The function will have the form:
     //     Table2D('tableId', argX, argY)
     case "Table2D":
     {
         // There must be three function arguments
         if (arguments.Count != 3)
         {
             AddError(ref errors, string.Format("{0} function requires {1} argument(s) but has {2}", name, 3, arguments.Count));
             return(null);
         }
         // The first argument must be a string containing the table ID
         if (!(arguments[0] is Constant <string>))
         {
             AddError(ref errors, "Table2DLookup function requires a first argument as a constant string being the table ID");
             return(null);
         }
         // The next two argument must be of type double
         IExpression <double> argX = TryConvertExpression <double>(name, 1, arguments[1], ref errors);
         IExpression <double> argY = TryConvertExpression <double>(name, 2, arguments[2], ref errors);
         // Get the table from the tableid
         string    tableid = ((Constant <string>)arguments[0]).Value;
         Table2D   table   = null;
         IAnyTable anytable;
         if (!_tableInfos.TryGetValue(tableid, out anytable))
         {
             AddError(ref errors, string.Format("{0}: table id not found: '{1}'", name, tableid));
         }
         else
         {
             table = anytable as Table2D;
             if (table == null)
             {
                 AddError(ref errors, string.Format("{0}: table has wrong type of data: '{1}'", name, tableid));
             }
         }
         // Create and return our control function
         return(new ControlFunctionTable2D(table, argX, argY));
     }
     }
     // Not "my" function name, just return null
     return(null);
 }
        /// <summary>
        /// Read table data from table file. Table must contain:
        ///
        /// tableID; xCount; yCount
        /// x-header having xCount values
        /// y-header having yCount values
        /// yCount lines (rows) having xCount values (columns)
        /// </summary>
        public static void ReadControlTableFile(Mike1DData mike1DData, string tableFile)
        {
            // Text split character.
            char[] splitChar = new char[] { ';' };

            // Search for tableFile relative to the MIKE 1D setup file.
            FilePath tablePath = new FilePath(tableFile, mike1DData.Connection.FilePath);

            // Check if file exists
            if (System.IO.File.Exists(tablePath.FullFilePath))
            {
                StreamReader sr = new StreamReader(tableFile);

                while (true)
                {
                    string line;

                    // Read table header. On the form: TableId;xCount;yCount
                    if ((line = ReadLine(sr)) == null)
                    {
                        // End-of-file met, done reading file, close file and return.
                        sr.Close();
                        return;
                    }
                    // Split table header line
                    string[] parts = line.Split(splitChar, StringSplitOptions.RemoveEmptyEntries);
                    if (parts.Length != 3)
                    {
                        throw new Exception("Could not read table header line: It must have the form 'TableId;xCount;yCount'. Line: " + line);
                    }
                    string tableId = parts[0].Trim();
                    int    xCount;
                    int    yCount;
                    if (!int.TryParse(parts[1].Trim(), out xCount))
                    {
                        throw new Exception("Could not read table header line: xCount not recognized. It must have the form 'TableId;xCount;yCount'. Line: " + line);
                    }
                    if (!int.TryParse(parts[2].Trim(), out yCount))
                    {
                        throw new Exception("Could not read table header line: yCount not recognized. It must have the form 'TableId;xCount;yCount'. Line: " + line);
                    }

                    // Create table
                    Table2D table = new Table2D(xCount, yCount);

                    // Read X header row
                    if ((line = ReadLine(sr)) == null)
                    {
                        throw new Exception(string.Format("Premature end-of-file when reading table {0}, X header row", tableId));
                    }
                    parts = line.Split(splitChar, StringSplitOptions.RemoveEmptyEntries);
                    if (parts.Length < xCount)
                    {
                        throw new Exception(string.Format("Number of values mismatch reading table {0}, X header row. Found {1} values, expected {2}", tableId, parts.Length, xCount));
                    }
                    for (int icol = 0; icol < xCount; icol++)
                    {
                        double val;
                        if (!double.TryParse(parts[icol].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out val))
                        {
                            throw new Exception(string.Format("X header value in table {0}, column {1} is invalid: {2}", tableId, icol + 1, parts[icol]));
                        }
                        table.XAxis[icol] = val;
                    }

                    // Read Y header row
                    if ((line = ReadLine(sr)) == null)
                    {
                        throw new Exception(string.Format("Premature end-of-file when reading table {0}, Y header row", tableId));
                    }
                    parts = line.Split(splitChar, StringSplitOptions.RemoveEmptyEntries);
                    if (parts.Length < yCount)
                    {
                        throw new Exception(string.Format("Number of values mismatch reading table {0}, Y header row. Found {1} values, expected {2}", tableId, parts.Length, yCount));
                    }
                    for (int irow = 0; irow < yCount; irow++)
                    {
                        double val;
                        if (!double.TryParse(parts[irow].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out val))
                        {
                            throw new Exception(string.Format("Y header value in table {0}, column {1} is invalid: {2}", tableId, irow + 1, parts[irow]));
                        }
                        table.YAxis[irow] = val;
                    }

                    // Read table values, loop over all rows
                    for (int irow = 0; irow < yCount; irow++)
                    {
                        // For reach row, read line and column values
                        if ((line = ReadLine(sr)) == null)
                        {
                            throw new Exception(string.Format("Premature end-of-file when reading table {0}, row {1} missing", tableId, irow + 1));
                        }
                        parts = line.Split(splitChar, StringSplitOptions.RemoveEmptyEntries);
                        if (parts.Length < xCount)
                        {
                            throw new Exception(string.Format("Number of values mismatch reading table {0}, row {1}. Found {2} values, expected {3}", tableId, irow + 1, parts.Length, xCount));
                        }
                        for (int icol = 0; icol < xCount; icol++)
                        {
                            double val;
                            if (!double.TryParse(parts[icol].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out val))
                            {
                                throw new Exception(string.Format("Value in table {0}, row {1}, column {2} is invalid: {3}", tableId, irow + 1, icol + 1, parts[icol]));
                            }
                            table.TableValues[icol, irow] = val;
                        }
                    }
                    // Done reading table, add to MIKE1D data.
                    mike1DData.ControlData.TableInfos.Add(tableId, table);
                }
            }
        }
 public ControlFunctionTable2D(Table2D table, IExpression <double> argumentX, IExpression <double> argumentY)
 {
     _table     = table;
     _argumentX = argumentX;
     _argumentY = argumentY;
 }