public void InterpolateNodeTest() { string triMesh = UnitTestHelper.TestDataDir + "odense_rough.mesh"; string quadMesh = UnitTestHelper.TestDataDir + "odense_rough_quads.mesh"; // Source mesh MeshFile sourcemeshFile = MeshFile.ReadMesh(triMesh); SMeshData sourcemesh = sourcemeshFile.ToSMeshData(); sourcemesh.BuildDerivedData(); // Target mesh MeshFile targetMeshFile = MeshFile.ReadMesh(quadMesh); SMeshData targetmesh = targetMeshFile.ToSMeshData(); targetmesh.BuildDerivedData(); MeshInterpolator2D interpolator = new MeshInterpolator2D(sourcemesh, MeshValueType.Nodes); interpolator.SetTarget(targetmesh, MeshValueType.Nodes); double[] target = new double[targetmesh.NumberOfNodes]; interpolator.InterpolateNodeToTarget(sourcemesh.Z, target); Assert.False(target.Any(vv => vv == interpolator.DeleteValue)); targetMeshFile.Z = target; targetMeshFile.Write(UnitTestHelper.TestDataDir + "test_odense_rough_quads-fromTri.mesh"); }
/// <summary> /// Process the incoming mesh file names /// </summary> /// <param name="files">List of mesh file names to merge</param> /// <param name="fileBoundaryCodesToRemove">List of boundary codes to remove for each mesh. Must match the size of the files argument</param> public void Process(List <string> files, List <List <int> > fileBoundaryCodesToRemove = null) { // Extent of entire domain, all meshes Extent extent = new Extent(); // Load all meshes List <MeshFile> meshes = new List <MeshFile>(files.Count); for (int i = 0; i < files.Count; i++) { MeshFile mesh = MeshFile.ReadMesh(files[i]); meshes.Add(mesh); for (int j = 0; j < mesh.NumberOfNodes; j++) { extent.Include(mesh.X[j], mesh.Y[j]); } } // grow it a littl bit, in case of rounding errors extent.XMin = extent.XMin - NodeTolerance; extent.XMax = extent.XMax + NodeTolerance; extent.YMin = extent.YMin - NodeTolerance; extent.YMax = extent.YMax + NodeTolerance; // Initialize search tree _nodeSearchTree = new QuadSearchTree(extent); // Create new mesh nodes and elements for (int i = 0; i < files.Count; i++) { int prevNodeMergeCount = NodeMergeCount; List <int> boundaryCodesToRemove = fileBoundaryCodesToRemove != null ? fileBoundaryCodesToRemove[i] : null; AddMesh(meshes[i], boundaryCodesToRemove); if (i > 0) { Console.Out.WriteLine("Mesh {0}, number of nodes merged in: {1}", i + 1, NodeMergeCount - prevNodeMergeCount); } } Console.Out.WriteLine("Total number of nodes merged in : {0}", NodeMergeCount); RemoveInternalBoundaryCodes(_code, _connectivity); // Create new mesh file string projection = meshes[0].ProjectionString; eumQuantity eumQuantity = meshes[0].EumQuantity; MeshBuilder builder = new MeshBuilder(); builder.SetNodes(_x.ToArray(), _y.ToArray(), _z.ToArray(), _code.ToArray()); builder.SetElements(_connectivity.ToArray()); builder.SetProjection(projection); builder.SetEumQuantity(eumQuantity); MeshFile newMesh = builder.CreateMesh(); MeshValidator meshValidator = new MeshValidator(); meshValidator.ValidateMesh(newMesh.X, newMesh.Y, newMesh.Code, newMesh.ElementTable); foreach (string error in meshValidator.Errors) { Console.Out.WriteLine(error); } newMesh.Write(_newMeshFileName); //------------------------------------- // Do some statistics on the mesh: // collect number of face codes for each mesh SortedDictionary <int, int[]> bcCodesStats = new SortedDictionary <int, int[]>(); List <MeshValidator> validators = new List <MeshValidator>(); for (int meshIndex = 0; meshIndex < meshes.Count; meshIndex++) { MeshFile meshFile = meshes[meshIndex]; MeshValidator validator = new MeshValidator(); validator.ValidateMesh(meshFile.X, meshFile.Y, meshFile.Code, meshFile.ElementTable); validators.Add(validator); UpdateStatistics(meshes.Count + 1, meshIndex, bcCodesStats, validator.GetFaceCodeStatistics()); } UpdateStatistics(meshes.Count + 1, meshes.Count, bcCodesStats, meshValidator.GetFaceCodeStatistics()); Console.Out.Write("---------------------"); Console.Out.Write(" Statistics of faces "); Console.Out.Write("---------------------"); Console.Out.WriteLine(""); Console.Out.Write("FaceCode |"); for (int i = 0; i < meshes.Count; i++) { Console.Out.Write(" mesh {0,2} ", i + 1); } Console.Out.Write(" | total | new mesh"); Console.Out.WriteLine(""); int[] totals = new int[meshes.Count + 2]; foreach (KeyValuePair <int, int[]> keyValuePair in bcCodesStats) { Console.Out.Write(" {0,4} |", keyValuePair.Key); int total = 0; for (int index = 0; index < keyValuePair.Value.Length - 1; index++) { int meshCodeCount = keyValuePair.Value[index]; total += meshCodeCount; totals[index] += meshCodeCount; Console.Out.Write(" {0,7} ", meshCodeCount); } totals[meshes.Count] += total; totals[meshes.Count + 1] += keyValuePair.Value.Last(); Console.Out.Write(" |{0,7} | ", total); Console.Out.Write(" {0,7} ", keyValuePair.Value.Last()); Console.Out.WriteLine(""); } Console.Out.Write(" total |"); for (int index = 0; index < meshes.Count; index++) { Console.Out.Write(" {0,7} ", totals[index]); } Console.Out.Write(" |{0,7} | ", totals[meshes.Count]); Console.Out.Write(" {0,7} ", totals[meshes.Count + 1]); Console.Out.WriteLine(""); Console.Out.Write("---------------------"); Console.Out.Write("---------------------"); Console.Out.Write("---------------------"); Console.Out.WriteLine(""); }
/// <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(); }