/// <summary> /// Update DFS2 bathymetry, lowering bathymetry with 5.61 meters everywhere, /// taking land value into account. /// <para> /// The method assumes that the OresundBathy900.dfs2 test file /// (or preferably a copy of it) is the input file. /// </para> /// </summary> /// <param name="bathyFilename">Path and name of OresundBathy900.dfs2 test file</param> public static void ModifyDfs2Bathymetry(string bathyFilename) { // Open file Dfs2File dfs2 = DfsFileFactory.Dfs2FileOpenEdit(bathyFilename); // Second custom block (index 1) contains the M21_MISC values, // where the 4th (index 3) is the land value float landValue = (float)dfs2.FileInfo.CustomBlocks[1][3]; // Read bathymetry data IDfsItemData2D <float> bathyData = (IDfsItemData2D <float>)dfs2.ReadItemTimeStepNext(); // Modify bathymetry data for (int i = 0; i < bathyData.Data.Length; i++) { if (bathyData.Data[i] != landValue) { bathyData.Data[i] -= 5.61f; } } // Write back bathymetry data dfs2.WriteItemTimeStep(1, 0, 0, bathyData.Data); dfs2.Close(); }
/// <summary> /// Example of how to create a M21 Dfs2 Bathymetry from scratch. This method /// creates a file matching the OresundBathy900.dfs2 test file. /// </summary> /// <param name="bathyDataArray">Array of bathymetry data, 1D array with 2D data, size n x m</param> /// <param name="filename">Path and name of the new file to create</param> public static void CreateM21Bathymetry(float[] bathyDataArray, string filename) { DfsFactory factory = new DfsFactory(); Dfs2Builder builder = Dfs2Builder.Create(@"C:\0\Training\Bat1_0.dfs2", @"Grid editor", 1); // Set up the header builder.SetDataType(0); builder.SetGeographicalProjection(factory.CreateProjectionGeoOrigin("UTM-33", 12.438741600559911, 55.2257078424238, 327)); builder.SetTemporalAxis(factory.CreateTemporalEqCalendarAxis(eumUnit.eumUsec, new DateTime(2003, 01, 01, 0, 0, 0), 0, 1)); builder.SetSpatialAxis(factory.CreateAxisEqD2(eumUnit.eumUmeter, 72, 0, 900, 94, 0, 900)); builder.DeleteValueFloat = -1e-30f; builder.AddCustomBlock(factory.CreateCustomBlock("Display Settings", new int[] { 1, 0, 0 })); builder.AddCustomBlock(factory.CreateCustomBlock("M21_Misc", new float[] { 327f, 0f, -900f, 10f, 0f, 0f, 0f })); // Set up dynamic items builder.AddDynamicItem("Bathymetry", eumQuantity.Create(eumItem.eumIWaterLevel, eumUnit.eumUmeter), DfsSimpleType.Float, DataValueType.Instantaneous); // Create and get file builder.CreateFile(filename); Dfs2File file = builder.GetFile(); // Add bathymetry data file.WriteItemTimeStepNext(0, bathyDataArray); file.Close(); }
/// <summary> /// Example of how to get from a geographical coordinate to an (j,k) index /// in the 2D grid. It also shows how to get the closest cell value and how /// to perform bilinear interpolation. /// <para> /// The method assumes that the OresundHD.dfs2 test file is the input file. /// </para> /// </summary> /// <param name="filename">Path and name of OresundHD.dfs2 test file</param> public static void GetjkIndexForGeoCoordinate(string filename) { Dfs2File file = DfsFileFactory.Dfs2FileOpen(filename); // The spatial axis is a EqD2 axis IDfsAxisEqD2 axis = (IDfsAxisEqD2)file.SpatialAxis; // Data for first time step IDfsItemData2D <float> data = (IDfsItemData2D <float>)file.ReadItemTimeStep(1, 0); // Get the projection and create a cartography object IDfsProjection projection = file.FileInfo.Projection; DHI.Projections.Cartography cart = new DHI.Projections.Cartography(projection.WKTString, projection.Longitude, projection.Latitude, projection.Orientation); // Coordinates just south of Amager double lon = 12.59; double lat = 55.54; // Get the (x,y) grid coordinates double x; double y; cart.Geo2Xy(lon, lat, out x, out y); Console.Out.WriteLine("Grid coordinates (x,y) = ({0:0.000},{1:0.000})", x, y); Console.Out.WriteLine("Relative grid coordinates (x,y) = ({0:0.000},{1:0.000})", x / axis.Dx, y / axis.Dy); // Calculate the cell indices of the lon-lat coordinate. // The cell extents from its center and +/- 1/2 dx and dy // in each direction int j = (int)(x / axis.Dx + 0.5); // 30 int k = (int)(y / axis.Dy + 0.5); // 27 Console.Out.WriteLine("Value in cell ({0},{1}) = {2}", j, k, data[j, k]); // If you want to interpolate between the values, calculate // the (j,k) indices of lower left corner and do bilinear interpolation. // This procedure does not take delete values into account!!! j = (int)(x / axis.Dx); // 30 k = (int)(y / axis.Dy); // 26 double xFrac = (x % axis.Dx) / axis.Dx; // fraction of j+1 value double yFrac = (y % axis.Dy) / axis.Dy; // fraction of k+1 value double vk = (1 - xFrac) * data[j, k] + xFrac * data[j + 1, k]; double vkp1 = (1 - xFrac) * data[j, k + 1] + xFrac * data[j + 1, k + 1]; double v = (1 - yFrac) * vk + yFrac * vkp1; Console.Out.WriteLine("Interpolated value = {0}", v); file.Close(); }
/// <summary> /// Example of how to update item axis in a dfs2 file. /// <para> /// The method assumes that the OresundHD.dfs2 test file /// (or preferably a copy of it) is the input file. /// </para> /// </summary> /// <param name="filename">Path and name of OresundHD.dfs2 test file</param> public static void ModifyDfs2ItemAxis(string filename) { Dfs2File file = DfsFileFactory.Dfs2FileOpenEdit(filename); IDfsAxisEqD2 axisEqD2 = ((IDfsAxisEqD2)file.SpatialAxis); axisEqD2.X0 = 55; axisEqD2.Dx = 905; axisEqD2.Y0 = -55; axisEqD2.Dy = 915; file.Close(); }
/// <summary> /// Create maximum velocity field for a dfs2 file /// <para> /// FFrom a dfs2 file containing items (H-P-Q), (P-Q-Speed) or (u-v-Speed), /// find maximum velocity for each cell and store in [outputFilename] /// </para> /// </summary> public static void MaxVelocityField(string sourceFilename, string outfilename) { // Open source file IDfs2File source = DfsFileFactory.Dfs2FileOpen(sourceFilename); // Create output file Dfs2Builder builder = Dfs2Builder.Create("Max Velocity", @"MIKE SDK", 0); // Set up the header builder.SetDataType(1); builder.SetGeographicalProjection(source.FileInfo.Projection); builder.SetTemporalAxis(source.FileInfo.TimeAxis); builder.SetSpatialAxis(source.SpatialAxis); builder.DeleteValueFloat = -1e-30f; // Add custom block foreach (IDfsCustomBlock customBlock in source.FileInfo.CustomBlocks) { builder.AddCustomBlock(customBlock); } // Set up dynamic items builder.AddDynamicItem("Maximum Speed", eumQuantity.Create(eumItem.eumIFlowVelocity, eumUnit.eumUmeterPerSec), DfsSimpleType.Float, DataValueType.Instantaneous); builder.AddDynamicItem("u-velocity", eumQuantity.Create(eumItem.eumIFlowVelocity, eumUnit.eumUmeterPerSec), DfsSimpleType.Float, DataValueType.Instantaneous); builder.AddDynamicItem("v-velocity", eumQuantity.Create(eumItem.eumIFlowVelocity, eumUnit.eumUmeterPerSec), DfsSimpleType.Float, DataValueType.Instantaneous); //builder.AddDynamicItem("H Water Depth m", eumQuantity.Create(eumItem.eumIWaterLevel, eumUnit.eumUmeter), DfsSimpleType.Float, DataValueType.Instantaneous); // Create file builder.CreateFile(outfilename); // Add static items containing bathymetri data, use data from source IDfsStaticItem sourceStaticItem; while (null != (sourceStaticItem = source.ReadStaticItemNext())) { builder.AddStaticItem(sourceStaticItem.Name, sourceStaticItem.Quantity, sourceStaticItem.Data); } // Get the file Dfs2File file = builder.GetFile(); // Arrays storing max-speed values int numberOfCells = file.SpatialAxis.SizeOfData; float[] maxSpeed = new float[numberOfCells]; float[] uAtMaxSpeed = new float[numberOfCells]; float[] vAtMaxSpeed = new float[numberOfCells]; // Initialize with delete values for (int i = 0; i < numberOfCells; i++) { maxSpeed[i] = source.FileInfo.DeleteValueFloat; uAtMaxSpeed[i] = source.FileInfo.DeleteValueFloat; vAtMaxSpeed[i] = source.FileInfo.DeleteValueFloat; } // Create empty ItemData's, for easing reading of source data IDfsItemData2D <float>[] datas = new IDfsItemData2D <float> [source.ItemInfo.Count]; for (int i = 0; i < source.ItemInfo.Count; i++) { datas[i] = source.CreateEmptyItemData <float>(i + 1); } // Find HPQ items in file - uses StartsWith, since the string varies slightly with the version of the engine. int dIndex = source.ItemInfo.FindIndex(item => item.Name.StartsWith("H Water Depth", StringComparison.OrdinalIgnoreCase)); int pIndex = source.ItemInfo.FindIndex(item => item.Name.StartsWith("P Flux", StringComparison.OrdinalIgnoreCase)); int qIndex = source.ItemInfo.FindIndex(item => item.Name.StartsWith("Q Flux", StringComparison.OrdinalIgnoreCase)); int sIndex = source.ItemInfo.FindIndex(item => item.Name.StartsWith("Current Speed", StringComparison.OrdinalIgnoreCase)); int uIndex = source.ItemInfo.FindIndex(item => item.Name.StartsWith("U velocity", StringComparison.OrdinalIgnoreCase)); int vIndex = source.ItemInfo.FindIndex(item => item.Name.StartsWith("V velocity", StringComparison.OrdinalIgnoreCase)); // Either p and q must be there, or u and v, and either d or s must be there. bool haspq = (pIndex >= 0 && qIndex >= 0); bool hasuv = (uIndex >= 0 && vIndex >= 0); if (!hasuv && !haspq || dIndex < 0 && sIndex < 0) { throw new Exception("Could not find items. File must have H-P-Q items, P-Q-Speed or U-V-Speed items"); } IDfsItemData2D <float> dItem = dIndex >= 0 ? datas[dIndex] : null; IDfsItemData2D <float> pItem = pIndex >= 0 ? datas[pIndex] : null; IDfsItemData2D <float> qItem = qIndex >= 0 ? datas[qIndex] : null; IDfsItemData2D <float> sItem = sIndex >= 0 ? datas[sIndex] : null; IDfsItemData2D <float> uItem = uIndex >= 0 ? datas[uIndex] : null; IDfsItemData2D <float> vItem = vIndex >= 0 ? datas[vIndex] : null; // Spatial 2D axis IDfsAxisEqD2 axis = (IDfsAxisEqD2)source.SpatialAxis; double dx = axis.Dx; double dy = axis.Dy; // Loop over all time steps for (int i = 0; i < source.FileInfo.TimeAxis.NumberOfTimeSteps; i++) { // Read data for all items from source file. That will also update the depth, p and q. for (int j = 0; j < source.ItemInfo.Count; j++) { source.ReadItemTimeStep(datas[j], i); } // For each cell, find maximum speed and store u, v and depth at that point in time. for (int j = 0; j < numberOfCells; j++) { // Skip delete values if (dItem?.Data[j] == source.FileInfo.DeleteValueFloat || sItem?.Data[j] == source.FileInfo.DeleteValueFloat) { continue; } double p = pItem.Data[j]; double q = qItem.Data[j]; double speed, u, v; if (sItem != null) { // Use speed from result file speed = sItem.Data[j]; if (hasuv) { // Use u and v from result file u = uItem.Data[j]; v = vItem.Data[j]; } else // (haspq) { // Calculate u and v from speed and direction of p and q double pqLength = System.Math.Sqrt(p * p + q * q); u = hasuv ? uItem.Data[j] : speed * p / pqLength; v = hasuv ? vItem.Data[j] : speed * q / pqLength; } } else // (dItem != null) { // Current speed is not directly available in source file, calculate from u and v if (hasuv) { u = uItem.Data[j]; v = vItem.Data[j]; } else { // u and v is not available, calculate fromdh, p and q. double d = dItem.Data[j]; u = pItem.Data[j] / d; v = qItem.Data[j] / d; } speed = System.Math.Sqrt(u * u + v * v); } if (speed > maxSpeed[j]) { maxSpeed[j] = (float)speed; uAtMaxSpeed[j] = (float)u; vAtMaxSpeed[j] = (float)v; } } } file.WriteItemTimeStepNext(0, maxSpeed); file.WriteItemTimeStepNext(0, uAtMaxSpeed); file.WriteItemTimeStepNext(0, vAtMaxSpeed); //file.WriteItemTimeStepNext(0, maxDepth); source.Close(); file.Close(); }
/// <summary> /// Example of how to create a Dfs2 file from scratch. This method /// creates a copy of the OresundHD.dfs2 test file. /// <para> /// Data for static and dynamic item is taken from a source dfs file, /// which here is the OresundHD.dfs2 test file. The data could come /// from any other source. /// </para> /// </summary> /// <param name="sourceFilename">Path and name of the OresundHD.dfs2 test file</param> /// <param name="filename">Path and name of the new file to create</param> public static void CreateDfs2File(string sourceFilename, string filename) { IDfs2File source = DfsFileFactory.Dfs2FileOpen(sourceFilename); DfsFactory factory = new DfsFactory(); Dfs2Builder builder = Dfs2Builder.Create("", @"C:\Program Files\DHI\2010\bin\nmodel.exe", 0); // Set up the header builder.SetDataType(1); builder.SetGeographicalProjection(factory.CreateProjectionGeoOrigin("UTM-33", 12.438741600559766, 55.225707842436385, 326.99999999999955)); builder.SetTemporalAxis(factory.CreateTemporalEqCalendarAxis(eumUnit.eumUsec, new DateTime(1993, 12, 02, 0, 0, 0), 0, 86400)); builder.SetSpatialAxis(factory.CreateAxisEqD2(eumUnit.eumUmeter, 71, 0, 900, 91, 0, 900)); builder.DeleteValueFloat = -1e-30f; // Add custom block // M21_Misc : {orientation (should match projection), drying depth, -900=has projection, land value, 0, 0, 0} builder.AddCustomBlock(factory.CreateCustomBlock("M21_Misc", new float[] { 327f, 0.2f, -900f, 10f, 0f, 0f, 0f })); // Set up dynamic items builder.AddDynamicItem("H Water Depth m", eumQuantity.Create(eumItem.eumIWaterLevel, eumUnit.eumUmeter), DfsSimpleType.Float, DataValueType.Instantaneous); builder.AddDynamicItem("P Flux m^3/s/m", eumQuantity.Create(eumItem.eumIFlowFlux, eumUnit.eumUm3PerSecPerM), DfsSimpleType.Float, DataValueType.Instantaneous); builder.AddDynamicItem("Q Flux m^3/s/m", eumQuantity.Create(eumItem.eumIFlowFlux, eumUnit.eumUm3PerSecPerM), DfsSimpleType.Float, DataValueType.Instantaneous); // Create file builder.CreateFile(filename); // Add static items containing bathymetri data, use data from source IDfsStaticItem sourceStaticItem = source.ReadStaticItemNext(); builder.AddStaticItem("Static item", eumQuantity.UnDefined, sourceStaticItem.Data); // Get the file Dfs2File file = builder.GetFile(); // Loop over all time steps for (int i = 0; i < source.FileInfo.TimeAxis.NumberOfTimeSteps; i++) { // Loop over all items for (int j = 0; j < source.ItemInfo.Count; j++) { // Add data for all item-timesteps, copying data from source file. // Read data from source file IDfsItemData2D <float> sourceData = (IDfsItemData2D <float>)source.ReadItemTimeStepNext(); // Create empty item data, and copy over data from source // The IDfsItemData2D can handle 2D indexing, on the form data2D[k,l]. // An ordinary array, float[], can also be used, though indexing from 2D to 1D must be // handled by user code i.e. using data1D[k + l*xCount] compared to data2D[k,l] IDfsItemData2D <float> itemData2D = (IDfsItemData2D <float>)file.CreateEmptyItemData(j + 1); for (int k = 0; k < 71; k++) { for (int l = 0; l < 91; l++) { itemData2D[k, l] = sourceData[k, l]; } } // the itemData2D.Data is a float[], so any float[] of the correct size is valid here. file.WriteItemTimeStep(j + 1, i, sourceData.Time, itemData2D.Data); } } source.Close(); file.Close(); }
/// <summary> /// Create DFS2 file with interpolated values from the 3x3 quadrangles, /// with various delete values applied in each time step. /// </summary> /// <param name="centerOnly">Only use center quadrangle</param> public void DeleteValueVisualDfs2Test(bool centerOnly) { DfsFactory factory = new DfsFactory(); Dfs2Builder dfs2Builder = new Dfs2Builder(); dfs2Builder.SetDataType(0); dfs2Builder.SetTemporalAxis(factory.CreateTemporalEqTimeAxis(eumUnit.eumUsec, 0, 1)); dfs2Builder.SetSpatialAxis(factory.CreateAxisEqD2(eumUnit.eumUmeter, 200, 0, 0.1, 200, 0, 0.1)); dfs2Builder.SetGeographicalProjection(factory.CreateProjectionUndefined()); dfs2Builder.AddDynamicItem("DeleteValueSmooth", eumQuantity.UnDefined, DfsSimpleType.Float, DataValueType.Instantaneous); dfs2Builder.AddDynamicItem("DeleteValueBox", eumQuantity.UnDefined, DfsSimpleType.Float, DataValueType.Instantaneous); dfs2Builder.DeleteValueFloat = (float)d; if (centerOnly) { dfs2Builder.CreateFile(UnitTestHelper.TestDataDir + "test_InterpQuadCenter.dfs2"); } else { dfs2Builder.CreateFile(UnitTestHelper.TestDataDir + "test_InterpQuad.dfs2"); } Dfs2File dfs2File = dfs2Builder.GetFile(); // Calculate interpolation weights QuadWeights[][] weights = new QuadWeights[200][]; for (int j = 0; j < 200; j++) { double y = 5 + 0.1 * j + 0.05; weights[j] = new QuadWeights[200]; for (int i = 0; i < 200; i++) { double x = 5 + 0.1 * i + 0.05; weights[j][i].Weights = InterpQuadrangle.UndefinedWeights(); for (int jr = 0; jr < 3; jr++) { for (int ir = 0; ir < 3; ir++) { if (centerOnly && (jr != 1 || ir != 1)) { continue; } double x0 = xcoords[ind(ir, jr)]; double x1 = xcoords[ind(ir + 1, jr)]; double x2 = xcoords[ind(ir + 1, jr + 1)]; double x3 = xcoords[ind(ir, jr + 1)]; double y0 = ycoords[ind(ir, jr)]; double y1 = ycoords[ind(ir + 1, jr)]; double y2 = ycoords[ind(ir + 1, jr + 1)]; double y3 = ycoords[ind(ir, jr + 1)]; if (MeshExtensions.IsPointInsideQuadrangle(x, y, x0, y0, x1, y1, x2, y2, x3, y3)) { weights[j][i].IR = ir; weights[j][i].JR = jr; weights[j][i].Weights = InterpQuadrangle.InterpolationWeights(x, y, x0, y0, x1, y1, x2, y2, x3, y3); } } } } } // Original center quadrangle values double z0 = zcoords[ind(1, 1)]; double z1 = zcoords[ind(1 + 1, 1)]; double z2 = zcoords[ind(1 + 1, 1 + 1)]; double z3 = zcoords[ind(1, 1 + 1)]; float[] data = new float[200 * 200]; VisualDfs2Data(weights, data, z0, z1, z2, z3, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, z1, z2, z3, false); dfs2File.WriteItemTimeStepNext(0, data); // One delete value VisualDfs2Data(weights, data, d, z1, z2, z3, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, z1, z2, z3, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, d, z2, z3, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, d, z2, z3, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, z1, d, z3, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, z1, d, z3, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, z1, z2, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, z1, z2, d, false); dfs2File.WriteItemTimeStepNext(0, data); // Two adjacent delete values VisualDfs2Data(weights, data, d, d, z2, z3, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, d, z2, z3, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, d, d, z3, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, d, d, z3, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, z1, d, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, z1, d, d, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, z1, z2, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, z1, z2, d, false); dfs2File.WriteItemTimeStepNext(0, data); // Two diagonal delete values VisualDfs2Data(weights, data, d, z1, d, z3, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, z1, d, z3, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, d, z2, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, d, z2, d, false); dfs2File.WriteItemTimeStepNext(0, data); // Three delete values VisualDfs2Data(weights, data, d, d, d, z3, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, d, d, z3, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, d, z2, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, d, z2, d, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, z1, d, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, z1, d, d, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, d, d, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z0, d, d, d, false); dfs2File.WriteItemTimeStepNext(0, data); // All delete values VisualDfs2Data(weights, data, d, d, d, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, d, d, d, false); dfs2File.WriteItemTimeStepNext(0, data); dfs2File.Close(); }
/// <summary> Write dfs2 file </summary> private void Write(string dfsFilename, string projectionString) { DfsFactory factory = new DfsFactory(); Dfs2Builder builder = new Dfs2Builder(); // Data type builder.SetDataType(0); // Projection and spatial axis double lon0; double lat0; double dx; double dy; int flip; FindAxisProperties(out lon0, out lat0, out dx, out dy, out flip); builder.SetGeographicalProjection(factory.CreateProjectionGeoOrigin(projectionString, lon0, lat0, 0)); builder.SetSpatialAxis(factory.CreateAxisEqD2(eumUnit.eumUdegree, _dimensions[0], 0, dx, _dimensions[1], 0, dy)); // Time axis eumUnit timeUnit; DateTime startDateTime; double timeStep; FindTimeProperties(out timeUnit, out startDateTime, out timeStep); builder.SetTemporalAxis(factory.CreateTemporalEqCalendarAxis(timeUnit, startDateTime, 0, timeStep)); // Add dynamic items foreach (Variable item in _items) { eumQuantity quantity = GetQuantityFromItem(item); builder.AddDynamicItem(item.Name, quantity, DfsSimpleType.Float, DataValueType.Instantaneous); } // Create and get file (no static items there) builder.CreateFile(dfsFilename); Dfs2File dfs2File = builder.GetFile(); // Write data to file int itemSize = _dimensions[0] * _dimensions[1]; float[] values = new float[itemSize]; float[] valuesFlipped = new float[itemSize]; for (int i = 0; i < _time.Array.Length; i++) { for (int j = 0; j < _items.Count; j++) { // Time of time step double time = (double)_time.Array.GetValue(i); // Values for all time steps float[] allfloats = (float[])_items[j].Array; // Copy single time step data from allFloats to values Array.Copy(allfloats, i * itemSize, values, 0, itemSize); // Flip values, if necessary float[] actual; if (flip == 0) { actual = values; } else { PerformFlip(flip, values, valuesFlipped); actual = valuesFlipped; } // Save values to file dfs2File.WriteItemTimeStepNext(time, actual); } } dfs2File.Close(); }
/// <summary> /// Create DFS2 file with iterpolated values from the 3x3 quadrangles, /// with various delete values applied in each time step. /// </summary> public void DeleteValueVisualDfs2DoTest() { string meshFileName = UnitTestHelper.TestDataDir + "small.mesh"; MeshFile file = MeshFile.ReadMesh(meshFileName); _meshVisual = file.ToSMeshData(); DfsFactory factory = new DfsFactory(); Dfs2Builder dfs2Builder = new Dfs2Builder(); dfs2Builder.SetDataType(0); dfs2Builder.SetTemporalAxis(factory.CreateTemporalEqTimeAxis(eumUnit.eumUsec, 0, 1)); dfs2Builder.SetSpatialAxis(factory.CreateAxisEqD2(eumUnit.eumUmeter, 80, 0, 0.01, 80, 0, 0.01)); dfs2Builder.SetGeographicalProjection(factory.CreateProjectionUndefined()); dfs2Builder.AddDynamicItem("DeleteValueSmooth", eumQuantity.UnDefined, DfsSimpleType.Float, DataValueType.Instantaneous); dfs2Builder.AddDynamicItem("DeleteValueBox", eumQuantity.UnDefined, DfsSimpleType.Float, DataValueType.Instantaneous); dfs2Builder.DeleteValueFloat = (float)d; dfs2Builder.CreateFile(UnitTestHelper.TestDataDir + "test_InterpTri.dfs2"); Dfs2File dfs2File = dfs2Builder.GetFile(); // Calculate interpolation weights MeshWeights[][] weights = new MeshWeights[80][]; for (int j = 0; j < 80; j++) { double y = 0.2 + 0.01 * j + 0.005; weights[j] = new MeshWeights[80]; for (int i = 0; i < 80; i++) { double x = 0.4 + 0.01 * i + 0.005; weights[j][i].QuadWeights = InterpQuadrangle.UndefinedWeights(); weights[j][i].TriWeights = InterpTriangle.UndefinedWeights(); for (int ielmt = 0; ielmt < _meshVisual.NumberOfElements; ielmt++) { var elmtNodes = _meshVisual.ElementTable[ielmt]; if (elmtNodes.Length == 4) { double x0 = _meshVisual.X[elmtNodes[0]]; double x1 = _meshVisual.X[elmtNodes[1]]; double x2 = _meshVisual.X[elmtNodes[2]]; double x3 = _meshVisual.X[elmtNodes[3]]; double y0 = _meshVisual.Y[elmtNodes[0]]; double y1 = _meshVisual.Y[elmtNodes[1]]; double y2 = _meshVisual.Y[elmtNodes[2]]; double y3 = _meshVisual.Y[elmtNodes[3]]; if (MeshExtensions.IsPointInsideQuadrangle(x, y, x0, y0, x1, y1, x2, y2, x3, y3)) { weights[j][i].ElmtIndex = ielmt; weights[j][i].QuadWeights = InterpQuadrangle.InterpolationWeights(x, y, x0, y0, x1, y1, x2, y2, x3, y3); } } else { double x0 = _meshVisual.X[elmtNodes[0]]; double x1 = _meshVisual.X[elmtNodes[1]]; double x2 = _meshVisual.X[elmtNodes[2]]; double y0 = _meshVisual.Y[elmtNodes[0]]; double y1 = _meshVisual.Y[elmtNodes[1]]; double y2 = _meshVisual.Y[elmtNodes[2]]; if (MeshExtensions.IsPointInsideTriangle(x, y, x0, y0, x1, y1, x2, y2)) { weights[j][i].ElmtIndex = ielmt; weights[j][i].TriWeights = InterpTriangle.InterpolationWeights(x, y, x0, y0, x1, y1, x2, y2); } } } } } // Original center quadrangle values double z4 = _meshVisual.Z[3]; double z6 = _meshVisual.Z[5]; double z8 = _meshVisual.Z[7]; float[] data = new float[80 * 80]; VisualDfs2Data(weights, data, z4, z6, z8, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z4, z6, z8, false); dfs2File.WriteItemTimeStepNext(0, data); // One delete value VisualDfs2Data(weights, data, d, z6, z8, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, z6, z8, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z4, d, z8, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z4, d, z8, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z4, z6, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z4, z6, d, false); dfs2File.WriteItemTimeStepNext(0, data); // Two adjacent delete values VisualDfs2Data(weights, data, d, d, z8, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, d, z8, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z4, d, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, z4, d, d, false); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, z6, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, z6, d, false); dfs2File.WriteItemTimeStepNext(0, data); // All delete values VisualDfs2Data(weights, data, d, d, d, true); dfs2File.WriteItemTimeStepNext(0, data); VisualDfs2Data(weights, data, d, d, d, false); dfs2File.WriteItemTimeStepNext(0, data); dfs2File.Close(); }
/// <summary> /// Create dfsu and mesh file from dfs2 file. /// <para> /// Note 1: Boundary code is set to land value at /// all boundaries of mesh and dfsu file. /// These must be updated to something "better" /// if to use as input in another simulation. /// </para> /// <para> /// Note 2: P and Q values are not rotated with the /// grid, but should be so, if used in the /// projected coordinate system. It must take /// the 327 degrees rotation into account. /// </para> /// </summary> /// <param name="dfs2Filename">Name of input dfs2 file, e.g. the OresundHD.dfs2</param> /// <param name="meshFilename">Name of output mesh file</param> /// <param name="dfsuFilename">Name of output dfsu file</param> public static void CreateDfsuFromDfs2(string dfs2Filename, string meshFilename, string dfsuFilename) { // Open file Dfs2File dfs2 = DfsFileFactory.Dfs2FileOpen(dfs2Filename); // Read bathymetry from first static item IDfsStaticItem bathymetryItem = dfs2.ReadStaticItemNext(); float[] bathymetry = (float[])bathymetryItem.Data; // Extract spatial axis IDfsAxisEqD2 spatialAxis = (IDfsAxisEqD2)dfs2.SpatialAxis; // Some convenience variables double dx = spatialAxis.Dx; double dy = spatialAxis.Dy; double x0 = spatialAxis.X0; double y0 = spatialAxis.Y0; int xCount = spatialAxis.XCount; int yCount = spatialAxis.YCount; // First custom block (index 0) contains the M21_MISC values, // where the 4th (index 3) is the land value float landValue = (float)dfs2.FileInfo.CustomBlocks[0][3]; //----------------------------------------- // Find out which elements in the dfs2 grid that is not a land value // and include all those elements and their surrounding nodes in mesh // Arrays indicating if element and node in grid is used or not in mesh bool[,] elmts = new bool[xCount, yCount]; int[,] nodes = new int[xCount + 1, yCount + 1]; // Loop over all elements in 2D grid for (int l = 0; l < yCount; l++) { for (int k = 0; k < xCount; k++) { // If bathymetry is not land value, use element. if (bathymetry[k + l * xCount] != landValue) { // element [l,k] is used, and also the 4 nodes around it elmts[k, l] = true; nodes[k, l] = 1; nodes[k + 1, l] = 1; nodes[k, l + 1] = 1; nodes[k + 1, l + 1] = 1; } } } //----------------------------------------- // Create new mest nodes // Cartography object can convert grid (x,y) to projection (east,north) IDfsProjection proj = dfs2.FileInfo.Projection; DHI.Projections.Cartography cart = new DHI.Projections.Cartography(proj.WKTString, proj.Longitude, proj.Latitude, proj.Orientation); // New mesh nodes List <double> X = new List <double>(); List <double> Y = new List <double>(); List <float> Zf = new List <float>(); // float values for dfsu file List <double> Zd = new List <double>(); // double values for mesh file List <int> Code = new List <int>(); // Loop over all nodes int nodesCount = 0; for (int l = 0; l < yCount + 1; l++) { for (int k = 0; k < xCount + 1; k++) { // Check if node is included in mesh if (nodes[k, l] > 0) { // Convert from mesh (x,y) to projection (east,north) double east, north; cart.Xy2Proj((k - 0.5) * dx + x0, (l - 0.5) * dy + y0, out east, out north); // Average Z on node from neighbouring grid cell values, cell value is used // unless they are outside grid or has land values double z = 0; int zCount = 0; if (k > 0 && l > 0 && bathymetry[k - 1 + (l - 1) * xCount] != landValue) { zCount++; z += bathymetry[k - 1 + (l - 1) * xCount]; } if (k < xCount && l > 0 && bathymetry[k + (l - 1) * xCount] != landValue) { zCount++; z += bathymetry[k + (l - 1) * xCount]; } if (k > 0 && l < yCount && bathymetry[k - 1 + (l) * xCount] != landValue) { zCount++; z += bathymetry[k - 1 + (l) * xCount]; } if (k < xCount && l < yCount && bathymetry[k + (l) * xCount] != landValue) { zCount++; z += bathymetry[k + (l) * xCount]; } if (zCount > 0) { z /= zCount; } else { z = landValue; } // Store new node number and add node nodesCount++; nodes[k, l] = nodesCount; // this is the node number to use in the element table X.Add(east); Y.Add(north); Zf.Add((float)z); Zd.Add(z); Code.Add(zCount == 4 ? 0 : 1); // Land boundary if zCount < 4 } } } // New mesh elements List <int[]> elmttable2 = new List <int[]>(); for (int l = 0; l < yCount; l++) { for (int k = 0; k < xCount; k++) { // Check if element is included in mesh if (elmts[k, l]) { // For this element, add the four surrounding nodes, // counter-clockwise order int[] newNodes = new int[4]; newNodes[0] = nodes[k, l]; newNodes[1] = nodes[k + 1, l]; newNodes[2] = nodes[k + 1, l + 1]; newNodes[3] = nodes[k, l + 1]; elmttable2.Add(newNodes); } } } //----------------------------------------- // Create mesh { // Create 2D dfsu file MeshBuilder builder = new MeshBuilder(); // Setup header and geometry builder.SetNodes(X.ToArray(), Y.ToArray(), Zd.ToArray(), Code.ToArray()); builder.SetElements(elmttable2.ToArray()); builder.SetProjection(dfs2.FileInfo.Projection); // Create new file MeshFile mesh = builder.CreateMesh(); mesh.Write(meshFilename); } //----------------------------------------- // Create dfsu file { // dfs2 time axis IDfsEqCalendarAxis timeAxis = (IDfsEqCalendarAxis)dfs2.FileInfo.TimeAxis; // Create 2D dfsu file DfsuBuilder builder = DfsuBuilder.Create(DfsuFileType.Dfsu2D); // Setup header and geometry builder.SetNodes(X.ToArray(), Y.ToArray(), Zf.ToArray(), Code.ToArray()); builder.SetElements(elmttable2.ToArray()); builder.SetProjection(dfs2.FileInfo.Projection); builder.SetTimeInfo(timeAxis.StartDateTime, timeAxis.TimeStepInSeconds()); builder.SetZUnit(eumUnit.eumUmeter); // Add dynamic items, copying from dfs2 file for (int i = 0; i < dfs2.ItemInfo.Count; i++) { IDfsSimpleDynamicItemInfo itemInfo = dfs2.ItemInfo[i]; builder.AddDynamicItem(itemInfo.Name, itemInfo.Quantity); } // Create new file DfsuFile dfsu = builder.CreateFile(dfsuFilename); // Add dfs2 data to dfsu file float[] dfsuData = new float[dfsu.NumberOfElements]; for (int i = 0; i < dfs2.FileInfo.TimeAxis.NumberOfTimeSteps; i++) { for (int j = 0; j < dfs2.ItemInfo.Count; j++) { // Read dfs2 grid data IDfsItemData2D <float> itemData = (IDfsItemData2D <float>)dfs2.ReadItemTimeStep(j + 1, i); // Extract 2D grid data to dfsu data array int lk = 0; for (int l = 0; l < yCount; l++) { for (int k = 0; k < xCount; k++) { if (elmts[k, l]) { dfsuData[lk++] = itemData[k, l]; } } } // write data dfsu.WriteItemTimeStepNext(itemData.Time, dfsuData); } } dfsu.Close(); } dfs2.Close(); }