Example #1
0
        /// <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();
        }
Example #2
0
        /// <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();
        }
Example #3
0
        /// <summary>
        /// Example on how to extract dfs0 data from a 2D dfsu file for certain elements. All items
        /// from dfsu file are extracted.
        /// </summary>
        /// <param name="dfsuFileNamePath">Name, including path, of 2D dfsu file</param>
        /// <param name="elmtsIndices">Indices of elements to extract data from</param>
        /// <param name="useStream">Use stream when writing dfs0 files - then more than 400 files can be created simultaneously</param>
        public static void ExtractDfs0FromDfsu(string dfsuFileNamePath, IList <int> elmtsIndices, bool useStream)
        {
            // If not using stream approach, at most 400 elements at a time can be processed.
            // There is a limit on how many files you can have open at the same time using
            // the standard approach. It will fail in a nasty way, if the maximum number of
            // file handles are exceeded. This is not an issue when using .NET streams.
            if (!useStream && elmtsIndices.Count > 400)
            {
                throw new ArgumentException("At most 400 elements at a time");
            }

            // Open source dfsu file
            IDfsuFile source;
            Stream    stream = null;

            if (useStream)
            {
                stream = new FileStream(dfsuFileNamePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                source = DfsuFile.Open(stream);
            }
            else
            {
                source = DfsuFile.Open(dfsuFileNamePath);
            }

            // Figure out "basic" dfs0 file name
            string dfsuFilename     = Path.GetFileNameWithoutExtension(dfsuFileNamePath);
            string path             = Path.GetDirectoryName(dfsuFileNamePath);
            string dfs0BaseFilename = Path.Combine(path, "test_" + dfsuFilename + "-");

            // Factory for creating dfs objects
            DfsFactory factory = new DfsFactory();

            // Create a dfs0 file for each element in elmtsIndices
            DfsFile[] dfs0Files   = new DfsFile[elmtsIndices.Count];
            Stream[]  dfs0Streams = new Stream [elmtsIndices.Count];
            double    timeSpan    = source.TimeStepInSeconds * source.NumberOfTimeSteps;

            for (int k = 0; k < elmtsIndices.Count; k++)
            {
                // Index of element to create dfs0 for
                int elmtsIndex = elmtsIndices[k];

                // Calculate element center coordinates, to be stored in dfs0 items.
                // Stored as float in dfs0, hence possible loss of precision...
                float x = 0, y = 0, z = 0;
                int[] nodeNumbers = source.ElementTable[elmtsIndex];
                for (int i = 0; i < nodeNumbers.Length; i++)
                {
                    int nodeIndex = nodeNumbers[i] - 1; // from number to index
                    x += (float)source.X[nodeIndex];
                    y += (float)source.Y[nodeIndex];
                    z += source.Z[nodeIndex];
                }
                x /= nodeNumbers.Length;
                y /= nodeNumbers.Length;
                z /= nodeNumbers.Length;

                // Start building dfs0 file header
                DfsBuilder builder = DfsBuilder.Create("fileTitle", "appTitle", 1);
                builder.SetDataType(1); // standard dfs0 value
                builder.SetGeographicalProjection(source.Projection);
                builder.SetTemporalAxis(factory.CreateTemporalEqCalendarAxis(eumUnit.eumUsec, source.StartDateTime, 0, source.TimeStepInSeconds));

                // Add all dynamic items from dfsu file to dfs0 file
                for (int j = 0; j < source.ItemInfo.Count; j++)
                {
                    IDfsSimpleDynamicItemInfo sourceItem  = source.ItemInfo[j];
                    DfsDynamicItemBuilder     itemBuilder = builder.CreateDynamicItemBuilder();
                    itemBuilder.Set(sourceItem.Name, sourceItem.Quantity, sourceItem.DataType);
                    itemBuilder.SetAxis(factory.CreateAxisEqD0());
                    itemBuilder.SetValueType(sourceItem.ValueType);
                    itemBuilder.SetReferenceCoordinates(x, y, z); // optional
                    builder.AddDynamicItem(itemBuilder.GetDynamicItemInfo());
                }


                // Create and get file, store them in dfs0s array
                string dfs0Filename = dfs0BaseFilename + (elmtsIndex).ToString("000000") + ".dfs0";
                if (useStream)
                {
                    // Create file using C# streams - necessary to provie number of time steps and timespan of data
                    builder.SetNumberOfTimeSteps(source.NumberOfTimeSteps);
                    builder.SetTimeInfo(0, timeSpan);
                    Stream dfs0FileStream = new FileStream(dfs0Filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
                    builder.CreateStream(dfs0FileStream);
                    dfs0Streams[k] = dfs0FileStream;
                }
                else
                {
                    // Create file in the ordinary way. Will include statistics (of delete values etc).
                    builder.CreateFile(dfs0Filename);
                }
                dfs0Files[k] = builder.GetFile();
            }

            // For performance, use predefined itemdata objects when reading data from dfsu
            IDfsItemData <float>[] dfsuItemDatas = new IDfsItemData <float> [source.ItemInfo.Count];
            for (int j = 0; j < source.ItemInfo.Count; j++)
            {
                dfsuItemDatas[j] = (IDfsItemData <float>)source.ItemInfo[j].CreateEmptyItemData();
            }

            // Read data from dfsu and store in dfs0
            float[] dfs0Data = new float[1];
            for (int i = 0; i < source.NumberOfTimeSteps; i++)
            {
                for (int j = 0; j < source.ItemInfo.Count; j++)
                {
                    // Read data from dfsu
                    IDfsItemData <float> dfsuItemData = dfsuItemDatas[j];
                    bool    ok     = source.ReadItemTimeStep(dfsuItemData, i);
                    float[] floats = dfsuItemData.Data;

                    // write data to dfs0's
                    for (int k = 0; k < elmtsIndices.Count; k++)
                    {
                        int elmtsIndex = elmtsIndices[k];
                        dfs0Data[0] = floats[elmtsIndex];
                        dfs0Files[k].WriteItemTimeStepNext(0, dfs0Data);
                    }
                }
            }

            // Close dfsu files
            source.Close();
            if (stream != null)
            {
                stream.Close();
            }
            // Close all dfs0 files
            for (int k = 0; k < elmtsIndices.Count; k++)
            {
                dfs0Files[k].Close();
                if (dfs0Streams[k] != null)
                {
                    dfs0Streams[k].Close();
                }
            }
        }