public static ScalarField FromAnalyticalField(AnalyticalField func, Index size, Vector origin, Vector cellSize) { Debug.Assert(size.Length == origin.Length && size.Length == cellSize.Length); RectlinearGrid grid = new RectlinearGrid(size); ScalarField field = new ScalarField(grid); for (int idx = 0; idx < size.Product(); ++idx) { // Compute the n-dimensional position. int index = idx; Index pos = new Index(0, size.Length); pos[0] = index % size[0]; for (int dim = 1; dim < size.Length; ++dim) { index -= pos[dim - 1]; index /= size[dim - 1]; pos[dim] = index % size[dim]; } Vector posV = origin + pos * cellSize; field[idx] = func(posV); } return(field); }
/// <summary> /// Append a time dimension. /// </summary> /// <param name="numTimeSlices"></param> /// <param name="timeStart"></param> /// <param name="timeStep"></param> /// <returns></returns> public override FieldGrid GetAsTimeGrid(int numTimeSlices, float timeStart, float timeStep) { Index timeSize = new Index(Size.Length + 1); Array.Copy(Size.Data, timeSize.Data, Size.Length); timeSize[Size.Length] = numTimeSlices; Vector origin = Origin.ToVec(Origin.Length + 1); RectlinearGrid timeGrid = new RectlinearGrid(timeSize, origin, timeStart); //_timeDependent = true; //TimeOrigin = timeStart; return(timeGrid); }
public static void TestCP() { Random rnd = new Random(DateTime.Today.Millisecond); RectlinearGrid grid = new RectlinearGrid(new Index(2, 2)); ScalarField cell0 = new ScalarField(grid); ScalarField cell1 = new ScalarField(grid); for (int tests = 0; tests < 100; ++tests) { for (int i = 0; i < 4; ++i) { cell0.Data[i] = (float)rnd.NextDouble() - 0.5f; cell1.Data[i] = (float)rnd.NextDouble() - 0.5f; } VectorField cell = new VectorField(new ScalarField[] { cell0, cell1 }); //PointSet<Point> points = FieldAnalysis.ComputeCriticalPointsRegularAnalytical2D(cell); } }
public override VectorField GetSlicePlanarVelocity(int timeSlice) { ScalarField[] slices = new ScalarField[Size.Length - 1]; // Copy the grid - one dimension smaller! RectlinearGrid grid = Grid as RectlinearGrid; Index newSize = new Index(Size.Length - 1); Array.Copy(Size.Data, newSize.Data, newSize.Length); FieldGrid sliceGrid = new RectlinearGrid(newSize); for (int i = 0; i < Size.Length - 1; ++i) { slices[i] = this._scalarsUnsteady[i].GetTimeSlice(timeSlice); slices[i].TimeOrigin = timeSlice; } return(new VectorField(slices)); }
public virtual VectorField GetSlicePlanarVelocity(int posInLastDimension) { ScalarField[] slices = new ScalarField[Size.Length - 1]; // Copy the grid - one dimension smaller! RectlinearGrid grid = Grid as RectlinearGrid; Index newSize = new Index(Size.Length - 1); Array.Copy(Size.Data, newSize.Data, newSize.Length); FieldGrid sliceGrid = new RectlinearGrid(newSize); for (int i = 0; i < Size.Length - 1; ++i) { slices[i] = new ScalarField(sliceGrid); Array.Copy(((ScalarField)this.Scalars[i]).Data, newSize.Product() * posInLastDimension, slices[i].Data, 0, newSize.Product()); slices[i].TimeOrigin = posInLastDimension; } return(new VectorField(slices)); }
public override VectorField GetSlicePlanarVelocity(int timeSlice) { ScalarField[] slices = new ScalarField[Size.Length - 1]; // Copy the grid - one dimension smaller! RectlinearGrid grid = Grid as RectlinearGrid; Index newSize = new Index(Size.Length - 1); Array.Copy(Size.Data, newSize.Data, newSize.Length); FieldGrid sliceGrid = new RectlinearGrid(newSize); for (int i = 0; i < Size.Length - 1; ++i) { slices[i] = this._scalarsUnsteady[i].GetTimeSlice(timeSlice); slices[i].TimeOrigin = timeSlice; } return new VectorField(slices); }
/// <summary> /// Load a slice from the file. /// </summary> /// <param name="slice">Carries variable to load, dimensions in file and what to load.</param> /// <returns></returns> public override ScalarField LoadFieldSlice(SliceRange slice) { ScalarField field; Index offsets = new Index(slice.GetOffsets()); NetCDF.ResultCode ncState = NetCDF.ResultCode.NC_NOERR; //int[] sizeInFile = new int[offsets.Length]; int[] sizeInFile = slice.GetLengths(); // Probably has less dimensions. int[] sizeField = new int[offsets.Length]; int numDimsField = 0; //int currDimSlice = 0; for (int dim = 0; dim < offsets.Length; ++dim) { if (offsets[dim] != -1 && sizeInFile[dim] > 1) { sizeField[numDimsField++] = sizeInFile[dim]; } // Include whole dimension. else if (offsets[dim] == -1) { // Fill size. int sizeDim; ncState = NetCDF.nc_inq_dimlen(_fileID, slice.GetDimensionID(dim), out sizeDim); Debug.Assert(ncState == NetCDF.ResultCode.NC_NOERR); sizeInFile[dim] = sizeDim; // Set offset to one. offset = 0, size = size of dimension. offsets[dim] = 0; // Save size in size-vector for the scalar field. sizeField[numDimsField++] = sizeDim; } } //if (slice.IsTimeDependent()) // numDimsField++; // Generate size index for field class. Index fieldSize = new Index(numDimsField); Array.Copy(sizeField, fieldSize.Data, numDimsField); // When the field has several time slices, add a time dimension. //if (slice.IsTimeDependent()) // fieldSize[numDimsField - 1] = slice.GetNumTimeSlices(); // Change order of dimensions, so that fastest dimension is at the end. for (int dim = 0; dim < fieldSize.Length / 2; ++dim) { int tmp = fieldSize[dim]; fieldSize[dim] = fieldSize[fieldSize.Length - 1 - dim]; fieldSize[fieldSize.Length - 1 - dim] = tmp; } // Create a grid descriptor for the field. // TODO: Actually load this data. RectlinearGrid grid = new RectlinearGrid(fieldSize);//, new Vector(0.0f, fieldSize.Length), new Vector(0.1f, fieldSize.Length)); // Create scalar field instance and fill it with data. field = new ScalarField(grid); int sliceSize = grid.Size.Product();// / slice.GetNumTimeSlices(); // Get data. x64 dll fails in debug here... ncState = NetCDF.nc_get_vara_float(_fileID, (int)slice.GetVariable(), offsets.Data, sizeInFile, field.Data); Debug.Assert(ncState == NetCDF.ResultCode.NC_NOERR, ncState.ToString()); // Read in invalid value. float[] invalidval = new float[1]; ncState = NetCDF.nc_get_att_float(_fileID, (int)slice.GetVariable(), "_FillValue", invalidval); field.InvalidValue = invalidval[0]; return(field); }
/// <summary> /// Append a time dimension. /// </summary> /// <param name="numTimeSlices"></param> /// <param name="timeStart"></param> /// <param name="timeStep"></param> /// <returns></returns> public override FieldGrid GetAsTimeGrid(int numTimeSlices, float timeStart, float timeStep) { Index timeSize = new Index(Size.Length + 1); Array.Copy(Size.Data, timeSize.Data, Size.Length); timeSize[Size.Length] = numTimeSlices; Vector origin = Origin.ToVec(Origin.Length + 1); RectlinearGrid timeGrid = new RectlinearGrid(timeSize, origin, timeStart); //_timeDependent = true; //TimeOrigin = timeStart; return timeGrid; }
protected FieldPlane LoadPlane(int member, int time, out RectlinearGrid grid, int subtime = 0) { var result = LoadPlaneAndGrid(member, time, subtime); grid = result.Item2; return result.Item1; }
private FieldPlane LoadPlane(int member, int time) { ScalarField[] scalars;// = new ScalarField[2]; //RedSea.Variable measureAsVar; //switch (_currentSetting.Measure) //{ // case RedSea.Measure.SALINITY: // case RedSea.Measure.SURFACE_HEIGHT: // case RedSea.Measure.TEMPERATURE: // measureAsVar = (RedSea.Variable)(int)_currentSetting.Measure; // break; // default: // measureAsVar = RedSea.Variable.VELOCITY_Z; // break; //} int stepTime = time / 12; int substepTime = time - (stepTime * 12); // substepTime *= 9; LoaderRaw file = RedSea.Singleton.GetLoader(stepTime, substepTime, member, RedSea.Variable.VELOCITY_X) as LoaderRaw; int height = _currentSetting.Measure == RedSea.Measure.SURFACE_HEIGHT ? 0 : _currentSetting.SliceHeight; file.Range.SetMember(RedSea.Dimension.GRID_Z, height); file.Range.CorrectEndian = false; switch (_currentSetting.Measure) { case RedSea.Measure.VELOCITY: case RedSea.Measure.DIVERGENCE: case RedSea.Measure.VORTICITY: case RedSea.Measure.SHEAR: case RedSea.Measure.DIVERGENCE_2D: scalars = new ScalarField[2]; LoadVelocity: scalars[0] = file.LoadFieldSlice(); file.Range.SetVariable(RedSea.Variable.VELOCITY_Y); scalars[1] = file.LoadFieldSlice(); break; default: RedSea.Measure var = _currentSetting.Measure; // Maybe load vector field too. bool addVelocity = (_currentSetting.Shader == FieldPlane.RenderEffect.LIC || _currentSetting.Shader == FieldPlane.RenderEffect.LIC_LENGTH); scalars = new ScalarField[addVelocity ? 3 : 1]; file.Range.SetVariable((RedSea.Variable)var); scalars[scalars.Length - 1] = file.LoadFieldSlice(); if (addVelocity) goto LoadVelocity; break; } VectorField field; switch (_currentSetting.Measure) { case RedSea.Measure.DIVERGENCE: { VectorField vel = new VectorField(scalars); bool keepField = _currentSetting.Shader == FieldPlane.RenderEffect.LIC; scalars = new ScalarField[keepField ? 3 : 1]; scalars[scalars.Length - 1] = new VectorField(vel, FieldAnalysis.Divergence, 1, true).Scalars[0] as ScalarField; if (keepField) { scalars[0] = vel.Scalars[0] as ScalarField; scalars[1] = vel.Scalars[1] as ScalarField; } break; } case RedSea.Measure.DIVERGENCE_2D: { VectorField vel = new VectorField(scalars); scalars = new VectorField(vel, FieldAnalysis.Div2D, 2, true).Scalars as ScalarField[]; break; } case RedSea.Measure.VORTICITY: { VectorField vel = new VectorField(scalars); bool keepField = _currentSetting.Shader == FieldPlane.RenderEffect.LIC; scalars = new ScalarField[keepField ? 3 : 1]; scalars[scalars.Length - 1] = new VectorField(vel, FieldAnalysis.Vorticity, 1, true).Scalars[0] as ScalarField; if (keepField) { scalars[0] = vel.Scalars[0] as ScalarField; scalars[1] = vel.Scalars[1] as ScalarField; } break; } case RedSea.Measure.SHEAR: { VectorField vel = new VectorField(scalars); bool keepField = _currentSetting.Shader == FieldPlane.RenderEffect.LIC; scalars = new ScalarField[keepField ? 3 : 1]; scalars[scalars.Length - 1] = new VectorField(vel, FieldAnalysis.Shear, 1, true).Scalars[0] as ScalarField; if (keepField) { scalars[0] = vel.Scalars[0] as ScalarField; scalars[1] = vel.Scalars[1] as ScalarField; } break; } default: break; } field = new VectorField(scalars); _grid = field.Grid as RectlinearGrid; return new FieldPlane(Plane, field, _currentSetting.Shader, _currentSetting.Colormap); }
/// <summary> /// Load a slice from the file. /// </summary> /// <param name="slice">Carries variable to load, dimensions in file and what to load.</param> /// <returns></returns> public override ScalarFieldUnsteady LoadTimeSlices(SliceRange slice, int starttime = -1, int timelength = -1) { Index offsets = new Index(slice.GetOffsets()); int spaceDims = 4; int[] sizeInFile = slice.GetLengths(); Debug.Assert(starttime == -1 && timelength == -1, "Ignoring those parameters. Plase specify in the SliceRange instance!"); // Probably has less dimensions. int[] sizeField = new int[spaceDims]; int numDimsField = 0; // Exclude time dimension. It will be treated differently. for (int dim = 0; dim < offsets.Length; ++dim) { if (offsets[dim] != -1 && sizeInFile[dim] > 1) { sizeField[numDimsField++] = sizeInFile[dim]; } // Include whole dimension. else if (offsets[dim] == -1) { // Fill size. sizeInFile[dim] = _dimLengths[dim]; // Set offset to one. offset = 0, size = size of dimension. offsets[dim] = 0; // Save size in size-vector for the scalar field. sizeField[numDimsField++] = sizeInFile[dim]; } } int numSpaceDims = ((sizeInFile[0] > 1) ? 1 : 0) + ((sizeInFile[1] > 1) ? 1 : 0) + ((sizeInFile[2] > 1) ? 1 : 0); Index fieldSize = new Index(numSpaceDims); Array.Copy(sizeField, fieldSize.Data, fieldSize.Length); Debug.Assert(sizeInFile[3] == 1, "How should I load several members into one data block???"); // Create a grid descriptor for the field. // TODO: Actually load this data. RectlinearGrid grid = new RectlinearGrid(fieldSize); // Create scalar field instance and fill it with data. int sliceSize = grid.Size.Product(); // For each time and subtime step, run through them. ScalarField[] fields = new ScalarField[sizeInFile[4] * sizeInFile[5]]; int indexTime = 0; for (int time = 0; time < sizeInFile[spaceDims]; ++time) { for (int subtime = 0; subtime < sizeInFile[spaceDims + 1]; ++subtime) { // Now, load one single file. string filename = RedSea.Singleton.GetFilename(offsets[spaceDims] + time, offsets[spaceDims + 1] + subtime, offsets[3], slice.GetVariable()); using (FileStream fs = File.Open(@filename, FileMode.Open)) { // Read in the data you need. using (BinaryReader reader = new BinaryReader(fs)) { // Read in all floats. Debug.Assert(reader.BaseStream.Length >= sliceSize * sizeof(float)); fields[indexTime] = new ScalarField(grid); int indexSpace = 0; for (int z = offsets[2]; z < offsets[2] + sizeInFile[2]; ++z) { // Set file reader position to right start point. reader.BaseStream.Seek(z * _dimLengths[0] * _dimLengths[1] + offsets[1] * _dimLengths[0] + offsets[0], SeekOrigin.Begin); for (int y = offsets[1]; y < offsets[1] + sizeInFile[1]; ++y) { for (int x = offsets[0]; x < offsets[0] + sizeInFile[0]; ++x) { fields[indexTime][indexSpace++] = reader.ReadSingle(); } // Advance one line. reader.BaseStream.Seek((_dimLengths[0] - sizeInFile[0]) * sizeof(float), SeekOrigin.Current); } } } } // Change Endian of data. if (!Range.CorrectEndian) { fields[indexTime].ChangeEndian(); for (int i = 0; i < fields[indexTime].Data.Length; ++i) { if (fields[indexTime].Data[i] == 0) { fields[indexTime].Data[i] = float.MaxValue; } } fields[indexTime].InvalidValue = float.MaxValue; } // Go on to next file. indexTime++; } } return(new ScalarFieldUnsteady(fields, offsets[spaceDims] * _dimLengths[spaceDims + 1] + offsets[spaceDims + 1])); }
/// <summary> /// Setup as empty map with only one value at 1. /// </summary> /// <param name="pos"></param> /// <param name="fieldEnsemble"></param> /// <param name="startTime"></param> /// <param name="endTime"></param> public void SetupPoint(Int2 pos, int startTime) { // ~~~~~~~~~~~~~~ Copy relevant data ~~~~~~~~~~~~~~ \\ // Count up when advection was executed. CurrentTime = startTime; _startTime = startTime; // ~~~~~~~~~~~~ Load ensemble ~~~~~~~~~~~~ \\ // Load fields first to get the grid size. //Loader ncFile = new Loader(RedSea.Singleton.DataFolder + (_startTime + 1) + RedSea.Singleton.FileName); //ScalarField t0X = ncFile.LoadFieldSlice(_ensembleRanges[0]); //ScalarField t0Y = ncFile.LoadFieldSlice(_ensembleRanges[1]); //ncFile.Close(); LoaderNCF ncFile = RedSea.Singleton.GetLoaderNCF(_startTime); ScalarField t1X = ncFile.LoadFieldSlice(_ensembleRanges[0]); ScalarField t1Y = ncFile.LoadFieldSlice(_ensembleRanges[1]); ncFile.Close(); // ~~~~~~~~~~~~~~ Copy relevant data ~~~~~~~~~~~~~~ \\ // Keep for plane creation and size reference. _ensembleGrid = t1X.Grid as RectlinearGrid; // Mapper for binding the SlimDX texture to CUDA easily. _cudaDxMapper = new CudaGraphicsInteropResourceCollection(); // Tell CUDA which value is a border. _texInvalidValue = t1X.InvalidValue ?? float.MaxValue; // ~~~~~~~~~~~~ Fill CUDA resources ~~~~~~~~~~~~ \\ // All members are above each other. int vHeight = _height * _numMembers; //// vX, t=0 //_t0X = new CudaArray2D(CUArrayFormat.Float, _width, vHeight, CudaArray2DNumChannels.One); //_t0X.CopyFromHostToThis<float>(t0X.Data); //new CudaTextureArray2D(_advectParticlesKernel, "vX_t0", CUAddressMode.Wrap, CUFilterMode.Linear, CUTexRefSetFlags.None, _t0X); //// vY, t=0 //_t0Y = new CudaArray2D(CUArrayFormat.Float, _width, vHeight, CudaArray2DNumChannels.One); //_t0Y.CopyFromHostToThis<float>(t0Y.Data); //new CudaTextureArray2D(_advectParticlesKernel, "vY_t0", CUAddressMode.Wrap, CUFilterMode.Linear, CUTexRefSetFlags.None, _t0Y); // vX, t=1 _t1X = new CudaArray2D(CUArrayFormat.Float, _width, vHeight, CudaArray2DNumChannels.One); _t1X.CopyFromHostToThis <float>(t1X.Data); new CudaTextureArray2D(_advectParticlesKernel, "vX_t1", CUAddressMode.Wrap, CUFilterMode.Linear, CUTexRefSetFlags.None, _t1X); // vY, t=1 _t1Y = new CudaArray2D(CUArrayFormat.Float, _width, vHeight, CudaArray2DNumChannels.One); _t1Y.CopyFromHostToThis <float>(t1Y.Data); new CudaTextureArray2D(_advectParticlesKernel, "vY_t1", CUAddressMode.Wrap, CUFilterMode.Linear, CUTexRefSetFlags.None, _t1Y); // ~~~~~~~~~~~~~ Create texture ~~~~~~~~~~~~~~~~~~~~ \\ // Create texture. Completely zero, except for one point. Texture2DDescription desc = new Texture2DDescription { ArraySize = 1, BindFlags = BindFlags.ShaderResource, CpuAccessFlags = CpuAccessFlags.None, Format = Format.R32_Float, Width = _width, Height = _height, MipLevels = 1, OptionFlags = ResourceOptionFlags.None, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Default }; // Put field data into stream/rectangle object float[] zeros = new float[_width * _height]; Array.Clear(zeros, 0, zeros.Length); // Fill the empty texture. DataRectangle texData = new DataRectangle(_width * sizeof(float), new DataStream(zeros, true, true)); _pongFlowMap = new CudaDeviceVariable <float>(_width * _height);//new Texture2D(_device, desc, texData); // Magically, copy to device happens here. _pongFlowMap = zeros; // Add one pixel for integration. zeros[pos.X + pos.Y * _width] = 1; texData = new DataRectangle(_width * sizeof(float), new DataStream(zeros, true, true)); // Create texture. FlowMap = new Texture2D(_device, desc, texData); // ~~~~~~~~~ Make textures mappable to CUDA ~~~~~~~~~~ \\ _cudaDxMapper.Add(new CudaDirectXInteropResource(FlowMap.ComPointer, CUGraphicsRegisterFlags.None, CudaContext.DirectXVersion.D3D11)); _cudaDxMapper.MapAllResources(); CudaArray2D lastFlowMap = _cudaDxMapper[0].GetMappedArray2D(0, 0); new CudaTextureArray2D(_advectParticlesKernel, "flowMap", CUAddressMode.Wrap, CUFilterMode.Linear, CUTexRefSetFlags.None, lastFlowMap); _cudaDxMapper.UnmapAllResources(); }
/// <summary> /// Load a slice from the file. /// </summary> /// <param name="slice">Carries variable to load, dimensions in file and what to load.</param> /// <returns></returns> public override ScalarFieldUnsteady LoadTimeSlices(SliceRange slice, int starttime = -1, int timelength = -1) { Index offsets = new Index(slice.GetOffsets()); int spaceDims = 4; int[] sizeInFile = slice.GetLengths(); Debug.Assert(starttime == -1 && timelength == -1, "Ignoring those parameters. Plase specify in the SliceRange instance!"); // Probably has less dimensions. int[] sizeField = new int[spaceDims]; int numDimsField = 0; // Exclude time dimension. It will be treated differently. for (int dim = 0; dim < offsets.Length; ++dim) { if (offsets[dim] != -1 && sizeInFile[dim] > 1) { sizeField[numDimsField++] = sizeInFile[dim]; } // Include whole dimension. else if (offsets[dim] == -1) { // Fill size. sizeInFile[dim] = _dimLengths[dim]; // Set offset to one. offset = 0, size = size of dimension. offsets[dim] = 0; // Save size in size-vector for the scalar field. sizeField[numDimsField++] = sizeInFile[dim]; } } int numSpaceDims = ((sizeInFile[0] > 1) ? 1 : 0) + ((sizeInFile[1] > 1) ? 1 : 0) + ((sizeInFile[2] > 1) ? 1 : 0); Index fieldSize = new Index(numSpaceDims); Array.Copy(sizeField, fieldSize.Data, fieldSize.Length); Debug.Assert(sizeInFile[3] == 1, "How should I load several members into one data block???"); // Create a grid descriptor for the field. // TODO: Actually load this data. RectlinearGrid grid = new RectlinearGrid(fieldSize); // Create scalar field instance and fill it with data. int sliceSize = grid.Size.Product(); // For each time and subtime step, run through them. ScalarField[] fields = new ScalarField[sizeInFile[4] * sizeInFile[5]]; int indexTime = 0; for (int time = 0; time < sizeInFile[spaceDims]; ++time) { for (int subtime = 0; subtime < sizeInFile[spaceDims + 1]; ++subtime) { // Now, load one single file. string filename = RedSea.Singleton.GetFilename(offsets[spaceDims] + time, offsets[spaceDims + 1] + subtime, offsets[3], slice.GetVariable()); using (FileStream fs = File.Open(@filename, FileMode.Open)) { // Read in the data you need. using (BinaryReader reader = new BinaryReader(fs)) { // Read in all floats. Debug.Assert(reader.BaseStream.Length >= sliceSize * sizeof(float)); fields[indexTime] = new ScalarField(grid); int indexSpace = 0; for (int z = offsets[2]; z < offsets[2] + sizeInFile[2]; ++z) { // Set file reader position to right start point. reader.BaseStream.Seek(z * _dimLengths[0] * _dimLengths[1] + offsets[1] * _dimLengths[0] + offsets[0], SeekOrigin.Begin); for (int y = offsets[1]; y < offsets[1] + sizeInFile[1]; ++y) { for (int x = offsets[0]; x < offsets[0] + sizeInFile[0]; ++x) { fields[indexTime][indexSpace++] = reader.ReadSingle(); } // Advance one line. reader.BaseStream.Seek((_dimLengths[0] - sizeInFile[0]) * sizeof(float), SeekOrigin.Current); } } } } // Change Endian of data. if (!Range.CorrectEndian) { fields[indexTime].ChangeEndian(); for (int i = 0; i < fields[indexTime].Data.Length; ++i) { if (fields[indexTime].Data[i] == 0) fields[indexTime].Data[i] = float.MaxValue; } fields[indexTime].InvalidValue = float.MaxValue; } // Go on to next file. indexTime++; } } return new ScalarFieldUnsteady(fields, offsets[spaceDims] * _dimLengths[spaceDims+1] + offsets[spaceDims+1]); }
public static ScalarField FromAnalyticalField(AnalyticalField func, Index size, Vector origin, Vector cellSize) { Debug.Assert(size.Length == origin.Length && size.Length == cellSize.Length); RectlinearGrid grid = new RectlinearGrid(size); ScalarField field = new ScalarField(grid); for(int idx = 0; idx < size.Product(); ++idx) { // Compute the n-dimensional position. int index = idx; Index pos = new Index(0, size.Length); pos[0] = index % size[0]; for(int dim = 1; dim < size.Length; ++dim) { index -= pos[dim - 1]; index /= size[dim - 1]; pos[dim] = index % size[dim]; } Vector posV = origin + pos * cellSize; field[idx] = func(posV); } return field; }