Пример #1
0
        /// <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();
        }
Пример #2
0
        /// <summary>
        /// Example of how to resample a dfs2 file in x/y space
        /// </summary>
        /// <param name="inputFilename">Path and name of the file to resample</param>
        /// <param name="outputFilename">Path and name of the new file to create</param>
        /// <param name="xCount">Number of cells in x-direction</param>
        /// <param name="yCount">Number of cells in y-direction</param>
        public static void Resample(string inputFilename, string outputFilename, int xCount, int yCount)
        {
            // Load dfs2 file
            Dfs2File     dfs2File = DfsFileFactory.Dfs2FileOpen(inputFilename);
            IDfsAxisEqD2 axis     = (IDfsAxisEqD2)dfs2File.SpatialAxis;

            // Create reprojector
            Dfs2Reprojector reproj = new Dfs2Reprojector(dfs2File, outputFilename);

            // scale change
            double dxScale = (double)axis.XCount / xCount;
            double dyScale = (double)axis.YCount / yCount;

            // Calculate new lon/lat origin - center of lower left cell
            Cartography cart = new Cartography(dfs2File.FileInfo.Projection.WKTString, dfs2File.FileInfo.Projection.Longitude, dfs2File.FileInfo.Projection.Latitude, dfs2File.FileInfo.Projection.Orientation);
            // Change in center of lower left cell
            double dxOrigin = 0.5 * axis.Dx * (dxScale - 1);
            double dyOrigin = 0.5 * axis.Dy * (dyScale - 1);

            cart.Xy2Geo(dxOrigin, dyOrigin, out double lonOrigin, out double latOrigin);

            // Set new target
            reproj.SetTarget(dfs2File.FileInfo.Projection.WKTString, lonOrigin, latOrigin, dfs2File.FileInfo.Projection.Orientation, xCount, 0, axis.Dx * dxScale, yCount, 0, axis.Dy * dyScale);
            reproj.Interpolate = true;
            // Create new file
            reproj.Process();
        }
Пример #3
0
        /// <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();
        }
Пример #4
0
        static void Main(string[] args)
        {
            string filename = @"..\..\TestData\OresundHD.dfs2";

            // Load the file
            Dfs2File dfs2File = DfsFileFactory.Dfs2FileOpen(filename);

            // Print out some info on the spatial axis
            IDfsAxisEqD2 axis = (IDfsAxisEqD2)dfs2File.SpatialAxis;

            Console.Out.WriteLine("Size of grid    : {0} x {1}", axis.XCount, axis.YCount);
            Console.Out.WriteLine("Projection      : " + dfs2File.FileInfo.Projection.WKTString);

            // Print out some info of the first item
            IDfsSimpleDynamicItemInfo dynamicItemInfo = dfs2File.ItemInfo[0];

            Console.Out.WriteLine("Item 1 name     : " + dynamicItemInfo.Name);
            Console.Out.WriteLine("Item 1 datatype : " + dynamicItemInfo.DataType);

            // This iterates through the first 5 time steps and print out the value in the grid
            // at index (3,4) for the first item
            for (int i = 0; i < 5; i++)
            {
                IDfsItemData2D <float> data2D = (IDfsItemData2D <float>)dfs2File.ReadItemTimeStep(1, i);
                float value = data2D[3, 4];
                Console.Out.WriteLine("Value in time step {0} = {1}", i, value);
            }
        }
Пример #5
0
        /// <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();
        }
Пример #6
0
        /// <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();
        }
Пример #7
0
        /// <summary>
        /// Introductory example of how to load a dfs2 file.
        /// <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 ReadingDfs2File(string filename)
        {
            // Open the file as a dfs2 file
            Dfs2File dfs2File = DfsFileFactory.Dfs2FileOpen(filename);

            // Spatial axis for this file is a 2D equidistant axis
            IDfsAxisEqD2 axisEqD2 = ((IDfsAxisEqD2)dfs2File.SpatialAxis);
            double       dx       = axisEqD2.Dx;                         // 900
            double       dy       = axisEqD2.Dy;                         // 900

            // Header information is contained in the IDfsFileInfo
            IDfsFileInfo fileInfo         = dfs2File.FileInfo;
            int          steps            = fileInfo.TimeAxis.NumberOfTimeSteps; // 13
            string       projectionString = fileInfo.Projection.WKTString;       // "UTM-33"

            // Information on each of the dynamic items, here the first one
            IDfsSimpleDynamicItemInfo dynamicItemInfo = dfs2File.ItemInfo[0];
            string        nameOfFirstDynamicItem      = dynamicItemInfo.Name;     // "H Water Depth m"
            DfsSimpleType typeOfFirstDynamicItem      = dynamicItemInfo.DataType; // Float

            // Read data of first item, third time step (items start by 1, timesteps by 0),
            // assuming data is of type float.
            IDfsItemData2D <float> data2D = (IDfsItemData2D <float>)dfs2File.ReadItemTimeStep(1, 2);
            // Get the value at (i,j) = (3,4) of the item and timestep
            float value = data2D[3, 4];                                  // 11.3634329

            // This iterates through all the timesteps and items in the file
            // For performance reasons it is important to iterate over time steps
            // first and items second.
            for (int i = 0; i < steps; i++)
            {
                for (int j = 1; j <= dfs2File.ItemInfo.Count; j++)
                {
                    data2D = (IDfsItemData2D <float>)dfs2File.ReadItemTimeStep(j, i);
                    value  = data2D[3, 4];
                }
            }
        }
Пример #8
0
        /// <summary>
        /// dfs2 reader. Gets information from the dfs file, and reads data.
        /// </summary>
        /// <param name="dfsfile">full path string to dfs2 file.</param>
        public DFS2Reader(string dfsfile)
        {
            throw new NotImplementedException("ToDo dfs2");

            // Open the file as a generic dfs file
            _dfs2File = DfsFileFactory.Dfs2FileOpen(dfsfile);

            // Header information is contained in the IDfsFileInfo
            IDfsFileInfo fileInfo = _dfs2File.FileInfo;

            // Check for dfs compliance
            CheckDFSCompliance();

            // Number of time steps (same for all items)
            _numTimeSteps = fileInfo.TimeAxis.NumberOfTimeSteps;

            // Number of variable items in dfs2
            _numItems = _dfs2File.ItemInfo.Count;

            // Add the IDs to list (Keys)
            _itemIDs = new List <string>();
            foreach (var itemInfo in _dfs2File.ItemInfo)
            {
                _itemIDs.Add(itemInfo.Name);
            }

            _times = _dfs2File.FileInfo.TimeAxis.GetDateTimes().ToList();

            // Delelte Values
            _deleteValueDouble = _dfs2File.FileInfo.DeleteValueDouble;
            _deleteValueFloat  = _dfs2File.FileInfo.DeleteValueFloat;

            _xyLayerPoints = new List <IXYLayerPoint>();
            foreach (var itemInfo in _dfs2File.ItemInfo)
            {
                throw new NotImplementedException("ToDo dfs2");
            }
        }
Пример #9
0
        /// <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();
        }
Пример #10
0
        /// <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();
        }
Пример #11
0
        /// <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();
        }
Пример #12
0
        /// <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();
        }
Пример #13
0
        /// <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();
        }
Пример #14
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();
        }