/// <summary> /// Introductory example of how to load a dfsu file. /// <para> /// The method assumes that the OresundHD.dfsu test file /// is the input file. /// </para> /// </summary> /// <param name="filename">path and name of OresundHD.dfsu test file</param> public static void ReadingDfsuFile(string filename) { IDfsuFile file = DfsuFile.Open(filename); // Read geometry int numberOfElements = file.NumberOfElements; // 3636 int numberOfNodes = file.NumberOfNodes; // 2057 double firstNodeXCoordinate = file.X[0]; // 359978.8 int[] firstElementNodes = file.ElementTable[0]; // [1, 2, 3] // Read dynamic item info string firstItemName = file.ItemInfo[0].Name; // "Surface elevation" eumQuantity quantity = file.ItemInfo[0].Quantity; // eumISurfaceElevation in eumUmeter // load data for the first item, 6th timestep float[] itemTimeStepData = (float[])file.ReadItemTimeStep(1, 5).Data; // Read the value of the third element float thirdElementValue = itemTimeStepData[2]; // 0.0014070312 file.Close(); }
/// <summary> /// Example of how to create a Dfsu file from scratch. This method /// creates a copy of the OresundHD.dfsu test file. /// <para> /// Data for static and dynamic item is taken from a source dfs file, /// which here is the OresundHD.dfsu test file. The data could come /// from any other source. /// </para> /// </summary> /// <param name="sourceFilename">Path and name of the OresundHD.dfsu test file</param> /// <param name="filename">Path and name of the new file to create</param> /// <param name="zInMeters">Flag specifying whether the z values are in meters or feet </param> public static void CreateDfsuFile(string sourceFilename, string filename, bool zInMeters) { IDfsuFile source = DfsuFile.Open(sourceFilename); DfsuBuilder builder = DfsuBuilder.Create(DfsuFileType.Dfsu2D); // Setup header and geometry, copy from source file builder.SetNodes(source.X, source.Y, source.Z, source.Code); builder.SetElements(source.ElementTable); builder.SetProjection(source.Projection); builder.SetTimeInfo(source.StartDateTime, source.TimeStepInSeconds); if (zInMeters) { builder.SetZUnit(eumUnit.eumUmeter); } else { builder.SetZUnit(eumUnit.eumUfeet); } // Add dynamic items, copying from source foreach (DfsuDynamicItemInfo itemInfo in source.ItemInfo) { builder.AddDynamicItem(itemInfo.Name, itemInfo.Quantity); } DfsuFile file = builder.CreateFile(filename); // Add data for all item-timesteps, copying from source IDfsItemData sourceData; while (null != (sourceData = source.ReadItemTimeStepNext())) { file.WriteItemTimeStepNext(sourceData.Time, sourceData.Data); } source.Close(); file.Close(); }
/// <summary> /// Example of how to modify the geometry of a dfsu file. /// The method will rotate the geometry by 125 degrees. /// <para> /// The method will work on any dfsu file. The OresundHD.dfsu test file /// (preferably a copy of it) can be used as input file. /// </para> /// </summary> /// <param name="filename">Path and name of a dfsu file</param> public static void ModifyDfsuFileGeometry(string filename) { // Open file for editing IDfsuFile dfsuFile = DfsuFile.OpenEdit(filename); dfsuFile.TimeStepInSeconds /= 2; dfsuFile.StartDateTime = new DateTime(2019, 6, 27, 13, 50, 30); // Make a rotation matrix double rotation = 125.0 / 180.0 * System.Math.PI; double x1 = System.Math.Cos(rotation); double y1 = -System.Math.Sin(rotation); double x2 = System.Math.Sin(rotation); double y2 = System.Math.Cos(rotation); // Get the x- and y-coordinates from the file double[] x = dfsuFile.X; double[] y = dfsuFile.Y; // Point to rotate around double x0 = x[0]; double y0 = y[0]; // Rotate coordinates for (int i = 0; i < dfsuFile.NumberOfNodes; i++) { double xx = x[i] - x0; double yy = y[i] - y0; x[i] = x1 * xx + y1 * yy + x0; y[i] = x2 * xx + y2 * yy + y0; } // Set the x- and y-coordinates back to the file dfsuFile.X = x; dfsuFile.Y = y; // Close the file dfsuFile.Close(); }
private void ComputeHmax(string filename) { btStart.Enabled = false; //Disable the Start button, to prevent user from running the tool twice at the same time btClose.Enabled = false; //Disable the Close button, to prevent user from closing the tool while running //Read input file and find relevant items IDfsuFile InputFile = DfsuFile.Open(filename); //Open the file int ItemNb = InputFile.ItemInfo.Count; //Number of items in the file int ItemNbH = -1; //Stores the item number for water depth. Initialised with a temporary value. int ItemNbU = -1; //Stores the item number for U velocity. Initialised with a temporary value. int ItemNbV = -1; //Stores the item number for V velocity. Initialised with a temporary value. for (int i = 0; i < ItemNb; i++) //Loop finding appropriate items H, U and V { if (InputFile.ItemInfo[i].Name == "Total water depth") { ItemNbH = i; //Save the actual item number when Total water depth is found } if (InputFile.ItemInfo[i].Name == "U velocity") { ItemNbU = i; //Save the actual item number when U velocity is found } if (InputFile.ItemInfo[i].Name == "V velocity") { ItemNbV = i; //Save the actual item number when V velocity is found } } if (ItemNbH == -1 || ItemNbU == -1 || ItemNbV == -1) //If one of the required item cannot be found { btClose.Enabled = true; //Enable the Close button again throw new Exception("The result file doesn't contain the necessary items H, U and V"); //Throw error message } else { //Create output file, with same nodes, elements, projection and time info as the input file, but with different output items DfsuBuilder OutputBuilder = DfsuBuilder.Create(DfsuFileType.Dfsu2D); OutputBuilder.SetNodes(InputFile.X, InputFile.Y, InputFile.Z, InputFile.Code); OutputBuilder.SetElements(InputFile.ElementTable); OutputBuilder.SetProjection(InputFile.Projection); OutputBuilder.SetTimeInfo(InputFile.StartDateTime, InputFile.TimeStepInSeconds); OutputBuilder.SetZUnit(InputFile.ZUnit); OutputBuilder.AddDynamicItem("Maximum water depth", InputFile.ItemInfo[ItemNbH].Quantity); //Create item H OutputBuilder.AddDynamicItem("U velocity @ max. depth", InputFile.ItemInfo[ItemNbU].Quantity); //Create item U OutputBuilder.AddDynamicItem("V velocity @ max. depth", InputFile.ItemInfo[ItemNbV].Quantity); //Create item V OutputBuilder.AddDynamicItem("Current speed @ max. depth", InputFile.ItemInfo[ItemNbU].Quantity); //Create item Speed OutputBuilder.AddDynamicItem("Current direction @ max. depth", eumQuantity.Create(eumItem.eumICurrentDirection, eumUnit.eumUradian)); //Create item Direction. Note: eumQuantity requires "using DHI.Generic.MikeZero" //Initialization of all output variables. Both source data and output data are intialized with data from first time step of the input file. float[] SourceDataH = (float[])InputFile.ReadItemTimeStep(ItemNbH + 1, 0).Data; //ReadItemTimeStep is 1-based! That is, the first time step must be numbered 1, whereas the first time step in the file is numbered 0, hence the +1. float[] SourceDataU = (float[])InputFile.ReadItemTimeStep(ItemNbU + 1, 0).Data; float[] SourceDataV = (float[])InputFile.ReadItemTimeStep(ItemNbV + 1, 0).Data; float[] OutputDataH = (float[])InputFile.ReadItemTimeStep(ItemNbH + 1, 0).Data; float[] OutputDataU = (float[])InputFile.ReadItemTimeStep(ItemNbU + 1, 0).Data; float[] OutputDataV = (float[])InputFile.ReadItemTimeStep(ItemNbV + 1, 0).Data; float[] OutputDataSpeed = (float[])InputFile.ReadItemTimeStep(ItemNbU + 1, 0).Data; //Initialise speed with values of U at time step 0 float[] OutputDataDir = (float[])InputFile.ReadItemTimeStep(ItemNbU + 1, 0).Data; //Initialise direction with values of U at time step 0 for (int m = 0; m < InputFile.NumberOfElements; m++) //Change speed and direction at first time step based on U and V values, with a loop over each element { OutputDataSpeed[m] = (float)Math.Sqrt(Math.Pow(SourceDataU[m], 2) + Math.Pow(SourceDataV[m], 2)); OutputDataDir[m] = (float)Math.Atan2(SourceDataU[m], SourceDataV[m]); } //Define the properties of the progress bar progressBar1.Maximum = InputFile.NumberOfTimeSteps - 1; progressBar1.Step = 1; //Loop over all time steps to get results for maxH (starting from 2nd time step) for (int j = 1; j < InputFile.NumberOfTimeSteps; j++) { SourceDataH = (float[])InputFile.ReadItemTimeStep(ItemNbH + 1, j).Data; //Load the new time step H data into the SourceDataH array. ReadItemTimeStep is 1-based! SourceDataU = (float[])InputFile.ReadItemTimeStep(ItemNbU + 1, j).Data; //Load the new time step U data into the SourceDataU array. ReadItemTimeStep is 1-based! SourceDataV = (float[])InputFile.ReadItemTimeStep(ItemNbV + 1, j).Data; //Load the new time step V data into the SourceDataV array. ReadItemTimeStep is 1-based! for (int k = 0; k < InputFile.NumberOfElements; k++) //Loop over all elements { if (SourceDataH[k] > OutputDataH[k]) //If the water depth for the new time step is higher than the previous maximum depth, then store the corresponding U, V, speed and direction values { OutputDataH[k] = SourceDataH[k]; OutputDataU[k] = SourceDataU[k]; OutputDataV[k] = SourceDataV[k]; OutputDataSpeed[k] = (float)Math.Sqrt(Math.Pow(SourceDataU[k], 2) + Math.Pow(SourceDataV[k], 2)); OutputDataDir[k] = (float)Math.Atan2(SourceDataU[k], SourceDataV[k]); } } progressBar1.PerformStep(); //Increment progress bar } // Write results string folder = Path.GetDirectoryName(txtPath.Text); string FileRoot = Path.GetFileNameWithoutExtension(txtPath.Text); string FileNameOut = folder + "\\" + FileRoot + "_Statistics_Hmax.dfsu"; //Add suffix to input file name, to be used for output file DfsuFile OutputFile = OutputBuilder.CreateFile(FileNameOut); //Create output file OutputFile.WriteItemTimeStepNext(0, OutputDataH); //Write H data. Time set to 0 : ignored since equidistant interval OutputFile.WriteItemTimeStepNext(0, OutputDataU); //Write U data OutputFile.WriteItemTimeStepNext(0, OutputDataV); //Write V data OutputFile.WriteItemTimeStepNext(0, OutputDataSpeed); //Write speed data OutputFile.WriteItemTimeStepNext(0, OutputDataDir); //Write direction data InputFile.Close(); //Release the input file OutputFile.Close(); //Release the output file MessageBox.Show("File created"); //Confirm that the file has been created progressBar1.Value = 0; //Reset the progress bar btStart.Enabled = true; //Enable the Start button again btClose.Enabled = true; //Enable the Close button again } }
/// <summary> /// Find element (index) for a specified coordinate /// <para> /// The method assumes that the OresundHD.dfsu test file /// is the input file. /// </para> /// </summary> /// <param name="filename">path and name of OresundHD.dfsu test file</param> public static void FindElementForCoordinate(string filename) { IDfsuFile file = DfsuFile.Open(filename); double[] X = file.X; double[] Y = file.Y; // Coordinate to search for double xc = 346381; double yc = 6153637; // Loop over all elements - linear search, which may be slow! // If to find element for a large number of coordinates and if especially the // file has many elements, then a search tree procedure should be used to // optimize the searching performance. int elmt = -1; // result of search for (int i = 0; i < file.NumberOfElements; i++) { // Take out nodes for element int[] nodes = file.ElementTable[i]; // Loop over all faces in element. The coordinate (x,y) is // inside an element if the coordinate is "left of" all faces, // when travelling faces counter-clockwise bool isInside = true; for (int j = 0; j < nodes.Length; j++) { // face start/end node indices int a = nodes[j] - 1; int b = nodes[(j + 1) % nodes.Length] - 1; // Assuming face is A->B and coordinate is C, then "left of" test: // (B-A) X (C-A) > 0 // where X is the cross product double cross = (X[b] - X[a]) * (yc - Y[a]) - (Y[b] - Y[a]) * (xc - X[a]); if (cross < 0) { // (xc, yc) is "right of", hence not inside, skip to next element isInside = false; break; } } if (isInside) { // All "left of" tests succeded, element found! elmt = i; break; } } if (elmt >= 0) { Console.Out.WriteLine("Found element index: = {0}", elmt); Console.Out.WriteLine("(xc,yc) = ({0},{1})", xc, yc); int[] resNodes = file.ElementTable[elmt]; for (int j = 0; j < resNodes.Length; j++) { int node = resNodes[j] - 1; Console.Out.WriteLine("(x,y) = ({0},{1})", X[node], Y[node]); } } file.Close(); }
/// <summary> /// Extract a single layer from a 3D dfsu file, and write it to a 2D dfsu file. /// <para> /// If a layer value does not exist for a certain 2D element, delete value is written /// to the 2D resut file. This is relevant for Sigma-Z type of files. /// </para> /// </summary> /// <param name="filenameDfsu3">Name of 3D dfsu source file</param> /// <param name="filenameDfsu2">Name of 2D dfsu result file</param> /// <param name="layerNumber">Layer to extract. /// <para> /// Positive values count from bottom up i.e. 1 is bottom layer, 2 is second layer from bottom etc. /// </para> /// <para> /// Negative values count from top down, i.e. -1 is toplayer, -2 is second layer from top etc. /// </para> /// </param> public static void ExtractDfsu2DLayerFrom3D(string filenameDfsu3, string filenameDfsu2, int layerNumber) { IDfsuFile dfsu3File = DfsFileFactory.DfsuFileOpen(filenameDfsu3); // Check that dfsu3 file is a 3D dfsu file. switch (dfsu3File.DfsuFileType) { case DfsuFileType.Dfsu2D: case DfsuFileType.DfsuVerticalColumn: case DfsuFileType.DfsuVerticalProfileSigma: case DfsuFileType.DfsuVerticalProfileSigmaZ: throw new InvalidOperationException("Input file is not a 3D dfsu file"); } // Calculate offset from toplayer element. Offset is between 0 (top layer) and // dfsu3File.NumberOfLayers-1 (bottom layer) int topLayerOffset; if (layerNumber > 0 && layerNumber <= dfsu3File.NumberOfLayers) { topLayerOffset = dfsu3File.NumberOfLayers - layerNumber; } else if (layerNumber < 0 && -layerNumber <= dfsu3File.NumberOfLayers) { topLayerOffset = -layerNumber - 1; } else { throw new ArgumentException("Layer number is out of range"); } double[] xv = dfsu3File.X; double[] yv = dfsu3File.Y; float[] zv = dfsu3File.Z; int[] cv = dfsu3File.Code; // -------------------------------------------------- // Create 2D mesh from 3D mesh // List of new 2D nodes int node2DCount = 0; List <double> xv2 = new List <double>(); List <double> yv2 = new List <double>(); List <float> zv2 = new List <float>(); List <int> cv2 = new List <int>(); // Renumbering array, from 3D node numbers to 2D node numbers // i.e. if a 3D element refers to node number k, the 2D element node number is renumber[k] int[] renumber = new int[dfsu3File.NumberOfNodes]; // Coordinates of last created node double xr2 = -1e-10; double yr2 = -1e-10; // Create 2D nodes, by skipping nodes with equal x,y coordinates for (int i = 0; i < dfsu3File.NumberOfNodes; i++) { // If 3D x,y coordinates are equal to the last created 2D node, // map this node to the last created 2D node, otherwise // create new 2D node and map to that one if (xv[i] != xr2 || yv[i] != yr2) { // Create new node node2DCount++; xr2 = xv[i]; yr2 = yv[i]; float zr2 = zv[i]; int cr2 = cv[i]; xv2.Add(xr2); yv2.Add(yr2); zv2.Add(zr2); cv2.Add(cr2); } // Map this 3D node to the last created 2D node. renumber[i] = node2DCount; } // Find indices of top layer elements IList <int> topLayer = dfsu3File.FindTopLayerElements(); // Create element table for 2D dfsu file int[][] elmttable2 = new int[topLayer.Count][]; for (int i = 0; i < topLayer.Count; i++) { // 3D element nodes int[] elmt3 = dfsu3File.ElementTable[topLayer[i]]; // 2D element nodes, only half as big, so copy over the first half int[] elmt2 = new int[elmt3.Length / 2]; for (int j = 0; j < elmt2.Length; j++) { elmt2[j] = renumber[elmt3[j]]; } elmttable2[i] = elmt2; } // -------------------------------------------------- // Create 2D dfsu file DfsuBuilder builder = DfsuBuilder.Create(DfsuFileType.Dfsu2D); // Setup header and geometry builder.SetNodes(xv2.ToArray(), yv2.ToArray(), zv2.ToArray(), cv2.ToArray()); builder.SetElements(elmttable2); builder.SetProjection(dfsu3File.Projection); builder.SetTimeInfo(dfsu3File.StartDateTime, dfsu3File.TimeStepInSeconds); if (dfsu3File.ZUnit == eumUnit.eumUUnitUndefined) { builder.SetZUnit(eumUnit.eumUmeter); } else { builder.SetZUnit(dfsu3File.ZUnit); } // Add dynamic items, copying from source, though not the first one, if it // contains the z-variation on the nodes for (int i = 0; i < dfsu3File.ItemInfo.Count; i++) { IDfsSimpleDynamicItemInfo itemInfo = dfsu3File.ItemInfo[i]; if (itemInfo.ElementCount == dfsu3File.NumberOfElements) { builder.AddDynamicItem(itemInfo.Name, itemInfo.Quantity); } } // Create file DfsuFile dfsu2File = builder.CreateFile(filenameDfsu2); // -------------------------------------------------- // Process data // Check if the layer number exists for 2D element, i.e. if that element // in 2D has that number of columnes in the 3D (relevant for sigma-z files) // If elementExists[i] is false, write delete value to file bool[] elementExists = new bool[topLayer.Count]; int numLayersInColumn = topLayer[0] + 1; elementExists[0] = (numLayersInColumn - topLayerOffset) > 0; for (int i = 1; i < topLayer.Count; i++) { numLayersInColumn = (topLayer[i] - topLayer[i - 1]); elementExists[i] = (numLayersInColumn - topLayerOffset) > 0; } // For performance, use predefined itemdata objects when reading data from dfsu 3D file IDfsItemData <float>[] dfsu3ItemDatas = new IDfsItemData <float> [dfsu3File.ItemInfo.Count]; for (int j = 0; j < dfsu3File.ItemInfo.Count; j++) { dfsu3ItemDatas[j] = (IDfsItemData <float>)dfsu3File.ItemInfo[j].CreateEmptyItemData(); } // Float data to write to dfsu 2D file float[] data2 = new float[dfsu2File.NumberOfElements]; float deleteValueFloat = dfsu2File.DeleteValueFloat; for (int i = 0; i < dfsu3File.NumberOfTimeSteps; i++) { for (int j = 0; j < dfsu3File.ItemInfo.Count; j++) { // Read data from 3D dfsu IDfsItemData <float> data3Item = dfsu3ItemDatas[j]; bool ok = dfsu3File.ReadItemTimeStep(data3Item, i); // 3D data float[] data3 = data3Item.Data; // Skip any items not having size = NumberOfElments (the z-variation on the nodes) if (data3.Length != dfsu3File.NumberOfElements) { continue; } // Loop over all 2D elements for (int k = 0; k < topLayer.Count; k++) { // Extract layer data from 3D column into 2D element value if (elementExists[k]) { data2[k] = data3[topLayer[k] - topLayerOffset]; } else { data2[k] = deleteValueFloat; } } dfsu2File.WriteItemTimeStepNext(data3Item.Time, data2); } } dfsu3File.Close(); dfsu2File.Close(); }