/// <summary> /// Constructor /// </summary> /// <param name="fs">FluidSolver containing solution</param> /// <param name="omega">Domain containing geometry information and /// exact solutions (if known)</param> public PostProcessor(FluidSolver fs, Domain omega) { this.fs = fs; this.omega = omega; de = new DataExtractor(omega, fs); }
public void UpdateVelocity() { int pos = FluidSolver.Pos(i, j, grid.N); grid.velocitiesX[pos] = velX; grid.velocitiesY[pos] = velY; }
// Use this for initialization void Start() { m_fluidSolver = gameObject.AddComponent <FluidSolver>() as FluidSolver; m_fluidSolver.Setup(width, heigth, true, 0.03f); m_fluidSolver.SetViscosity(m_viscosity); m_fluidSolver.SetBuoyancy(m_smokeBuoyancy); m_fluidSolver.SetFadeSpeed(m_fadeSpeed); m_fluidDrawer = gameObject.AddComponent <FluidDrawer>() as FluidDrawer; m_fluidDrawer.Setup(m_fluidSolver); m_fluidDrawer.SetDrawMode(m_drawMode); m_fluidDrawer.SetTransparancy(m_transparency); }
public void RefreshCells() { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { int pos = FluidSolver.Pos(i, j, N); cells[pos].color = colors[pos]; cells[pos].velX = velocitiesX[pos]; cells[pos].velY = velocitiesY[pos]; } } }
private void RunStep(ref int timestep, ref int counter) { Rhino.RhinoApp.WriteLine($"{id} - " + Convert.ToString(t) + " of " + Convert.ToString(t_end)); double[,,] p_t2 = new double[ffd.p.GetLength(0), ffd.p.GetLength(1), ffd.p.GetLength(2)]; Array.Copy(ffd.p, 0, p_t2, 0, ffd.p.Length); double[,,] u_t2 = new double[ffd.u.GetLength(0), ffd.u.GetLength(1), ffd.u.GetLength(2)]; Array.Copy(ffd.u, 0, u_t2, 0, ffd.u.Length); double[,,] v_t2 = new double[ffd.v.GetLength(0), ffd.v.GetLength(1), ffd.v.GetLength(2)]; Array.Copy(ffd.v, 0, v_t2, 0, ffd.v.Length); double[,,] w_t2 = new double[ffd.w.GetLength(0), ffd.w.GetLength(1), ffd.w.GetLength(2)]; Array.Copy(ffd.w, 0, w_t2, 0, ffd.w.Length); ffd.time_step(f_x, f_y, f_z); if (t > dt && calcres) { double[] p_residuals; double[,,] p_t1 = ffd.p; FastFluidSolverMT.Utilities.calculate_residuals(p_t1, p_t2, out p_residuals); Rhino.RhinoApp.WriteLine($"{id} - " + "p residuals: {0};{1};{2}", p_residuals[0], p_residuals[1], p_residuals[2]); double[] u_residuals; double[,,] u_t1 = ffd.u; FastFluidSolverMT.Utilities.calculate_residuals(u_t1, u_t2, out u_residuals); Rhino.RhinoApp.WriteLine($"{id} - " + "u residuals: {0};{1};{2}", u_residuals[0], u_residuals[1], u_residuals[2]); double[] v_residuals; double[,,] v_t1 = ffd.v; FastFluidSolverMT.Utilities.calculate_residuals(v_t1, v_t2, out v_residuals); Rhino.RhinoApp.WriteLine($"{id} - " + "v residuals: {0};{1};{2}", v_residuals[0], v_residuals[1], v_residuals[2]); double[] w_residuals; double[,,] w_t1 = ffd.w; FastFluidSolverMT.Utilities.calculate_residuals(w_t1, w_t2, out w_residuals); Rhino.RhinoApp.WriteLine($"{id} - " + "w residuals: {0};{1};{2}", w_residuals[0], w_residuals[1], w_residuals[2]); File.AppendAllText(residualstxt, Convert.ToString(p_residuals[0]) + ";" + Convert.ToString(p_residuals[1]) + ";" + Convert.ToString(p_residuals[2]) + ";" + Convert.ToString(u_residuals[0]) + ";" + Convert.ToString(u_residuals[1]) + ";" + Convert.ToString(u_residuals[2]) + ";" + Convert.ToString(v_residuals[0]) + ";" + Convert.ToString(v_residuals[1]) + ";" + Convert.ToString(v_residuals[2]) + ";" + Convert.ToString(w_residuals[0]) + ";" + Convert.ToString(w_residuals[1]) + ";" + Convert.ToString(w_residuals[2]) + "\n"); } if (t >= t_end - m * dt) { ffd_old[counter] = new FluidSolver(ffd); counter++; } if (writeVTK) { pp.export_data_vtk(filepath + @"\\vtk_" + timestep + ".vtk", t, false); } t += dt; }
public void PopulateGridFunction() { cells = new Cell[N * N]; velocitiesX = new float[N * N]; velocitiesY = new float[N * N]; colors = new float[N * N]; temp = new float[N * N]; Vector3 cellSpacing = cellPrefab.sprite.bounds.size; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { var cell = GameObject.Instantiate(cellPrefab, this.transform.position + new Vector3(cellSpacing.x * i, -cellSpacing.y * j), Quaternion.identity, this.transform); cell.i = i; cell.j = j; cell.grid = this; cells[FluidSolver.Pos(i, j, N)] = cell; } } }
static void Main() { // Set mesh parameters, here we ask for Nx cells in the x direction // Ny cells in the y direction and Nz cells in the z direction (ignoring ghost cells) int Nx = 20; int Ny = 20; int Nz = 20; // Set time step and viscosity double dt = 0.01; double nu = 1e-2; // Set simulation start and finish times double tf = 100; double t = 0; // Set initial conditions double[, ,] u0 = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] v0 = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] w0 = new double[Nx + 2, Ny + 2, Nz + 1]; // Create empty arrays for body forces double[, ,] f_x = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] f_y = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] f_z = new double[Nx + 2, Ny + 2, Nz + 1]; // Create structure containing solver parameters FluidSolver.solver_struct solver_prams = new FluidSolver.solver_struct(); solver_prams.tol = 1e-4; solver_prams.min_iter = 0; solver_prams.max_iter = 30; solver_prams.verbose = true; solver_prams.backtrace_order = 2; // Create domain // Pass in the number of cells in x, y and z direction (now including ghost cells) CavityDomain omega = new CavityDomain(Nx + 2, Ny + 2, Nz + 2); // Create FFD solver FluidSolver ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_prams); // Create post processor, export intial conditions and geometry information PostProcessor pp = new PostProcessor(ffd, omega); int tstep = 0; pp.export_data_vtk(String.Concat("cavity_", tstep, ".vtk"), 0, false); pp.export_geometry_vtk("cavity_geometry.vtk", 0); // Begin time loop while (t < tf) { t += dt; tstep++; Console.WriteLine("Time t = {0}", t); // Solve single time step and export results ffd.time_step(f_x, f_y, f_z); pp.export_data_vtk(String.Concat("cavity_", tstep, ".vtk"), t, false); } }
public bool Run() { if (xyzsize.Count == 0) { Rhino.RhinoApp.WriteLine($"{id} - Error"); return(false); } run = true; counter = 0; timestep = 0; double nu = 1.511e-5; // increase viscosity to impose turbulence. the higher velocity, the higher visc., 1e-3 FluidSolver.solver_struct solver_params = new FluidSolver.solver_struct(); double z0; if (str_params != null) { nu = Convert.ToDouble(str_params[0]); solver_params.tol = Convert.ToDouble(str_params[1]); solver_params.min_iter = Convert.ToInt16(str_params[2]); solver_params.max_iter = Convert.ToInt16(str_params[3]); solver_params.backtrace_order = Convert.ToInt16(str_params[4]); solver_params.mass_correction = str_params[5].Equals("false") ? false : true; solver_params.mass_corr_alpha = Convert.ToDouble(str_params[6]); solver_params.verbose = str_params[7].Equals("false") ? false : true; z0 = Convert.ToDouble(str_params[8]); } else { solver_params.tol = 1e-4; solver_params.min_iter = 1; solver_params.max_iter = 30; solver_params.backtrace_order = 2; solver_params.mass_correction = false; solver_params.mass_corr_alpha = 0.7; solver_params.verbose = false; z0 = 0.1; } // ********************************************************************************* // Set-up FFD Solver // ********************************************************************************* // Set initial velocity conditions u0 = new double[Nx + 1, Ny + 2, Nz + 2]; v0 = new double[Nx + 2, Ny + 1, Nz + 2]; w0 = new double[Nx + 2, Ny + 2, Nz + 1]; // Create empty arrays for body forces f_x = new double[Nx + 1, Ny + 2, Nz + 2]; f_y = new double[Nx + 2, Ny + 1, Nz + 2]; f_z = new double[Nx + 2, Ny + 2, Nz + 1]; // Create FFD solver and domain //if (ffd == null || resetFFD) //{ Rhino.RhinoApp.WriteLine($"{id} - " + "{0}, {1}, {2}", xyzsize[0], xyzsize[1], xyzsize[2]); if (terrain == 4) { omega = new WindInflowOpenFoam(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2], Vmet, z0); } else { omega = new WindInflow(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2], Vmet, terrain); } //Rhino.RhinoApp.WriteLine("M0005"); foreach (double[] geo in geom) { omega.add_obstacle(geo[0], geo[1], geo[2], geo[3], geo[4], geo[5]); } //Rhino.RhinoApp.WriteLine("M0005a"); ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_params); de = new DataExtractor(omega, ffd); t = 0; //Rhino.RhinoApp.WriteLine("M0006"); pp = new PostProcessor(ffd, omega); //if (resetFFD) resetFFD = false; //reset FFD solver and domain if (id == 0) { Rhino.RhinoApp.WriteLine($"{id} - " + "GRASSHOPPER FFD Air Flow Simulation."); Rhino.RhinoApp.WriteLine($"{id} - " + "GH Plug-in: https://github.com/christophwaibel/GH_Wind"); Rhino.RhinoApp.WriteLine($"{id} - " + "FFD Solver: https://github.com/lukasbystricky/GSoC_FFD"); Rhino.RhinoApp.WriteLine($"{id} - " + "________________________________________________________"); Rhino.RhinoApp.WriteLine($"{id} - " + "...Domain initialized"); Rhino.RhinoApp.WriteLine($"{id} - " + "________________________________________________________"); } //} if (run) { if (writeVTK) { pp.export_geometry_vtk(filepath + @"\\vtk_geometry.vtk", 0); } counter = 0; timestep = 0; ffd_old = new FluidSolver[m]; if (calcres) { File.AppendAllText(residualstxt, "pmin; pmax; pavg; umin; umax; uavg; vmin; vmax; vavg; wmin; wmax; wavg;\n"); } while (t < t_end) { // only works if in the gh component and not in this class. //if (GH_Document.IsEscapeKeyDown()) //{ // Rhino.RhinoApp.WriteLine("Cancelled by user"); // //GH_Document GHDocument = OnPingDocument(); // //GHDocument.RequestAbortSolution(); // break; //} if (run != true) { break; } RunStep(ref timestep, ref counter); // doesnt work because the gh component doesnt update. //if (t % 10 == 0) //{ // UpdateOutput(); //} } } UpdateOutput(); return(true); //returns to the task manager and updates GH component }
public void UpdateOutput() { //averaging results FluidSolver ffd_mean = new FluidSolver(ffd); ffd_mean.p = new double[ffd.p.GetLength(0), ffd.p.GetLength(1), ffd.p.GetLength(2)]; ffd_mean.u = new double[ffd.u.GetLength(0), ffd.u.GetLength(1), ffd.u.GetLength(2)]; ffd_mean.v = new double[ffd.v.GetLength(0), ffd.v.GetLength(1), ffd.v.GetLength(2)]; ffd_mean.w = new double[ffd.w.GetLength(0), ffd.w.GetLength(1), ffd.w.GetLength(2)]; for (int i = 0; i < ffd_mean.p.GetLength(0); i++) { for (int j = 0; j < ffd_mean.p.GetLength(1); j++) { for (int k = 0; k < ffd_mean.p.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.p[i, j, k] += ffd_old[u].p[i, j, k]; } ffd_mean.p[i, j, k] /= counter; } } } for (int i = 0; i < ffd_mean.u.GetLength(0); i++) { for (int j = 0; j < ffd_mean.u.GetLength(1); j++) { for (int k = 0; k < ffd_mean.u.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.u[i, j, k] += ffd_old[u].u[i, j, k]; } ffd_mean.u[i, j, k] /= counter; } } } for (int i = 0; i < ffd_mean.v.GetLength(0); i++) { for (int j = 0; j < ffd_mean.v.GetLength(1); j++) { for (int k = 0; k < ffd_mean.v.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.v[i, j, k] += ffd_old[u].v[i, j, k]; } ffd_mean.v[i, j, k] /= counter; } } } for (int i = 0; i < ffd_mean.w.GetLength(0); i++) { for (int j = 0; j < ffd_mean.w.GetLength(1); j++) { for (int k = 0; k < ffd_mean.w.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.w[i, j, k] += ffd_old[u].w[i, j, k]; } ffd_mean.w[i, j, k] /= counter; } } } de = new DataExtractor(omega, ffd_mean); // AVERAGE OUTPUT BELOW: p = new double[Nx, Ny, Nz]; double[,,] vu = new double[Nx, Ny, Nz]; double[,,] vv = new double[Nx, Ny, Nz]; double[,,] vw = new double[Nx, Ny, Nz]; pstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[,,] vustag = new double[Nx + 1, Ny + 1, Nz + 1]; double[,,] vvstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[,,] vwstag = new double[Nx + 1, Ny + 1, Nz + 1]; for (int i = 0; i < Nx; i++) { for (int j = 0; j < Ny; j++) { for (int k = 0; k < Nz; k++) { if (omega.obstacle_cells[i + 1, j + 1, k + 1] != 1) { p[i, j, k] = de.get_pressure(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); double[] vel = de.get_velocity(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); vu[i, j, k] = vel[0]; vv[i, j, k] = vel[1]; vw[i, j, k] = vel[2]; } else { p[i, j, k] = 0; vu[i, j, k] = 0; vv[i, j, k] = 0; vw[i, j, k] = 0; } pstag[i, j, k] = de.get_pressure(i * omega.hx, j * omega.hy, k * omega.hz); double[] velcen = de.get_velocity(i * omega.hx, j * omega.hy, k * omega.hz); vustag[i, j, k] = velcen[0]; vvstag[i, j, k] = velcen[1]; vwstag[i, j, k] = velcen[2]; } } } //last x slice for (int j = 0; j < Ny + 1; j++) { for (int k = 0; k < Nz + 1; k++) { pstag[Nx, j, k] = de.get_pressure((Nx) * omega.hx, j * omega.hy, k * omega.hz); double[] vcen = de.get_velocity((Nx) * omega.hx, j * omega.hy, k * omega.hz); vustag[Nx, j, k] = vcen[0]; vvstag[Nx, j, k] = vcen[1]; vwstag[Nx, j, k] = vcen[2]; } } //last y slice for (int i = 0; i < Nx + 1; i++) { for (int k = 0; k < Nz + 1; k++) { pstag[i, Ny, k] = de.get_pressure(i * omega.hx, (Ny) * omega.hy, k * omega.hz); double[] vcen = de.get_velocity(i * omega.hx, (Ny) * omega.hy, k * omega.hz); vustag[i, Ny, k] = vcen[0]; vvstag[i, Ny, k] = vcen[1]; vwstag[i, Ny, k] = vcen[2]; } } //last z slice for (int i = 0; i < Nx + 1; i++) { for (int j = 0; j < Ny + 1; j++) { pstag[i, j, Nz] = de.get_pressure(i * omega.hx, j * omega.hy, (Nz) * omega.hz); double[] vcen = de.get_velocity(i * omega.hx, j * omega.hy, (Nz) * omega.hz); vustag[i, j, Nz] = vcen[0]; vvstag[i, j, Nz] = vcen[1]; vwstag[i, j, Nz] = vcen[2]; } } List <double[, , ]> veloutCen = new List <double[, , ]> { }; veloutCen.Add(vu); veloutCen.Add(vv); veloutCen.Add(vw); List <double[, , ]> veloutStag = new List <double[, , ]> { }; veloutStag.Add(vustag); veloutStag.Add(vvstag); veloutStag.Add(vwstag); obstacle_cells = omega.obstacle_cells; }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { string filepath; Domain omega; FluidSolver ffd; DataExtractor de; double t; bool resetFFD; // current filepath filepath = Path.GetDirectoryName(this.OnPingDocument().FilePath); string residualstxt = filepath + @"\\residual.txt"; // ********************************************************************************* // Inputs // ********************************************************************************* List <double> xyzsize = new List <double>(); if (!DA.GetDataList(0, xyzsize)) { return; } ; List <int> Nxyz = new List <int>(); if (!DA.GetDataList(1, Nxyz)) { return; } ; int Nx = Nxyz[0]; int Ny = Nxyz[1]; int Nz = Nxyz[2]; List <double[]> geom = new List <double[]>(); if (!DA.GetDataList(2, geom)) { return; } ; // time step double dt = 0.1; if (!DA.GetData(3, ref dt)) { return; } // horizon double t_end = 1; if (!DA.GetData(4, ref t_end)) { return; } // wind speed double Vmet = 10; if (!DA.GetData(5, ref Vmet)) { return; } //terrain type int terrain = 0; if (!DA.GetData(6, ref terrain)) { return; } bool run = false; if (!DA.GetData(7, ref run)) { return; } //List<Mesh> mshCp = new List<Mesh>(); //DA.GetDataList(10, mshCp); bool writeresults = false; DA.GetData(8, ref writeresults); bool writeVTK = false; DA.GetData(9, ref writeVTK); //DA.GetData(10, ref resetFFD); bool calcres = false; DA.GetData(12, ref calcres); int m = 10; DA.GetData(13, ref m); string strparam = null; DA.GetData(11, ref strparam); string[] str_params = null; if (strparam != null) { str_params = strparam.Split(';'); } double nu = 1.511e-5; // increase viscosity to impose turbulence. the higher velocity, the higher visc., 1e-3 FluidSolver.solver_struct solver_params = new FluidSolver.solver_struct(); double z0; if (str_params != null) { nu = Convert.ToDouble(str_params[0]); solver_params.tol = Convert.ToDouble(str_params[1]); solver_params.min_iter = Convert.ToInt16(str_params[2]); solver_params.max_iter = Convert.ToInt16(str_params[3]); solver_params.backtrace_order = Convert.ToInt16(str_params[4]); solver_params.mass_correction = str_params[5].Equals("false") ? false : true; solver_params.mass_corr_alpha = Convert.ToDouble(str_params[6]); solver_params.verbose = str_params[7].Equals("false") ? false : true; z0 = Convert.ToDouble(str_params[8]); } else { solver_params.tol = 1e-4; solver_params.min_iter = 1; solver_params.max_iter = 30; solver_params.backtrace_order = 2; solver_params.mass_correction = false; solver_params.mass_corr_alpha = 0.7; solver_params.verbose = false; z0 = 0.1; } // ********************************************************************************* // Set-up FFD Solver // ********************************************************************************* // Set initial velocity conditions double[,,] u0 = new double[Nx + 1, Ny + 2, Nz + 2]; double[,,] v0 = new double[Nx + 2, Ny + 1, Nz + 2]; double[,,] w0 = new double[Nx + 2, Ny + 2, Nz + 1]; // Create empty arrays for body forces double[,,] f_x = new double[Nx + 1, Ny + 2, Nz + 2]; double[,,] f_y = new double[Nx + 2, Ny + 1, Nz + 2]; double[,,] f_z = new double[Nx + 2, Ny + 2, Nz + 1]; // Create FFD solver and domain //if (ffd == null || resetFFD) //{ if (terrain == 4) { omega = new WindInflowOpenFoam(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2], Vmet, z0); } else { omega = new WindInflow(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2], Vmet, terrain); } foreach (double[] geo in geom) { omega.add_obstacle(geo[0], geo[1], geo[2], geo[3], geo[4], geo[5]); } ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_params); de = new DataExtractor(omega, ffd); t = 0; PostProcessor pp = new PostProcessor(ffd, omega); //if (resetFFD) resetFFD = false; //reset FFD solver and domain Rhino.RhinoApp.WriteLine("GRASSHOPPER FFD Air Flow Simulation."); Rhino.RhinoApp.WriteLine("GH Plug-in: https://github.com/christophwaibel/GH_Wind"); Rhino.RhinoApp.WriteLine("FFD Solver: https://github.com/lukasbystricky/GSoC_FFD"); Rhino.RhinoApp.WriteLine("________________________________________________________"); Rhino.RhinoApp.WriteLine("...Domain initialized"); Rhino.RhinoApp.WriteLine("________________________________________________________"); //} // ******************************************************************************************* // Run each time GH is updated // ******************************************************************************************* //run solver. the solving-loop (new timestep) is executed in Grasshopper with a timer-component. //!!!!!!!!!!!!!!! CHANGE if (run) { if (writeVTK) { pp.export_geometry_vtk(filepath + @"\\vtk_geometry.vtk", 0); } int counter = 0; int timestep = 0; FluidSolver[] ffd_old = new FluidSolver[m]; if (calcres) { File.AppendAllText(residualstxt, "pmin; pmax; pavg; umin; umax; uavg; vmin; vmax; vavg; wmin; wmax; wavg;\n"); } # region whileloop while (t < t_end) { if (GH_Document.IsEscapeKeyDown()) { Rhino.RhinoApp.WriteLine("Cancelled by user"); GH_Document GHDocument = OnPingDocument(); GHDocument.RequestAbortSolution(); break; } Rhino.RhinoApp.WriteLine(Convert.ToString(t) + " of " + Convert.ToString(t_end)); double[,,] p_t2 = new double[ffd.p.GetLength(0), ffd.p.GetLength(1), ffd.p.GetLength(2)]; Array.Copy(ffd.p, 0, p_t2, 0, ffd.p.Length); double[,,] u_t2 = new double[ffd.u.GetLength(0), ffd.u.GetLength(1), ffd.u.GetLength(2)]; Array.Copy(ffd.u, 0, u_t2, 0, ffd.u.Length); double[,,] v_t2 = new double[ffd.v.GetLength(0), ffd.v.GetLength(1), ffd.v.GetLength(2)]; Array.Copy(ffd.v, 0, v_t2, 0, ffd.v.Length); double[,,] w_t2 = new double[ffd.w.GetLength(0), ffd.w.GetLength(1), ffd.w.GetLength(2)]; Array.Copy(ffd.w, 0, w_t2, 0, ffd.w.Length); ffd.time_step(f_x, f_y, f_z); if (t > dt && calcres) { double[] p_residuals; double[,,] p_t1 = ffd.p; FastFluidSolverMT.Utilities.calculate_residuals(p_t1, p_t2, out p_residuals); Rhino.RhinoApp.WriteLine("p residuals: {0};{1};{2}", p_residuals[0], p_residuals[1], p_residuals[2]); double[] u_residuals; double[,,] u_t1 = ffd.u; FastFluidSolverMT.Utilities.calculate_residuals(u_t1, u_t2, out u_residuals); Rhino.RhinoApp.WriteLine("u residuals: {0};{1};{2}", u_residuals[0], u_residuals[1], u_residuals[2]); double[] v_residuals; double[,,] v_t1 = ffd.v; FastFluidSolverMT.Utilities.calculate_residuals(v_t1, v_t2, out v_residuals); Rhino.RhinoApp.WriteLine("v residuals: {0};{1};{2}", v_residuals[0], v_residuals[1], v_residuals[2]); double[] w_residuals; double[,,] w_t1 = ffd.w; FastFluidSolverMT.Utilities.calculate_residuals(w_t1, w_t2, out w_residuals); Rhino.RhinoApp.WriteLine("w residuals: {0};{1};{2}", w_residuals[0], w_residuals[1], w_residuals[2]); File.AppendAllText(residualstxt, Convert.ToString(p_residuals[0]) + ";" + Convert.ToString(p_residuals[1]) + ";" + Convert.ToString(p_residuals[2]) + ";" + Convert.ToString(u_residuals[0]) + ";" + Convert.ToString(u_residuals[1]) + ";" + Convert.ToString(u_residuals[2]) + ";" + Convert.ToString(v_residuals[0]) + ";" + Convert.ToString(v_residuals[1]) + ";" + Convert.ToString(v_residuals[2]) + ";" + Convert.ToString(w_residuals[0]) + ";" + Convert.ToString(w_residuals[1]) + ";" + Convert.ToString(w_residuals[2]) + "\n"); } if (t >= t_end - m * dt) { ffd_old[counter] = new FluidSolver(ffd); counter++; } if (writeVTK) { pp.export_data_vtk(filepath + @"\\vtk_" + timestep + ".vtk", t, false); } t += dt; timestep++; } #endregion whileloop //averaging results FluidSolver ffd_mean = new FluidSolver(ffd); ffd_mean.p = new double[ffd.p.GetLength(0), ffd.p.GetLength(1), ffd.p.GetLength(2)]; ffd_mean.u = new double[ffd.u.GetLength(0), ffd.u.GetLength(1), ffd.u.GetLength(2)]; ffd_mean.v = new double[ffd.v.GetLength(0), ffd.v.GetLength(1), ffd.v.GetLength(2)]; ffd_mean.w = new double[ffd.w.GetLength(0), ffd.w.GetLength(1), ffd.w.GetLength(2)]; for (int i = 0; i < ffd_mean.p.GetLength(0); i++) { for (int j = 0; j < ffd_mean.p.GetLength(1); j++) { for (int k = 0; k < ffd_mean.p.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.p[i, j, k] += ffd_old[u].p[i, j, k]; } ffd_mean.p[i, j, k] /= counter; } } } for (int i = 0; i < ffd_mean.u.GetLength(0); i++) { for (int j = 0; j < ffd_mean.u.GetLength(1); j++) { for (int k = 0; k < ffd_mean.u.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.u[i, j, k] += ffd_old[u].u[i, j, k]; } ffd_mean.u[i, j, k] /= counter; } } } for (int i = 0; i < ffd_mean.v.GetLength(0); i++) { for (int j = 0; j < ffd_mean.v.GetLength(1); j++) { for (int k = 0; k < ffd_mean.v.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.v[i, j, k] += ffd_old[u].v[i, j, k]; } ffd_mean.v[i, j, k] /= counter; } } } for (int i = 0; i < ffd_mean.w.GetLength(0); i++) { for (int j = 0; j < ffd_mean.w.GetLength(1); j++) { for (int k = 0; k < ffd_mean.w.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.w[i, j, k] += ffd_old[u].w[i, j, k]; } ffd_mean.w[i, j, k] /= counter; } } } de = new DataExtractor(omega, ffd_mean); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { //// ********************************************************************************* ////grasshopper current document //// ********************************************************************************* //Component = this; //doc = Component.OnPingDocument(); // ********************************************************************************* // get info from grasshopper // ********************************************************************************* List <double> xyzsize = new List <double>(); if (!DA.GetDataList(0, xyzsize)) { return; } ; List <int> Nxyz = new List <int>(); if (!DA.GetDataList(1, Nxyz)) { return; } ; int Nx = Nxyz[0]; int Ny = Nxyz[1]; int Nz = Nxyz[2]; List <double[]> geom = new List <double[]>(); if (!DA.GetDataList(2, geom)) { return; } ; // time step double dt = 0.1; if (!DA.GetData(3, ref dt)) { return; } // wind speed double Vmet = 10; DA.GetData(4, ref Vmet); //terrain type int terrain = 0; DA.GetData(5, ref terrain); bool run = false; if (!DA.GetData(6, ref run)) { return; } //List<Mesh> mshCp = new List<Mesh>(); //DA.GetDataList(10, mshCp); bool writeresults = false; DA.GetData(7, ref writeresults); DA.GetData(9, ref resetFFD); double nu = 1.511e-5; // increase viscosity to impose turbulence. the higher velocity, the higher visc., 1e-3 DA.GetData(10, ref nu); // ********************************************************************************* //from Lukas // ********************************************************************************* // Set initial velocity conditions double[, ,] u0 = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] v0 = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] w0 = new double[Nx + 2, Ny + 2, Nz + 1]; // Create empty arrays for body forces double[, ,] f_x = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] f_y = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] f_z = new double[Nx + 2, Ny + 2, Nz + 1]; // Create structure for solver parameters FluidSolver.solver_struct solver_prams = new FluidSolver.solver_struct(); solver_prams.tol = 1e-4; solver_prams.min_iter = 1; solver_prams.max_iter = 30; solver_prams.verbose = false; solver_prams.backtrace_order = 2; solver_prams.mass_correction = false; solver_prams.mass_corr_alpha = 0.7; // Create FFD solver and domain if (ffd == null) { omega = new WindInflowAytac(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2]); foreach (double[] geo in geom) { omega.add_obstacle(geo[0], geo[1], geo[2], geo[3], geo[4], geo[5]); } ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_prams); de = new DataExtractor(omega, ffd); t = 0; } //reset FFD solver and domain if (resetFFD) { omega = new WindInflowAytac(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2]); foreach (double[] geo in geom) { omega.add_obstacle(geo[0], geo[1], geo[2], geo[3], geo[4], geo[5]); } ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_prams); de = new DataExtractor(omega, ffd); t = 0; resetFFD = false; } //run solver. the solving-loop (new timestep) is executed in Grasshopper with a timer-component. if (run) { ffd.time_step(f_x, f_y, f_z); } // ******************************************************************************************* // ******************************************************************************************* // TO DO: fix this loop with // pp.export_data_vtk(String.Concat("lid_driven_cavity_", tstep, ".vtk"), Nx, Ny, Nz, tstep ); //bool run2 = (bool)Component.Params.Input[5].Sources[0].VolatileData; //while (true) //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // I could move all this shit away, an only output de data extractor // ******************************************************************************************* // ********************************* Output Results ******************************** double[, ,] p = new double[Nx, Ny, Nz]; double[, ,] vu = new double[Nx, Ny, Nz]; double[, ,] vv = new double[Nx, Ny, Nz]; double[, ,] vw = new double[Nx, Ny, Nz]; double[, ,] pstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[, ,] vustag = new double[Nx + 1, Ny + 1, Nz + 1]; double[, ,] vvstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[, ,] vwstag = new double[Nx + 1, Ny + 1, Nz + 1]; for (int i = 0; i < Nx; i++) { for (int j = 0; j < Ny; j++) { for (int k = 0; k < Nz; k++) { if (omega.obstacle_cells[i + 1, j + 1, k + 1] != 1) { p[i, j, k] = de.get_pressure(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); double[] vel = de.get_velocity(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); vu[i, j, k] = vel[0]; vv[i, j, k] = vel[1]; vw[i, j, k] = vel[2]; pstag[i, j, k] = de.get_pressure(i * omega.hx, j * omega.hy, k * omega.hz); double[] velcen = de.get_velocity(i * omega.hx, j * omega.hy, k * omega.hz); vustag[i, j, k] = velcen[0]; vvstag[i, j, k] = velcen[1]; vwstag[i, k, k] = velcen[2]; } else { p[i, j, k] = 0; vu[i, j, k] = 0; vv[i, j, k] = 0; vw[i, j, k] = 0; //pstag[i, j, k] = 0; //vustag[i, j, k] = 0; //vvstag[i, j, k] = 0; //vwstag[i, k, k] = 0; pstag[i, j, k] = de.get_pressure(i * omega.hx, j * omega.hy, k * omega.hz); double[] velcen = de.get_velocity(i * omega.hx, j * omega.hy, k * omega.hz); vustag[i, j, k] = velcen[0]; vvstag[i, j, k] = velcen[1]; vwstag[i, k, k] = velcen[2]; } } } } //last x slice for (int j = 0; j < Ny + 1; j++) { for (int k = 0; k < Nz + 1; k++) { pstag[Nx, j, k] = de.get_pressure((Nx) * omega.hx, j * omega.hy, k * omega.hz); double[] vcen = de.get_velocity((Nx) * omega.hx, j * omega.hy, k * omega.hz); vustag[Nx, j, k] = vcen[0]; vvstag[Nx, j, k] = vcen[1]; vwstag[Nx, j, k] = vcen[2]; } } //last y slice for (int i = 0; i < Nx + 1; i++) { for (int k = 0; k < Nz + 1; k++) { pstag[i, Ny, k] = de.get_pressure(i * omega.hx, (Ny) * omega.hy, k * omega.hz); double[] vcen = de.get_velocity(i * omega.hx, (Ny) * omega.hy, k * omega.hz); vustag[i, Ny, k] = vcen[0]; vvstag[i, Ny, k] = vcen[1]; vwstag[i, Ny, k] = vcen[2]; } } //last z slice for (int i = 0; i < Nx + 1; i++) { for (int j = 0; j < Ny + 1; j++) { pstag[i, j, Nz] = de.get_pressure(i * omega.hx, j * omega.hy, (Nz) * omega.hz); double[] vcen = de.get_velocity(i * omega.hx, j * omega.hy, (Nz) * omega.hz); vustag[i, j, Nz] = vcen[0]; vvstag[i, j, Nz] = vcen[1]; vwstag[i, j, Nz] = vcen[2]; } } List <double[, , ]> veloutCen = new List <double[, , ]> { }; veloutCen.Add(vu); veloutCen.Add(vv); veloutCen.Add(vw); List <double[, , ]> veloutStag = new List <double[, , ]> { }; veloutStag.Add(vustag); veloutStag.Add(vvstag); veloutStag.Add(vwstag); DA.SetDataList(0, veloutCen); DA.SetData(1, p); DA.SetDataList(2, veloutStag); DA.SetData(3, pstag); // ******************************************************************************************* // ******************************* Output Cp values on Surfaces *********************** //if (mshCp.Count > 0) if (writeresults) { DA.SetData(4, de); } }
public void Setup(FluidSolver fluidSolver) { m_fluidSolver = fluidSolver; _CreateGUI(); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { FFDSolver ffdSolver; List <FFDSolver> ffdSolvers = new List <FFDSolver>(); DA.GetDataList(0, ffdSolvers); if (ffdSolvers.Count == 0) { return; } ffdSolver = ffdSolvers[0]; Domain omega = ffdSolver.omega; FluidSolver ffd = ffdSolver.ffd; DataExtractor de = new DataExtractor(ffdSolver.omega, ffdSolver.ffd); //double[,,] pstagResults = ffdSolver.pstag; //double[,,] p = ffdSolver.p; //List<double[,,]> veloutCen = ffdSolver.veloutCen; //List<double[,,]> veloutStag = ffdSolver.veloutStag; //double[,,] pstag = ffdSolver.pstag; //DataExtractor de = ffdSolver.de; //int[,,] obstacle_cells = ffdSolver.obstacle_cells; //DA.SetDataList(0, veloutCen); //DA.SetData(1, p); //DA.SetDataList(2, veloutStag); //DA.SetData(3, pstag); ////DA.SetData(3, pstagResults); //DA.SetData(4, de); //DA.SetData(5, obstacle_cells); //DA.SetData(6, ffdSolver); int Nx = ffdSolver.Nx; int Ny = ffdSolver.Ny; int Nz = ffdSolver.Nz; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // I could move all this away, an only output de data extractor double[,,] p = new double[Nx, Ny, Nz]; double[,,] vu = new double[Nx, Ny, Nz]; double[,,] vv = new double[Nx, Ny, Nz]; double[,,] vw = new double[Nx, Ny, Nz]; double[,,] pstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[,,] vustag = new double[Nx + 1, Ny + 1, Nz + 1]; double[,,] vvstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[,,] vwstag = new double[Nx + 1, Ny + 1, Nz + 1]; for (int i = 0; i < Nx; i++) { for (int j = 0; j < Ny; j++) { for (int k = 0; k < Nz; k++) { if (omega.obstacle_cells[i + 1, j + 1, k + 1] != 1) { p[i, j, k] = de.get_pressure(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); double[] vel = de.get_velocity(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); vu[i, j, k] = vel[0]; vv[i, j, k] = vel[1]; vw[i, j, k] = vel[2]; } else { p[i, j, k] = 0; vu[i, j, k] = 0; vv[i, j, k] = 0; vw[i, j, k] = 0; } pstag[i, j, k] = de.get_pressure(i * omega.hx, j * omega.hy, k * omega.hz); double[] velcen = de.get_velocity(i * omega.hx, j * omega.hy, k * omega.hz); vustag[i, j, k] = velcen[0]; vvstag[i, j, k] = velcen[1]; vwstag[i, j, k] = velcen[2]; } } } //last x slice for (int j = 0; j < Ny + 1; j++) { for (int k = 0; k < Nz + 1; k++) { pstag[Nx, j, k] = de.get_pressure((Nx) * omega.hx, j * omega.hy, k * omega.hz); double[] vcen = de.get_velocity((Nx) * omega.hx, j * omega.hy, k * omega.hz); vustag[Nx, j, k] = vcen[0]; vvstag[Nx, j, k] = vcen[1]; vwstag[Nx, j, k] = vcen[2]; } } //last y slice for (int i = 0; i < Nx + 1; i++) { for (int k = 0; k < Nz + 1; k++) { pstag[i, Ny, k] = de.get_pressure(i * omega.hx, (Ny) * omega.hy, k * omega.hz); double[] vcen = de.get_velocity(i * omega.hx, (Ny) * omega.hy, k * omega.hz); vustag[i, Ny, k] = vcen[0]; vvstag[i, Ny, k] = vcen[1]; vwstag[i, Ny, k] = vcen[2]; } } //last z slice for (int i = 0; i < Nx + 1; i++) { for (int j = 0; j < Ny + 1; j++) { pstag[i, j, Nz] = de.get_pressure(i * omega.hx, j * omega.hy, (Nz) * omega.hz); double[] vcen = de.get_velocity(i * omega.hx, j * omega.hy, (Nz) * omega.hz); vustag[i, j, Nz] = vcen[0]; vvstag[i, j, Nz] = vcen[1]; vwstag[i, j, Nz] = vcen[2]; } } List <double[, , ]> veloutCen = new List <double[, , ]> { }; veloutCen.Add(vu); veloutCen.Add(vv); veloutCen.Add(vw); List <double[, , ]> veloutStag = new List <double[, , ]> { }; veloutStag.Add(vustag); veloutStag.Add(vvstag); veloutStag.Add(vwstag); DA.SetDataList(0, veloutCen); DA.SetData(1, p); DA.SetDataList(2, veloutStag); DA.SetData(3, pstag); DA.SetData(4, de); DA.SetData(5, omega.obstacle_cells); GH_Structure <GH_Number> outNumbers = new GH_Structure <GH_Number>(); for (int j = 0; j < veloutStag[0].GetLength(0); j++) { for (int k = 0; k < veloutStag[0].GetLength(1); k++) { double velocity = Math.Sqrt(veloutStag[0][j, k, 1] * veloutStag[0][j, k, 1] + veloutStag[1][j, k, 1] * veloutStag[1][j, k, 1] + veloutStag[2][j, k, 1] * veloutStag[2][j, k, 1]); outNumbers.Append(new GH_Number(velocity), new GH_Path(j, k)); } } DA.SetDataTree(7, outNumbers); }
public void UpdateColor() { int pos = FluidSolver.Pos(i, j, grid.N); grid.colors[pos] = color; }
private void RunStep(ref int timestep, ref int counter) { double[,,] p_t2 = new double[ffd.p.GetLength(0), ffd.p.GetLength(1), ffd.p.GetLength(2)]; Array.Copy(ffd.p, 0, p_t2, 0, ffd.p.Length); double[,,] u_t2 = new double[ffd.u.GetLength(0), ffd.u.GetLength(1), ffd.u.GetLength(2)]; Array.Copy(ffd.u, 0, u_t2, 0, ffd.u.Length); double[,,] v_t2 = new double[ffd.v.GetLength(0), ffd.v.GetLength(1), ffd.v.GetLength(2)]; Array.Copy(ffd.v, 0, v_t2, 0, ffd.v.Length); double[,,] w_t2 = new double[ffd.w.GetLength(0), ffd.w.GetLength(1), ffd.w.GetLength(2)]; Array.Copy(ffd.w, 0, w_t2, 0, ffd.w.Length); ffd.time_step(f_x, f_y, f_z); if (t > dt && calcres) { double[] p_residuals; double[,,] p_t1 = ffd.p; FastFluidSolverMT.Utilities.calculate_residuals(p_t1, p_t2, out p_residuals); double[] u_residuals; double[,,] u_t1 = ffd.u; FastFluidSolverMT.Utilities.calculate_residuals(u_t1, u_t2, out u_residuals); double[] v_residuals; double[,,] v_t1 = ffd.v; FastFluidSolverMT.Utilities.calculate_residuals(v_t1, v_t2, out v_residuals); double[] w_residuals; double[,,] w_t1 = ffd.w; FastFluidSolverMT.Utilities.calculate_residuals(w_t1, w_t2, out w_residuals); double percent = (id + (t / t_end)) / maxSolvers * 100.0; TimeSpan timeElapsed = TimeSpan.FromTicks(DateTime.Now.Subtract(startTime).Ticks); string elapsedTime = String.Format("elapsed: {0:00}:{1:00}:{2:00} ", timeElapsed.Hours, timeElapsed.Minutes, timeElapsed.Seconds); string remainingTime = ""; if (id > 0 || t > 10) { TimeSpan timeRemaining = TimeSpan.FromTicks(DateTime.Now.Subtract(startTime).Ticks *(long)((100.0 - percent + 0.1) / percent + 0.1)); remainingTime = String.Format("(remaining: {0:00}:{1:00}:{2:00})", timeRemaining.Hours, timeRemaining.Minutes, timeRemaining.Seconds); } if (t % 5 == 0) { Rhino.RhinoApp.WriteLine($"[ {id+1,4:0}/{maxSolvers,4:0} ] {t,4:0} /{t_end,4:0} {percent,4:0.0}% {elapsedTime} {remainingTime} - " + $"p res: {p_residuals[0]:00.00} ; {p_residuals[1]:00.00} ; {p_residuals[2]:00.00}, u: {u_residuals[0]:00.00} ; {u_residuals[1]:00.00} ; {u_residuals[2]:00.00}, " + $"v: {v_residuals[0]:00.00} ; {v_residuals[1]:00.00} ; {v_residuals[2]:00.00}, w: {w_residuals[0]:00.00} ; {w_residuals[1]:00.00} ; {w_residuals[2]:00.00}"); } } else { Rhino.RhinoApp.WriteLine($"[{id+1}/{maxSolvers}] {t:000}/{t_end:000} ({(id+ (t / t_end) )/ maxSolvers * 100.0:0.0}%)"); } if (t >= t_end - m * dt) { ffd_old[counter] = new FluidSolver(ffd); counter++; } if (writeVTK) { pp.export_data_vtk(filepath + @"\\vtk_" + timestep + ".vtk", t, false); } t += dt; }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object can be used to retrieve data from input parameters and /// to store data in output parameters.</param> protected override void SolveInstance(IGH_DataAccess DA) { //// ********************************************************************************* ////grasshopper current document //// ********************************************************************************* //Component = this; //doc = Component.OnPingDocument(); // ********************************************************************************* // get info from grasshopper // ********************************************************************************* List <double> xyzsize = new List <double>(); if (!DA.GetDataList(0, xyzsize)) { return; } ; List <int> Nxyz = new List <int>(); if (!DA.GetDataList(1, Nxyz)) { return; } ; int Nx = Nxyz[0]; int Ny = Nxyz[1]; int Nz = Nxyz[2]; List <double[]> geom = new List <double[]>(); if (!DA.GetDataList(2, geom)) { return; } ; // time step double dt = 0.1; if (!DA.GetData(3, ref dt)) { return; } // wind speed double Vmet = 10; if (!DA.GetData(4, ref Vmet)) { return; } //terrain type int terrain = 0; if (!DA.GetData(5, ref terrain)) { return; } bool run = false; if (!DA.GetData(6, ref run)) { return; } //List<Mesh> mshCp = new List<Mesh>(); //DA.GetDataList(10, mshCp); bool writeresults = false; DA.GetData(7, ref writeresults); DA.GetData(9, ref resetFFD); double nu = 1.511e-5; // increase viscosity to impose turbulence. the higher velocity, the higher visc., 1e-3 DA.GetData(10, ref nu); // ********************************************************************************* //from Lukas // ********************************************************************************* // Set initial velocity conditions double[, ,] u0 = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] v0 = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] w0 = new double[Nx + 2, Ny + 2, Nz + 1]; // Create empty arrays for body forces double[, ,] f_x = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] f_y = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] f_z = new double[Nx + 2, Ny + 2, Nz + 1]; // Create structure for solver parameters FluidSolver.solver_struct solver_prams = new FluidSolver.solver_struct(); solver_prams.tol = 1e-4; solver_prams.min_iter = 1; solver_prams.max_iter = 30; solver_prams.verbose = false; solver_prams.backtrace_order = 2; solver_prams.mass_correction = false; solver_prams.mass_corr_alpha = 0.7; // Create FFD solver and domain if (ffd == null) { omega = new WindInflow(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2], Vmet, terrain); foreach (double[] geo in geom) { omega.add_obstacle(geo[0], geo[1], geo[2], geo[3], geo[4], geo[5]); } ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_prams); de = new DataExtractor(omega, ffd); t = 0; } //reset FFD solver and domain if (resetFFD) { omega = new WindInflow(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2], Vmet, terrain); foreach (double[] geo in geom) { omega.add_obstacle(geo[0], geo[1], geo[2], geo[3], geo[4], geo[5]); } ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_prams); de = new DataExtractor(omega, ffd); t = 0; resetFFD = false; } //run solver. the solving-loop (new timestep) is executed in Grasshopper with a timer-component. if (run) { ffd.time_step(f_x, f_y, f_z); } // ******************************************************************************************* // ******************************************************************************************* // TO DO: fix this loop with // pp.export_data_vtk(String.Concat("lid_driven_cavity_", tstep, ".vtk"), Nx, Ny, Nz, tstep ); //bool run2 = (bool)Component.Params.Input[5].Sources[0].VolatileData; //while (true) //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // I could move all this shit away, an only output de data extractor // ******************************************************************************************* // ********************************* Output Results ******************************** double[, ,] p = new double[Nx, Ny, Nz]; double[, ,] vu = new double[Nx, Ny, Nz]; double[, ,] vv = new double[Nx, Ny, Nz]; double[, ,] vw = new double[Nx, Ny, Nz]; double[, ,] pstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[, ,] vustag = new double[Nx + 1, Ny + 1, Nz + 1]; double[, ,] vvstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[, ,] vwstag = new double[Nx + 1, Ny + 1, Nz + 1]; for (int i = 0; i < Nx; i++) { for (int j = 0; j < Ny; j++) { for (int k = 0; k < Nz; k++) { if (omega.obstacle_cells[i + 1, j + 1, k + 1] != 1) { p[i, j, k] = de.get_pressure(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); double[] vel = de.get_velocity(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); vu[i, j, k] = vel[0]; vv[i, j, k] = vel[1]; vw[i, j, k] = vel[2]; pstag[i, j, k] = de.get_pressure(i * omega.hx, j * omega.hy, k * omega.hz); double[] velcen = de.get_velocity(i * omega.hx, j * omega.hy, k * omega.hz); vustag[i, j, k] = velcen[0]; vvstag[i, j, k] = velcen[1]; vwstag[i, k, k] = velcen[2]; } else { p[i, j, k] = 0; vu[i, j, k] = 0; vv[i, j, k] = 0; vw[i, j, k] = 0; //pstag[i, j, k] = 0; //vustag[i, j, k] = 0; //vvstag[i, j, k] = 0; //vwstag[i, k, k] = 0; pstag[i, j, k] = de.get_pressure(i * omega.hx, j * omega.hy, k * omega.hz); double[] velcen = de.get_velocity(i * omega.hx, j * omega.hy, k * omega.hz); vustag[i, j, k] = velcen[0]; vvstag[i, j, k] = velcen[1]; vwstag[i, k, k] = velcen[2]; } } } } //last x slice for (int j = 0; j < Ny + 1; j++) { for (int k = 0; k < Nz + 1; k++) { pstag[Nx, j, k] = de.get_pressure((Nx) * omega.hx, j * omega.hy, k * omega.hz); double[] vcen = de.get_velocity((Nx) * omega.hx, j * omega.hy, k * omega.hz); vustag[Nx, j, k] = vcen[0]; vvstag[Nx, j, k] = vcen[1]; vwstag[Nx, j, k] = vcen[2]; } } //last y slice for (int i = 0; i < Nx + 1; i++) { for (int k = 0; k < Nz + 1; k++) { pstag[i, Ny, k] = de.get_pressure(i * omega.hx, (Ny) * omega.hy, k * omega.hz); double[] vcen = de.get_velocity(i * omega.hx, (Ny) * omega.hy, k * omega.hz); vustag[i, Ny, k] = vcen[0]; vvstag[i, Ny, k] = vcen[1]; vwstag[i, Ny, k] = vcen[2]; } } //last z slice for (int i = 0; i < Nx + 1; i++) { for (int j = 0; j < Ny + 1; j++) { pstag[i, j, Nz] = de.get_pressure(i * omega.hx, j * omega.hy, (Nz) * omega.hz); double [] vcen = de.get_velocity(i * omega.hx, j * omega.hy, (Nz) * omega.hz); vustag[i, j, Nz] = vcen[0]; vvstag[i, j, Nz] = vcen[1]; vwstag[i, j, Nz] = vcen[2]; } } List <double[, , ]> veloutCen = new List <double[, , ]> { }; veloutCen.Add(vu); veloutCen.Add(vv); veloutCen.Add(vw); List <double[, , ]> veloutStag = new List <double[, , ]> { }; veloutStag.Add(vustag); veloutStag.Add(vvstag); veloutStag.Add(vwstag); DA.SetDataList(0, veloutCen); DA.SetData(1, p); DA.SetDataList(2, veloutStag); DA.SetData(3, pstag); // ******************************************************************************************* // ******************************* Output Cp values on Surfaces *********************** //if (mshCp.Count > 0) if (writeresults) { ////generate list of objects //// each item contains: //// - 2d matrix of Cp values for each node of the analysis mesh //// - mesh itself //List<object[]> mshCpOUT = new List<object[]>(); //foreach (Mesh msh in mshCp) //{ // object[] _mshCpout = new object[2] ; // _mshCpout[0] = msh; // //_mshCpout[1] // double [] Cps = new double[msh.Vertices.Count]; //this will be the Cp values. size of array corresponds to mesh vertices // for (int u = 0; u < msh.Vertices.Count; u++) // { // double pref = de.get_pressure(0, msh.Vertices[u].Y, msh.Vertices[u].Z); //!!! adjust msh to origin and discretisationj // double cp = de.get_pressure(msh.Vertices[u].X, msh.Vertices[u].Y, msh.Vertices[u].Z); // Cps[u] = 1; // } //} //DA.SetDataList(4, mshCp); DA.SetData(4, de); } // _____________________________________________________________________________________ // // THIS SHOWS HOW TO ADD A FORM //if (f == null) //{ // f = new LEGACY_Form1(); // f.Show(Grasshopper.Instances.DocumentEditor); // Grasshopper.Instances.DocumentEditor.FormShepard.RegisterForm(f); // f.checkBox1.Text = "run the solver"; //} // _____________________________________________________________________________________ // // THIS SHOWS HOW TO DYNAMICALLY USE GRASSHOPPER SLIDER INPUTS //List<Grasshopper.Kernel.Special.GH_NumberSlider> sliders = new List<Grasshopper.Kernel.Special.GH_NumberSlider>(); //foreach (IGH_Param param in Component.Params.Input) //{ // Grasshopper.Kernel.Special.GH_NumberSlider slider = param.Sources[0] as Grasshopper.Kernel.Special.GH_NumberSlider; // if (slider != null) // { // sliders.Add(slider); // x = (int)slider.CurrentValue; // } //} //while (terminate != true) //{ // doc.NewSolution(false); // fx = x * 10; // maximize(x, fx); // sliders[0].TickValue = xNew; // x = xNew; //} }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { // ********************************************************************************* // get info from grasshopper // ********************************************************************************* List <double> xyzsize = new List <double>(); if (!DA.GetDataList(0, xyzsize)) { return; } ; List <int> Nxyz = new List <int>(); if (!DA.GetDataList(1, Nxyz)) { return; } ; int Nx = Nxyz[0]; int Ny = Nxyz[1]; int Nz = Nxyz[2]; // time step double dt = 0.1; if (!DA.GetData(2, ref dt)) { return; } bool run = false; if (!DA.GetData(3, ref run)) { return; } DA.GetData(6, ref resetFFD); double re = 400; if (!DA.GetData(7, ref re)) { return; } // ********************************************************************************* //from Lukas // ********************************************************************************* double nu = 1 / re; // increase viscosity to impose turbulence. the higher velocity, the higher visc., 1e-3 // Set initial velocity conditions double[, ,] u0 = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] v0 = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] w0 = new double[Nx + 2, Ny + 2, Nz + 1]; // Create empty arrays for body forces double[, ,] f_x = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] f_y = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] f_z = new double[Nx + 2, Ny + 2, Nz + 1]; // Create structure for solver parameters FluidSolver.solver_struct solver_prams = new FluidSolver.solver_struct(); solver_prams.tol = 1e-4; solver_prams.min_iter = 1; solver_prams.max_iter = 30; solver_prams.verbose = false; solver_prams.backtrace_order = 2; solver_prams.mass_correction = false; solver_prams.mass_corr_alpha = 0.7; // Create FFD solver and domain if (ffd == null) { // Create domain // Pass in the number of cells in x, y and z direction (now including ghost cells) omega = new CavityDomain(Nx + 2, Ny + 2, Nz + 2); ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_prams); de = new DataExtractor(omega, ffd); t = 0; } //reset FFD solver and domain if (resetFFD) { omega = new CavityDomain(Nx + 2, Ny + 2, Nz + 2); ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_prams); de = new DataExtractor(omega, ffd); t = 0; resetFFD = false; } //run solver. the solving-loop (new timestep) is executed in Grasshopper with a timer-component. if (run) { ffd.time_step(f_x, f_y, f_z); } // ******************************************************************************************* // ********************************* Output Results ******************************** double[, ,] p = new double[Nx, Ny, Nz]; double[, ,] vu = new double[Nx, Ny, Nz]; double[, ,] vv = new double[Nx, Ny, Nz]; double[, ,] vw = new double[Nx, Ny, Nz]; double[, ,] pstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[, ,] vustag = new double[Nx + 1, Ny + 1, Nz + 1]; double[, ,] vvstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[, ,] vwstag = new double[Nx + 1, Ny + 1, Nz + 1]; for (int i = 0; i < Nx; i++) { for (int j = 0; j < Ny; j++) { for (int k = 0; k < Nz; k++) { if (omega.obstacle_cells[i + 1, j + 1, k + 1] != 1) { p[i, j, k] = de.get_pressure(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); double[] vel = de.get_velocity(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); vu[i, j, k] = vel[0]; vv[i, j, k] = vel[1]; vw[i, j, k] = vel[2]; pstag[i, j, k] = de.get_pressure(i * omega.hx, j * omega.hy, k * omega.hz); double[] velcen = de.get_velocity(i * omega.hx, j * omega.hy, k * omega.hz); vustag[i, j, k] = velcen[0]; vvstag[i, j, k] = velcen[1]; vwstag[i, k, k] = velcen[2]; } else { p[i, j, k] = 0; vu[i, j, k] = 0; vv[i, j, k] = 0; vw[i, j, k] = 0; //pstag[i, j, k] = 0; //vustag[i, j, k] = 0; //vvstag[i, j, k] = 0; //vwstag[i, k, k] = 0; pstag[i, j, k] = de.get_pressure(i * omega.hx, j * omega.hy, k * omega.hz); double[] velcen = de.get_velocity(i * omega.hx, j * omega.hy, k * omega.hz); vustag[i, j, k] = velcen[0]; vvstag[i, j, k] = velcen[1]; vwstag[i, k, k] = velcen[2]; } } } } //last x slice for (int j = 0; j < Ny + 1; j++) { for (int k = 0; k < Nz + 1; k++) { pstag[Nx, j, k] = de.get_pressure((Nx) * omega.hx, j * omega.hy, k * omega.hz); double[] vcen = de.get_velocity((Nx) * omega.hx, j * omega.hy, k * omega.hz); vustag[Nx, j, k] = vcen[0]; vvstag[Nx, j, k] = vcen[1]; vwstag[Nx, j, k] = vcen[2]; } } //last y slice for (int i = 0; i < Nx + 1; i++) { for (int k = 0; k < Nz + 1; k++) { pstag[i, Ny, k] = de.get_pressure(i * omega.hx, (Ny) * omega.hy, k * omega.hz); double[] vcen = de.get_velocity(i * omega.hx, (Ny) * omega.hy, k * omega.hz); vustag[i, Ny, k] = vcen[0]; vvstag[i, Ny, k] = vcen[1]; vwstag[i, Ny, k] = vcen[2]; } } //last z slice for (int i = 0; i < Nx + 1; i++) { for (int j = 0; j < Ny + 1; j++) { pstag[i, j, Nz] = de.get_pressure(i * omega.hx, j * omega.hy, (Nz) * omega.hz); double[] vcen = de.get_velocity(i * omega.hx, j * omega.hy, (Nz) * omega.hz); vustag[i, j, Nz] = vcen[0]; vvstag[i, j, Nz] = vcen[1]; vwstag[i, j, Nz] = vcen[2]; } } List <double[, , ]> veloutCen = new List <double[, , ]> { }; veloutCen.Add(vu); veloutCen.Add(vv); veloutCen.Add(vw); List <double[, , ]> veloutStag = new List <double[, , ]> { }; veloutStag.Add(vustag); veloutStag.Add(vvstag); veloutStag.Add(vwstag); DA.SetDataList(0, veloutCen); DA.SetData(1, p); DA.SetDataList(2, veloutStag); DA.SetData(3, pstag); List <double> ulist = new List <double>(); List <double> vlist = new List <double>(); //u velocities. (y called) z-section, in the vertical center... x=0.5Nx, y=0.5Ny //(Ny+1) / 2 for (int k = 0; k < Nz + 1; k++) { double[] vcen = de.get_velocity((Nx / 2) * omega.hx + 0.5 * omega.hx, (Ny / 2) * omega.hy + 0.5 * omega.hy, k * omega.hz); ulist.Add(vcen[0]); } for (int i = 0; i < Nx + 1; i++) { double[] vcen = de.get_velocity(i * omega.hx, (Ny / 2) * omega.hy + 0.5 * omega.hy, (Nz / 2) * omega.hz + 0.5 * omega.hz); vlist.Add(vcen[2]); } DA.SetDataList(4, ulist); DA.SetDataList(5, vlist); }
static void Main() { // Set mesh parameters, here we ask for Nx cells in the x direction // Ny cells in the y direction and Nz cells in the z direction (ignoring ghost cells) int Nx = 100; int Ny = 45; int Nz = 30; // Set time step and viscosity double dt = 0.1; double nu = 1e-5; // Set simulation start and finish times double tf = 100; double t = 0; // Set initial conditions double[, ,] u0 = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] v0 = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] w0 = new double[Nx + 2, Ny + 2, Nz + 1]; // Create empty arrays for body forces double[, ,] f_x = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] f_y = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] f_z = new double[Nx + 2, Ny + 2, Nz + 1]; // Create structure for solver parameters FluidSolver.solver_struct solver_prams = new FluidSolver.solver_struct(); solver_prams.tol = 1e-3; solver_prams.min_iter = 1; solver_prams.max_iter = 30; solver_prams.verbose = true; solver_prams.backtrace_order = 2; // Create domain WindInflow omega = new WindInflow(Nx + 2, Ny + 2, Nz + 2, 100, 45, 30); // Add buildings omega.add_obstacle(15, 20, 15, 20, 0, 5); omega.add_obstacle(15, 18, 18, 20, 5, 12); omega.add_obstacle(18, 25, 25, 30, 0, 8); omega.add_obstacle(30, 40, 15, 25, 0, 10); // Create FFD solver FluidSolver ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_prams); // Create post processor and export initial conditions and geometry information PostProcessor pp = new PostProcessor(ffd, omega); int tstep = 0; pp.export_data_vtk(String.Concat("city_test_", tstep, ".vtk"), 0, false); pp.export_geometry_vtk("city_test_geometry.vtk", 0); // Run time loop while (t < tf) { t += dt; tstep++; Console.WriteLine("Time t = {0}", t); // Solve single time step and export results ffd.time_step(f_x, f_y, f_z); pp.export_data_vtk(String.Concat("city_test_", tstep, ".vtk"), t, false); } }
/// <summary> /// Computes L2 and L-infinity error between FFD approximation and exact solution. /// </summary> /// <param name="fs">FluidSolver containing FFD solution at time t</param> /// <pram name="omega">Domain on which exact solution is given</pram> /// <param name="err_l2">Normalized pointwise L2 error</param> /// <param name="err_inf">Pointwise L-infinity error</param> /// <param name="t">Time</param> /// <param name="component">Component to evaluate</param> /// <remarks>The component to evaluate must be one of: /// 1 for pressure /// 2 for x component of velocity /// 3 for y component of velocity /// 4 for z component of velocity</remarks> public static void calculate_errors(FluidSolver fs, Domain omega, out double err_l2, out double err_inf, double t, int component) { DataExtractor de = new DataExtractor(omega, fs); double nu = fs.nu; int Nx = omega.Nx - 1; int Ny = omega.Ny - 1; int Nz = omega.Nz - 1; double[, ,] err_array = new double[Nx, Ny, Nz]; double[, ,] comp_interp = new double[Nx, Ny, Nz]; double[, ,] zeros = new double[Nx, Ny, Nz]; for (int i = 0; i < Nx; i++) { for (int j = 0; j < Ny; j++) { for (int k = 0; k < Nz; k++) { double x = i * omega.hx; double y = j * omega.hy; double z = k * omega.hz; double[] coordinate = new double[] { x, y, z }; double[] velocity_interp = de.get_velocity(x, y, z); double u_exact, v_exact, w_exact, p_exact; omega.exact_solution(coordinate, nu, t, out u_exact, out v_exact, out w_exact, out p_exact); switch (component) { case 1: comp_interp[i, j, k] = de.get_pressure(x, y, z); err_array[i, j, k] = Math.Abs(de.get_pressure(x, y, z) - p_exact); break; case 2: comp_interp[i, j, k] = velocity_interp[0]; err_array[i, j, k] = Math.Abs(velocity_interp[0] - u_exact); break; case 3: comp_interp[i, j, k] = velocity_interp[1]; err_array[i, j, k] = Math.Abs(velocity_interp[1] - v_exact); break; case 4: comp_interp[i, j, k] = velocity_interp[2]; err_array[i, j, k] = Math.Abs(velocity_interp[2] - w_exact); break; } } } } err_l2 = Utilities.compute_L2_difference(err_array, zeros); //L2 norm of errors err_inf = err_array.Cast <double>().Max(); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { string filepath; Domain omega; FluidSolver ffd; DataExtractor de; double t; bool resetFFD; // current filepath filepath = Path.GetDirectoryName(this.OnPingDocument().FilePath); string residualstxt = filepath + @"\\residual.txt"; // ********************************************************************************* // Inputs // ********************************************************************************* List <double> xyzsize = new List <double>(); if (!DA.GetDataList(0, xyzsize)) { return; } ; List <int> Nxyz = new List <int>(); if (!DA.GetDataList(1, Nxyz)) { return; } ; int Nx = Nxyz[0]; int Ny = Nxyz[1]; int Nz = Nxyz[2]; List <double[]> geom = new List <double[]>(); if (!DA.GetDataList(2, geom)) { return; } ; // time step double dt = 0.1; if (!DA.GetData(3, ref dt)) { return; } // horizon double t_end = 1; if (!DA.GetData(4, ref t_end)) { return; } // wind speed double Vmet = 10; if (!DA.GetData(5, ref Vmet)) { return; } //terrain type int terrain = 0; if (!DA.GetData(6, ref terrain)) { return; } bool run = false; if (!DA.GetData(7, ref run)) { return; } //List<Mesh> mshCp = new List<Mesh>(); //DA.GetDataList(10, mshCp); bool writeresults = false; DA.GetData(8, ref writeresults); bool writeVTK = false; DA.GetData(9, ref writeVTK); //DA.GetData(10, ref resetFFD); bool calcres = false; DA.GetData(12, ref calcres); int m = 10; DA.GetData(13, ref m); string strparam = null; DA.GetData(11, ref strparam); string[] str_params = null; if (strparam != null) { str_params = strparam.Split(';'); } double nu = 1.511e-5; // increase viscosity to impose turbulence. the higher velocity, the higher visc., 1e-3 FluidSolver.solver_struct solver_params = new FluidSolver.solver_struct(); double z0; if (str_params != null) { nu = Convert.ToDouble(str_params[0]); solver_params.tol = Convert.ToDouble(str_params[1]); solver_params.min_iter = Convert.ToInt16(str_params[2]); solver_params.max_iter = Convert.ToInt16(str_params[3]); solver_params.backtrace_order = Convert.ToInt16(str_params[4]); solver_params.mass_correction = str_params[5].Equals("false") ? false : true; solver_params.mass_corr_alpha = Convert.ToDouble(str_params[6]); solver_params.verbose = str_params[7].Equals("false") ? false : true; z0 = Convert.ToDouble(str_params[8]); } else { solver_params.tol = 1e-4; solver_params.min_iter = 1; solver_params.max_iter = 30; solver_params.backtrace_order = 2; solver_params.mass_correction = false; solver_params.mass_corr_alpha = 0.7; solver_params.verbose = false; z0 = 0.1; } // ********************************************************************************* // Set-up FFD Solver // ********************************************************************************* // Set initial velocity conditions double[,,] u0 = new double[Nx + 1, Ny + 2, Nz + 2]; double[,,] v0 = new double[Nx + 2, Ny + 1, Nz + 2]; double[,,] w0 = new double[Nx + 2, Ny + 2, Nz + 1]; // Create empty arrays for body forces double[,,] f_x = new double[Nx + 1, Ny + 2, Nz + 2]; double[,,] f_y = new double[Nx + 2, Ny + 1, Nz + 2]; double[,,] f_z = new double[Nx + 2, Ny + 2, Nz + 1]; // Create FFD solver and domain //if (ffd == null || resetFFD) //{ if (terrain == 4) { omega = new WindInflowOpenFoam(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2], Vmet, z0); } else { omega = new WindInflow(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2], Vmet, terrain); } foreach (double[] geo in geom) { omega.add_obstacle(geo[0], geo[1], geo[2], geo[3], geo[4], geo[5]); } ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_params); de = new DataExtractor(omega, ffd); t = 0; PostProcessor pp = new PostProcessor(ffd, omega); //if (resetFFD) resetFFD = false; //reset FFD solver and domain Rhino.RhinoApp.WriteLine("GRASSHOPPER FFD Air Flow Simulation."); Rhino.RhinoApp.WriteLine("GH Plug-in: https://github.com/christophwaibel/GH_Wind"); Rhino.RhinoApp.WriteLine("FFD Solver: https://github.com/lukasbystricky/GSoC_FFD"); Rhino.RhinoApp.WriteLine("________________________________________________________"); Rhino.RhinoApp.WriteLine("...Domain initialized"); Rhino.RhinoApp.WriteLine("________________________________________________________"); //} // ******************************************************************************************* // Run each time GH is updated // ******************************************************************************************* //run solver. the solving-loop (new timestep) is executed in Grasshopper with a timer-component. //!!!!!!!!!!!!!!! CHANGE if (run) { if (writeVTK) { pp.export_geometry_vtk(filepath + @"\\vtk_geometry.vtk", 0); } int counter = 0; int timestep = 0; FluidSolver[] ffd_old = new FluidSolver[m]; if (calcres) { File.AppendAllText(residualstxt, "pmin; pmax; pavg; umin; umax; uavg; vmin; vmax; vavg; wmin; wmax; wavg;\n"); } while (t < t_end) { Rhino.RhinoApp.WriteLine(Convert.ToString(t) + " of " + Convert.ToString(t_end)); double[,,] p_t2 = new double[ffd.p.GetLength(0), ffd.p.GetLength(1), ffd.p.GetLength(2)]; Array.Copy(ffd.p, 0, p_t2, 0, ffd.p.Length); double[,,] u_t2 = new double[ffd.u.GetLength(0), ffd.u.GetLength(1), ffd.u.GetLength(2)]; Array.Copy(ffd.u, 0, u_t2, 0, ffd.u.Length); double[,,] v_t2 = new double[ffd.v.GetLength(0), ffd.v.GetLength(1), ffd.v.GetLength(2)]; Array.Copy(ffd.v, 0, v_t2, 0, ffd.v.Length); double[,,] w_t2 = new double[ffd.w.GetLength(0), ffd.w.GetLength(1), ffd.w.GetLength(2)]; Array.Copy(ffd.w, 0, w_t2, 0, ffd.w.Length); ffd.time_step(f_x, f_y, f_z); if (t > dt && calcres) { double[] p_residuals; double[,,] p_t1 = ffd.p; FastFluidSolverMT.Utilities.calculate_residuals(p_t1, p_t2, out p_residuals); Rhino.RhinoApp.WriteLine("p residuals: {0};{1};{2}", p_residuals[0], p_residuals[1], p_residuals[2]); double[] u_residuals; double[,,] u_t1 = ffd.u; FastFluidSolverMT.Utilities.calculate_residuals(u_t1, u_t2, out u_residuals); Rhino.RhinoApp.WriteLine("u residuals: {0};{1};{2}", u_residuals[0], u_residuals[1], u_residuals[2]); double[] v_residuals; double[,,] v_t1 = ffd.v; FastFluidSolverMT.Utilities.calculate_residuals(v_t1, v_t2, out v_residuals); Rhino.RhinoApp.WriteLine("v residuals: {0};{1};{2}", v_residuals[0], v_residuals[1], v_residuals[2]); double[] w_residuals; double[,,] w_t1 = ffd.w; FastFluidSolverMT.Utilities.calculate_residuals(w_t1, w_t2, out w_residuals); Rhino.RhinoApp.WriteLine("w residuals: {0};{1};{2}", w_residuals[0], w_residuals[1], w_residuals[2]); File.AppendAllText(residualstxt, Convert.ToString(p_residuals[0]) + ";" + Convert.ToString(p_residuals[1]) + ";" + Convert.ToString(p_residuals[2]) + ";" + Convert.ToString(u_residuals[0]) + ";" + Convert.ToString(u_residuals[1]) + ";" + Convert.ToString(u_residuals[2]) + ";" + Convert.ToString(v_residuals[0]) + ";" + Convert.ToString(v_residuals[1]) + ";" + Convert.ToString(v_residuals[2]) + ";" + Convert.ToString(w_residuals[0]) + ";" + Convert.ToString(w_residuals[1]) + ";" + Convert.ToString(w_residuals[2]) + "\n"); } if (t >= t_end - m * dt) { ffd_old[counter] = new FluidSolver(ffd); counter++; } if (writeVTK) { pp.export_data_vtk(filepath + @"\\vtk_" + timestep + ".vtk", t, false); } t += dt; timestep++; } //averaging results FluidSolver ffd_mean = new FluidSolver(ffd); ffd_mean.p = new double[ffd.p.GetLength(0), ffd.p.GetLength(1), ffd.p.GetLength(2)]; ffd_mean.u = new double[ffd.u.GetLength(0), ffd.u.GetLength(1), ffd.u.GetLength(2)]; ffd_mean.v = new double[ffd.v.GetLength(0), ffd.v.GetLength(1), ffd.v.GetLength(2)]; ffd_mean.w = new double[ffd.w.GetLength(0), ffd.w.GetLength(1), ffd.w.GetLength(2)]; for (int i = 0; i < ffd_mean.p.GetLength(0); i++) { for (int j = 0; j < ffd_mean.p.GetLength(1); j++) { for (int k = 0; k < ffd_mean.p.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.p[i, j, k] += ffd_old[u].p[i, j, k]; } ffd_mean.p[i, j, k] /= counter; } } } for (int i = 0; i < ffd_mean.u.GetLength(0); i++) { for (int j = 0; j < ffd_mean.u.GetLength(1); j++) { for (int k = 0; k < ffd_mean.u.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.u[i, j, k] += ffd_old[u].u[i, j, k]; } ffd_mean.u[i, j, k] /= counter; } } } for (int i = 0; i < ffd_mean.v.GetLength(0); i++) { for (int j = 0; j < ffd_mean.v.GetLength(1); j++) { for (int k = 0; k < ffd_mean.v.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.v[i, j, k] += ffd_old[u].v[i, j, k]; } ffd_mean.v[i, j, k] /= counter; } } } for (int i = 0; i < ffd_mean.w.GetLength(0); i++) { for (int j = 0; j < ffd_mean.w.GetLength(1); j++) { for (int k = 0; k < ffd_mean.w.GetLength(2); k++) { for (int u = 0; u < counter; u++) { ffd_mean.w[i, j, k] += ffd_old[u].w[i, j, k]; } ffd_mean.w[i, j, k] /= counter; } } } de = new DataExtractor(omega, ffd_mean); } // ******************************************************************************************* // ******************************************************************************************* // TO DO: vtk export // pp.export_data_vtk(String.Concat("lid_driven_cavity_", tstep, ".vtk"), Nx, Ny, Nz, tstep ); //bool run2 = (bool)Component.Params.Input[5].Sources[0].VolatileData; //while (true) // ******************************************************************************************* // Redraw on or off // ******************************************************************************************* //return mean over m*dt, instead of only one snapshot if (writeresults) { //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // I could move all this away, an only output de data extractor double[,,] p = new double[Nx, Ny, Nz]; double[,,] vu = new double[Nx, Ny, Nz]; double[,,] vv = new double[Nx, Ny, Nz]; double[,,] vw = new double[Nx, Ny, Nz]; double[,,] pstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[,,] vustag = new double[Nx + 1, Ny + 1, Nz + 1]; double[,,] vvstag = new double[Nx + 1, Ny + 1, Nz + 1]; double[,,] vwstag = new double[Nx + 1, Ny + 1, Nz + 1]; for (int i = 0; i < Nx; i++) { for (int j = 0; j < Ny; j++) { for (int k = 0; k < Nz; k++) { if (omega.obstacle_cells[i + 1, j + 1, k + 1] != 1) { p[i, j, k] = de.get_pressure(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); double[] vel = de.get_velocity(i * omega.hx + 0.5 * omega.hx, j * omega.hy + 0.5 * omega.hy, k * omega.hz + 0.5 * omega.hz); vu[i, j, k] = vel[0]; vv[i, j, k] = vel[1]; vw[i, j, k] = vel[2]; } else { p[i, j, k] = 0; vu[i, j, k] = 0; vv[i, j, k] = 0; vw[i, j, k] = 0; } pstag[i, j, k] = de.get_pressure(i * omega.hx, j * omega.hy, k * omega.hz); double[] velcen = de.get_velocity(i * omega.hx, j * omega.hy, k * omega.hz); vustag[i, j, k] = velcen[0]; vvstag[i, j, k] = velcen[1]; vwstag[i, j, k] = velcen[2]; } } } //last x slice for (int j = 0; j < Ny + 1; j++) { for (int k = 0; k < Nz + 1; k++) { pstag[Nx, j, k] = de.get_pressure((Nx) * omega.hx, j * omega.hy, k * omega.hz); double[] vcen = de.get_velocity((Nx) * omega.hx, j * omega.hy, k * omega.hz); vustag[Nx, j, k] = vcen[0]; vvstag[Nx, j, k] = vcen[1]; vwstag[Nx, j, k] = vcen[2]; } } //last y slice for (int i = 0; i < Nx + 1; i++) { for (int k = 0; k < Nz + 1; k++) { pstag[i, Ny, k] = de.get_pressure(i * omega.hx, (Ny) * omega.hy, k * omega.hz); double[] vcen = de.get_velocity(i * omega.hx, (Ny) * omega.hy, k * omega.hz); vustag[i, Ny, k] = vcen[0]; vvstag[i, Ny, k] = vcen[1]; vwstag[i, Ny, k] = vcen[2]; } } //last z slice for (int i = 0; i < Nx + 1; i++) { for (int j = 0; j < Ny + 1; j++) { pstag[i, j, Nz] = de.get_pressure(i * omega.hx, j * omega.hy, (Nz) * omega.hz); double[] vcen = de.get_velocity(i * omega.hx, j * omega.hy, (Nz) * omega.hz); vustag[i, j, Nz] = vcen[0]; vvstag[i, j, Nz] = vcen[1]; vwstag[i, j, Nz] = vcen[2]; } } List <double[, , ]> veloutCen = new List <double[, , ]> { }; veloutCen.Add(vu); veloutCen.Add(vv); veloutCen.Add(vw); List <double[, , ]> veloutStag = new List <double[, , ]> { }; veloutStag.Add(vustag); veloutStag.Add(vvstag); veloutStag.Add(vwstag); DA.SetDataList(0, veloutCen); DA.SetData(1, p); DA.SetDataList(2, veloutStag); DA.SetData(3, pstag); DA.SetData(4, de); DA.SetData(5, omega.obstacle_cells); } }
void Start() { solver = GameObject.Find("fluids").GetComponent("FluidSolver") as FluidSolver; t = this.transform; c = solver.collider; }
static void Main() { const double EPS = 1e-8; // This test varies dt and viscosity while keeping N fixed int N = 64; double[] dt = new double[] { 1.0 / 50, 1.0 / 100, 1.0 / 200, 1.0 / 400 }; double[] nu = new double[] { 1, 0.1, 0.01, 0.001 }; String fname = "convergence_h64_t.txt"; // Constants needed for exact solution double a = 1.25; double d = 2.25; double tf = 1.0 / 10; // Create structure for solver parameters FluidSolver.solver_struct solver_prams = new FluidSolver.solver_struct(); solver_prams.tol = 1e-5; solver_prams.min_iter = 1; solver_prams.max_iter = 20; solver_prams.verbose = false; solver_prams.backtrace_order = 2; using (StreamWriter sw = new StreamWriter(fname)) { // Loop over viscosities for (int r = 0; r < nu.Length; r++) { sw.WriteLine("nu = {0}", nu[r]); // Loop over time step sizes for (int n = 0; n < dt.Length; n++) { Console.WriteLine("Starting simulation for dt = {0} and nu = {1}", dt[n], nu[r]); sw.WriteLine("N dt err_l2_u err_l2_v err_l2_w err_l2_p " + "err_inf_u err_inf_v err_inf_w err_inf_p"); double t = 0; int Nx, Ny, Nz; Nx = Ny = Nz = N; double err_l2_u, err_l2_v, err_l2_w, err_l2_p; double err_inf_u, err_inf_v, err_inf_w, err_inf_p; double hx = 1.0 / Nx; double hy = 1.0 / Ny; double hz = 1.0 / Nz; /***************************************************************************************** * Set up initial conditions *****************************************************************************************/ double[, ,] u0 = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] v0 = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] w0 = new double[Nx + 2, Ny + 2, Nz + 1]; double[, ,] f_x = new double[Nx + 1, Ny + 2, Nz + 2]; double[, ,] f_y = new double[Nx + 2, Ny + 1, Nz + 2]; double[, ,] f_z = new double[Nx + 2, Ny + 2, Nz + 1]; for (int i = 0; i < Nx + 1; i++) { for (int j = 0; j < Ny + 2; j++) { for (int k = 0; k < Nz + 2; k++) { double x = i * hx; double y = (j - 0.5) * hy; double z = (k - 0.5) * hz; u0[i, j, k] = -a * (Math.Exp(a * x) * Math.Sin(a * y + d * z) + Math.Exp(a * z) * Math.Cos(a * x + d * y)); } } } for (int i = 0; i < Nx + 2; i++) { for (int j = 0; j < Ny + 1; j++) { for (int k = 0; k < Nz + 2; k++) { double x = (i - 0.5) * hx; double y = j * hy; double z = (k - 0.5) * hz; v0[i, j, k] = -a * (Math.Exp(a * y) * Math.Sin(a * z + d * x) + Math.Exp(a * x) * Math.Cos(a * y + d * z)); } } } for (int i = 0; i < Nx + 2; i++) { for (int j = 0; j < Ny + 2; j++) { for (int k = 0; k < Nz + 1; k++) { double x = (i - 0.5) * hx; double y = (j - 0.5) * hy; double z = k * hz; w0[i, j, k] = -a * (Math.Exp(a * z) * Math.Sin(a * x + d * y) + Math.Exp(a * y) * Math.Cos(a * z + d * x)); } } } // Create domain EthierSteinmanDomain omega = new EthierSteinmanDomain(Nx + 2, Ny + 2, Nz + 2, nu[r], a, d); // Create FFD solver FluidSolver ffd = new FluidSolver(omega, dt[n], nu[r], u0, v0, w0, solver_prams); /******************************************************************************** * Run time loop **********************************************************************************/ while (Math.Abs(t - tf) > EPS) { t += dt[n]; Console.WriteLine("Time t = {0}", t); // Update boundary conditions and solve single time step omega.update_boundary_conditions(t); ffd.time_step(f_x, f_y, f_z); } /************************************************************************************* * Caclulate errors ************************************************************************************/ Utilities.calculate_errors(ffd, omega, out err_l2_u, out err_inf_u, t, 2); Utilities.calculate_errors(ffd, omega, out err_l2_v, out err_inf_v, t, 3); Utilities.calculate_errors(ffd, omega, out err_l2_w, out err_inf_w, t, 4); Utilities.calculate_errors(ffd, omega, out err_l2_p, out err_inf_p, t, 1); Console.WriteLine("u : L2 error = {0}, L infinity error = {1}", err_l2_u, err_inf_u); Console.WriteLine("v : L2 error = {0}, L infinity error = {1}", err_l2_v, err_inf_v); Console.WriteLine("w : L2 error = {0}, L infinity error = {1}", err_l2_w, err_inf_w); Console.WriteLine("p : L2 error = {0}, L infinity error = {1}", err_l2_p, err_inf_p); sw.WriteLine("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9}", N, dt[n], err_l2_u, err_l2_v, err_l2_w, err_l2_p, err_inf_u, err_inf_v, err_inf_w, err_inf_p); sw.Flush(); } sw.WriteLine(); } } }
/// <summary> /// Constructor /// </summary> /// <param name="omega">Domain</param> /// <param name="fs">FFD simulation</param> public DataExtractor(Domain omega, FluidSolver fs) { this.omega = omega; this.fs = fs; }
public bool Run() { if (xyzsize.Count == 0) { Rhino.RhinoApp.WriteLine($"\n[{id}] - Error\n"); return(false); } run = true; counter = 0; timestep = 0; double nu = 1.511e-5; // increase viscosity to impose turbulence. the higher velocity, the higher visc., 1e-3 FluidSolver.solver_struct solver_params = new FluidSolver.solver_struct(); double z0; if (str_params != null) { nu = Convert.ToDouble(str_params[0]); solver_params.tol = Convert.ToDouble(str_params[1]); solver_params.min_iter = Convert.ToInt16(str_params[2]); solver_params.max_iter = Convert.ToInt16(str_params[3]); solver_params.backtrace_order = Convert.ToInt16(str_params[4]); solver_params.mass_correction = str_params[5].Equals("false") ? false : true; solver_params.mass_corr_alpha = Convert.ToDouble(str_params[6]); solver_params.verbose = str_params[7].Equals("false") ? false : true; z0 = Convert.ToDouble(str_params[8]); } else { solver_params.tol = 1e-4; solver_params.min_iter = 1; solver_params.max_iter = 30; solver_params.backtrace_order = 2; solver_params.mass_correction = false; solver_params.mass_corr_alpha = 0.7; solver_params.verbose = false; z0 = 0.1; } // ********************************************************************************* // Set-up FFD Solver // ********************************************************************************* // Set initial velocity conditions u0 = new double[Nx + 1, Ny + 2, Nz + 2]; v0 = new double[Nx + 2, Ny + 1, Nz + 2]; w0 = new double[Nx + 2, Ny + 2, Nz + 1]; // Create empty arrays for body forces f_x = new double[Nx + 1, Ny + 2, Nz + 2]; f_y = new double[Nx + 2, Ny + 1, Nz + 2]; f_z = new double[Nx + 2, Ny + 2, Nz + 1]; // Create FFD solver and domain //if (ffd == null || resetFFD) //{ //Rhino.RhinoApp.WriteLine($"{id} - "+ "{0}, {1}, {2}", xyzsize[0], xyzsize[1], xyzsize[2]); if (terrain == 4) { omega = new WindInflowOpenFoam(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2], Vmet, z0); } else { omega = new WindInflow(Nx + 2, Ny + 2, Nz + 2, xyzsize[0], xyzsize[1], xyzsize[2], Vmet, terrain); } foreach (double[] geo in geom) { omega.add_obstacle(geo[0], geo[1], geo[2], geo[3], geo[4], geo[5]); } ffd = new FluidSolver(omega, dt, nu, u0, v0, w0, solver_params); de = new DataExtractor(omega, ffd); t = 0; pp = new PostProcessor(ffd, omega); if (id == 0) { Rhino.RhinoApp.WriteLine($"[{id+1}/{maxSolvers}] - " + "GRASSHOPPER FFD Air Flow Simulation."); Rhino.RhinoApp.WriteLine($"[{id+1}/{maxSolvers}] - " + "GH Plug-in: https://github.com/christophwaibel/GH_Wind"); Rhino.RhinoApp.WriteLine($"[{id+1}/{maxSolvers}] - " + "FFD Solver: https://github.com/lukasbystricky/GSoC_FFD"); //Rhino.RhinoApp.WriteLine($"[{id+1}/{maxSolvers}] - " + "________________________________________________________"); //Rhino.RhinoApp.WriteLine($"[{id+1}/{maxSolvers}] - " + "...Domain initialized"); //Rhino.RhinoApp.WriteLine($"[{id+1}/{maxSolvers}] - " + "________________________________________________________"); } if (run) { if (writeVTK) { pp.export_geometry_vtk(filepath + @"\\vtk_geometry.vtk", 0); } counter = 0; timestep = 0; ffd_old = new FluidSolver[m]; //watch.Start(); //startTime = DateTime.Now; while (t < t_end) { if (run != true) { break; } RunStep(ref timestep, ref counter); } //watch.Stop(); } UpdateOutput(); Rhino.RhinoApp.WriteLine($"[{id+1}/{maxSolvers}] Updated output"); return(true); //returns to the task manager and updates GH component }