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; }