int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("GAMM-channel.mesh", &mesh); // Perform initial mesh refinements. mesh.refine_towards_boundary(BDY_SOLID_WALL_BOTTOM, 1); for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); mesh.refine_towards_boundary(BDY_SOLID_WALL_BOTTOM, 1); // Initialize boundary condition types and spaces with default shapesets. L2Space space_rho(&mesh, P_INIT); L2Space space_rho_v_x(&mesh, P_INIT); L2Space space_rho_v_y(&mesh, P_INIT); L2Space space_e(&mesh, P_INIT); int ndof = Space::get_num_dofs(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); info("ndof: %d", ndof); // Initialize solutions, set initial conditions. InitialSolutionEulerDensity prev_rho(&mesh, RHO_EXT); InitialSolutionEulerDensityVelX prev_rho_v_x(&mesh, RHO_EXT * V1_EXT); InitialSolutionEulerDensityVelY prev_rho_v_y(&mesh, RHO_EXT * V2_EXT); InitialSolutionEulerDensityEnergy prev_e(&mesh, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); // Numerical flux. OsherSolomonNumericalFlux num_flux(KAPPA); // Initialize weak formulation. EulerEquationsWeakFormImplicitMultiComponent wf(&num_flux, KAPPA, RHO_EXT, V1_EXT, V2_EXT, P_EXT, BDY_SOLID_WALL_BOTTOM, BDY_SOLID_WALL_TOP, BDY_INLET, BDY_OUTLET, &prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, PRECONDITIONING); wf.set_time_step(time_step); // Initialize the FE problem. bool is_linear = false; DiscreteProblem dp(&wf, Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), is_linear); // If the FE problem is in fact a FV problem. if(P_INIT == 0) dp.set_fvm(); // Project the initial solution on the FE space // in order to obtain initial vector for NOX. info("Projecting initial solution on the FE mesh."); scalar* coeff_vec = new scalar[Space::get_num_dofs(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e))]; OGProjection::project_global(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), coeff_vec); // Filters for visualization of Mach number, pressure and entropy. MachNumberFilter Mach_number(Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); PressureFilter pressure(Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); EntropyFilter entropy(Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA, RHO_EXT, P_EXT); ScalarView pressure_view("Pressure", new WinGeom(0, 0, 600, 300)); ScalarView Mach_number_view("Mach number", new WinGeom(700, 0, 600, 300)); ScalarView entropy_production_view("Entropy estimate", new WinGeom(0, 400, 600, 300)); /* ScalarView s1("1", new WinGeom(0, 0, 600, 300)); ScalarView s2("2", new WinGeom(700, 0, 600, 300)); ScalarView s3("3", new WinGeom(0, 400, 600, 300)); ScalarView s4("4", new WinGeom(700, 400, 600, 300)); */ // Initialize NOX solver. NoxSolver solver(&dp, NOX_MESSAGE_TYPE); solver.set_ls_tolerance(NOX_LINEAR_TOLERANCE); solver.disable_abs_resid(); solver.set_conv_rel_resid(NOX_NONLINEAR_TOLERANCE); if(PRECONDITIONING) { RCP<Precond> pc = rcp(new MlPrecond("sa")); solver.set_precond(pc); } int iteration = 0; double t = 0; for(t = 0.0; t < 3.0; t += time_step) { info("---- Time step %d, time %3.5f.", iteration++, t); OGProjection::project_global(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), coeff_vec); solver.set_init_sln(coeff_vec); info("Assembling by DiscreteProblem, solving by NOX."); if (solver.solve()) Solution::vector_to_solutions(solver.get_solution(), Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<Solution *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); else error("NOX failed."); // Visualization. if((iteration - 1) % EVERY_NTH_STEP == 0) { // Hermes visualization. if(HERMES_VISUALIZATION) { Mach_number.reinit(); pressure.reinit(); entropy.reinit(); pressure_view.show(&pressure); entropy_production_view.show(&entropy); Mach_number_view.show(&Mach_number); /* s1.show(&prev_rho); s2.show(&prev_rho_v_x); s3.show(&prev_rho_v_y); s4.show(&prev_e); */ } // Output solution in VTK format. if(VTK_VISUALIZATION) { pressure.reinit(); Mach_number.reinit(); Linearizer lin; char filename[40]; sprintf(filename, "pressure-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", false); sprintf(filename, "pressure-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", true); sprintf(filename, "Mach number-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", false); sprintf(filename, "Mach number-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", true); } } info("Number of nonlin iterations: %d (norm of residual: %g)", solver.get_num_iters(), solver.get_residual()); info("Total number of iterations in linsolver: %d (achieved tolerance in the last step: %g)", solver.get_num_lin_iters(), solver.get_achieved_tol()); } pressure_view.close(); entropy_production_view.close(); Mach_number_view.close(); /* s1.close(); s2.close(); s3.close(); s4.close(); */ return 0; }
int main() { // Create coarse mesh, set Dirichlet BC, enumerate // basis functions Mesh *mesh = new Mesh(A, B, N_elem, P_init, N_eq); mesh->set_bc_left_dirichlet(0, Val_dir_left); mesh->set_bc_right_dirichlet(0, Val_dir_right); mesh->assign_dofs(); // Create discrete problem on coarse mesh DiscreteProblem *dp = new DiscreteProblem(); dp->add_matrix_form(0, 0, jacobian); dp->add_vector_form(0, residual); // Convergence graph wrt. the number of degrees of freedom GnuplotGraph graph; graph.set_log_y(); graph.set_captions("Convergence History", "Degrees of Freedom", "Error"); graph.add_row("exact error [%]", "k", "-", "o"); graph.add_row("max FTR error", "k", "--"); // Main adaptivity loop int adapt_iterations = 1; double ftr_errors[MAX_ELEM_NUM]; // This array decides what // elements will be refined. ElemPtr2 ref_ftr_pairs[MAX_ELEM_NUM]; // To store element pairs from the // FTR solution. Decides how // elements will be hp-refined. for (int i=0; i < MAX_ELEM_NUM; i++) { ref_ftr_pairs[i][0] = new Element(); ref_ftr_pairs[i][1] = new Element(); } while(1) { printf("============ Adaptivity step %d ============\n", adapt_iterations); printf("N_dof = %d\n", mesh->get_n_dof()); // Newton's loop on coarse mesh newton(dp, mesh, NULL, NEWTON_TOL_COARSE, NEWTON_MAXITER); // For every element perform its fast trial refinement (FTR), // calculate the norm of the difference between the FTR // solution and the coarse mesh solution, and store the // error in the ftr_errors[] array. int n_elem = mesh->get_n_active_elem(); for (int i=0; i < n_elem; i++) { printf("=== Starting FTR of Elem [%d]\n", i); // Replicate coarse mesh including solution. Mesh *mesh_ref_local = mesh->replicate(); // Perform FTR of element 'i' mesh_ref_local->reference_refinement(i, 1); printf("Elem [%d]: fine mesh created (%d DOF).\n", i, mesh_ref_local->assign_dofs()); // Newton's loop on the FTR mesh newton(dp, mesh_ref_local, NULL, NEWTON_TOL_REF, NEWTON_MAXITER); // Print FTR solution (enumerated) Linearizer *lxx = new Linearizer(mesh_ref_local); char out_filename[255]; sprintf(out_filename, "solution_ref_%d.gp", i); lxx->plot_solution(out_filename); delete lxx; // Calculate norm of the difference between the coarse mesh // and FTR solutions. // NOTE: later we want to look at the difference in some quantity // of interest rather than error in global norm. double err_est_array[MAX_ELEM_NUM]; ftr_errors[i] = calc_error_estimate(NORM, mesh, mesh_ref_local, err_est_array); //printf("Elem [%d]: absolute error (est) = %g\n", i, ftr_errors[i]); // Copy the reference element pair for element 'i' // into the ref_ftr_pairs[i][] array Iterator *I = new Iterator(mesh); Iterator *I_ref = new Iterator(mesh_ref_local); Element *e, *e_ref; while (1) { e = I->next_active_element(); e_ref = I_ref->next_active_element(); if (e->id == i) { e_ref->copy_into(ref_ftr_pairs[e->id][0]); // coarse element 'e' was split in space if (e->level != e_ref->level) { e_ref = I_ref->next_active_element(); e_ref->copy_into(ref_ftr_pairs[e->id][1]); } break; } } delete I; delete I_ref; delete mesh_ref_local; } // If exact solution available, also calculate exact error if (EXACT_SOL_PROVIDED) { // Calculate element errors wrt. exact solution double err_exact_total = calc_error_exact(NORM, mesh, exact_sol); // Calculate the norm of the exact solution // (using a fine subdivision and high-order quadrature) int subdivision = 500; // heuristic parameter int order = 20; // heuristic parameter double exact_sol_norm = calc_solution_norm(NORM, exact_sol, N_eq, A, B, subdivision, order); // Calculate an estimate of the global relative error double err_exact_rel = err_exact_total/exact_sol_norm; //printf("Relative error (exact) = %g %%\n", 100.*err_exact_rel); graph.add_values(0, mesh->get_n_dof(), 100 * err_exact_rel); } // Calculate max FTR error double max_ftr_error = 0; for (int i=0; i < mesh->get_n_active_elem(); i++) { if (ftr_errors[i] > max_ftr_error) max_ftr_error = ftr_errors[i]; } printf("Max FTR error = %g\n", max_ftr_error); // Add entry to DOF convergence graph graph.add_values(1, mesh->get_n_dof(), max_ftr_error); // Decide whether the max. FTR error is sufficiently small if(max_ftr_error < TOL_ERR_FTR) break; // debug if (adapt_iterations >= 1) break; // Returns updated coarse mesh with the last solution on it. adapt(NORM, ADAPT_TYPE, THRESHOLD, ftr_errors, mesh, ref_ftr_pairs); adapt_iterations++; } // Plot meshes, results, and errors adapt_plotting(mesh, ref_ftr_pairs, NORM, EXACT_SOL_PROVIDED, exact_sol); // Save convergence graph graph.save("conv_dof.gp"); printf("Done.\n"); return 1; }
int main(int argc, char* argv[]) { // Load the mesh. MeshSharedPtr mesh(new Mesh); if (USE_XML_FORMAT == true) { MeshReaderH2DXML mloader; Hermes::Mixins::Loggable::Static::info("Reading mesh in XML format."); try { mloader.load("domain.xml", mesh); } catch(Hermes::Exceptions::Exception& e) { e.print_msg(); } } else { MeshReaderH2D mloader; Hermes::Mixins::Loggable::Static::info("Reading mesh in original format."); mloader.load("domain.mesh", mesh); } // Perform initial mesh refinements (optional). for (int i = 0; i < INIT_REF_NUM; i++) mesh->refine_all_elements(); // Initialize the weak formulation. CustomWeakFormPoisson wf("Aluminum", new Hermes1DFunction<double>(LAMBDA_AL), "Copper", new Hermes1DFunction<double>(LAMBDA_CU), new Hermes2DFunction<double>(-VOLUME_HEAT_SRC)); // Initialize essential boundary conditions. DefaultEssentialBCConst<double> bc_essential( Hermes::vector<std::string>("Bottom", "Inner", "Outer", "Left"), FIXED_BDY_TEMP); EssentialBCs<double> bcs(&bc_essential); // Create an H1 space with default shapeset. SpaceSharedPtr<double> space(new H1Space<double>(mesh, &bcs, P_INIT)); int ndof = space->get_num_dofs(); Hermes::Mixins::Loggable::Static::info("ndof = %d", ndof); // Initialize the FE problem. DiscreteProblem<double> dp(&wf, space); // Initialize Newton solver. NewtonSolver<double> newton(&dp); // Perform Newton's iteration. try { // When newton.solve() is used without any parameters, this means that the initial coefficient // vector will be the zero vector, tolerance will be 1e-8, maximum allowed number of iterations // will be 100, and residual will be measured using Euclidean vector norm. newton.solve(); } catch(std::exception& e) { std::cout << e.what(); } // Translate the resulting coefficient vector into a Solution. MeshFunctionSharedPtr<double> sln(new Solution<double>); Solution<double>::vector_to_solution(newton.get_sln_vector(), space, sln); // VTK output. if (VTK_VISUALIZATION) { // Output solution in VTK format. Linearizer lin; bool mode_3D = true; lin.save_solution_vtk(sln, "sln.vtk", "Temperature", mode_3D); Hermes::Mixins::Loggable::Static::info("Solution in VTK format saved to file %s.", "sln.vtk"); // Output mesh and element orders in VTK format. Orderizer ord; ord.save_orders_vtk(space, "ord.vtk"); Hermes::Mixins::Loggable::Static::info("Element orders in VTK format saved to file %s.", "ord.vtk"); } // Visualize the solution. if (HERMES_VISUALIZATION) { ScalarView view("Solution", new WinGeom(0, 0, 440, 350)); // Hermes uses adaptive FEM to approximate higher-order FE solutions with linear // triangles for OpenGL. The second parameter of View::show() sets the error // tolerance for that. Options are HERMES_EPS_LOW, HERMES_EPS_NORMAL (default), // HERMES_EPS_HIGH and HERMES_EPS_VERYHIGH. The size of the graphics file grows // considerably with more accurate representation, so use it wisely. view.show(sln, HERMES_EPS_HIGH); View::wait(); } return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("cathedral.mesh", &mesh); // Perform initial mesh refinements. for(int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); mesh.refine_towards_boundary(bdy_air, INIT_REF_NUM_BDY); // Initialize an H1 space with default shepeset. H1Space space(&mesh, bc_types, essential_bc_values, P_INIT); int ndof = get_num_dofs(&space); info("ndof = %d.", ndof); // Set initial condition. Solution tsln; tsln.set_const(&mesh, T_INIT); // Initialize weak formulation. WeakForm wf; wf.add_matrix_form(bilinear_form<double, double>, bilinear_form<Ord, Ord>); wf.add_matrix_form_surf(bilinear_form_surf<double, double>, bilinear_form_surf<Ord, Ord>, bdy_air); wf.add_vector_form(linear_form<double, double>, linear_form<Ord, Ord>, H2D_ANY, &tsln); wf.add_vector_form_surf(linear_form_surf<double, double>, linear_form_surf<Ord, Ord>, bdy_air); // Initialize the linear problem. LinearProblem lp(&wf, &space); // Initialize matrix solver. Matrix* mat; Vector* rhs; CommonSolver* solver; init_matrix_solver(matrix_solver, ndof, mat, rhs, solver); // Time stepping: int nsteps = (int)(FINAL_TIME/TAU + 0.5); bool rhsonly = false; for(int ts = 1; ts <= nsteps; ts++) { info("---- Time step %d, time %3.5f, ext_temp %g", ts, TIME, temp_ext(TIME)); // Assemble stiffness matrix and rhs. lp.assemble(mat, rhs, rhsonly); rhsonly = true; // Solve the matrix problem. if (!solver->solve(mat, rhs)) error ("Matrix solver failed.\n"); // Update tsln. tsln.set_fe_solution(&space, rhs); if (ts % OUTPUT_FREQUENCY == 0) { Linearizer lin; int item = H2D_FN_VAL_0; double eps = H2D_EPS_NORMAL; double max_abs = -1.0; MeshFunction* xdisp = NULL; MeshFunction* ydisp = NULL; double dmult = 1.0; lin.process_solution(&tsln, item, eps, max_abs, xdisp, ydisp, dmult); char* filename = new char[100]; sprintf(filename, "tsln_%d.lin", ts); // Save Linearizer data. lin.save_data(filename); info("Linearizer data saved to file %s.", filename); // Save complete Solution. sprintf(filename, "tsln_%d.dat", ts); bool compress = false; // Gzip compression not used as it only works on Linux. tsln.save(filename, compress); info("Complete Solution saved to file %s.", filename); } // Update the time variable. TIME += TAU; } info("Let's assume that the remote computation has finished and you fetched the *.lin files."); info("Visualizing Linearizer data from file tsln_40.lin."); // First use ScalarView to read and show the Linearizer data. WinGeom* win_geom_1 = new WinGeom(0, 0, 450, 600); ScalarView sview_1("Saved Linearizer data", win_geom_1); sview_1.lin.load_data("tsln_40.lin"); sview_1.set_min_max_range(0,20); sview_1.fix_scale_width(3); sview_1.show_linearizer_data(); info("Visualizing Solution from file tsln_60.dat."); Solution sln_from_file; sln_from_file.load("tsln_60.dat"); WinGeom* win_geom_2 = new WinGeom(460, 0, 450, 600); ScalarView sview_2("Saved Solution data", win_geom_2); sview_2.set_min_max_range(0,20); sview_2.fix_scale_width(3); sview_2.show(&sln_from_file); info("Visualizing Mesh and Orders extracted from the Solution."); int p_init = 1; // The NULLs are for bc_types() and essential_bc_values(). H1Space space_from_file(sln_from_file.get_mesh(), NULL, NULL, p_init); space_from_file.set_element_orders(sln_from_file.get_element_orders()); WinGeom* win_geom_3 = new WinGeom(920, 0, 450, 600); OrderView oview("Saved Solution -> Space", win_geom_3); oview.show(&space_from_file); // Wait for the view to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { // Instantiate a class with global functions. Hermes2D hermes2d; // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("cathedral.mesh", &mesh); // Perform initial mesh refinements. for(int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); mesh.refine_towards_boundary("Boundary_air", INIT_REF_NUM_BDY); mesh.refine_towards_boundary("Boundary_ground", INIT_REF_NUM_BDY); // Previous time level solution (initialized by the external temperature). Solution tsln(&mesh, TEMP_INIT); // Initialize the weak formulation. double current_time = 0; CustomWeakFormHeatRK1 wf("Boundary_air", ALPHA, LAMBDA, HEATCAP, RHO, time_step, ¤t_time, TEMP_INIT, T_FINAL, &tsln); // Initialize boundary conditions. DefaultEssentialBCConst essential_bc("Boundary_ground", TEMP_INIT); EssentialBCs bcs(&essential_bc); // Initialize an H1 space with default shepeset. H1Space space(&mesh, &bcs, P_INIT); int ndof = Space::get_num_dofs(&space); info("ndof = %d.", ndof); // Initialize the FE problem. DiscreteProblem dp(&wf, &space); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix = create_matrix(matrix_solver); Vector* rhs = create_vector(matrix_solver); Solver* solver = create_linear_solver(matrix_solver, matrix, rhs); solver->set_factorization_scheme(HERMES_REUSE_FACTORIZATION_COMPLETELY); // Initial coefficient vector for the Newton's method. scalar* coeff_vec = new scalar[ndof]; memset(coeff_vec, 0, ndof*sizeof(scalar)); // Initialize views. ScalarView Tview("Temperature", new WinGeom(0, 0, 450, 600)); char title[100]; sprintf(title, "Time %3.5f", current_time); Tview.set_min_max_range(0,20); Tview.set_title(title); Tview.fix_scale_width(3); // Time stepping: int nsteps = (int)(T_FINAL/time_step + 0.5); bool jacobian_changed = true; for(int ts = 1; ts <= nsteps; ts++) { info("---- Time step %d, time %3.5f", ts, current_time); // Perform Newton's iteration. if (!hermes2d.solve_newton(coeff_vec, &dp, solver, matrix, rhs, jacobian_changed)) error("Newton's iteration failed."); jacobian_changed = false; // Translate the resulting coefficient vector into the Solution sln. Solution::vector_to_solution(coeff_vec, &space, &tsln); if (ts % OUTPUT_FREQUENCY == 0) { Linearizer lin; int item = H2D_FN_VAL_0; double eps = HERMES_EPS_NORMAL; double max_abs = -1.0; MeshFunction* xdisp = NULL; MeshFunction* ydisp = NULL; double dmult = 1.0; lin.process_solution(&tsln, item, eps, max_abs, xdisp, ydisp, dmult); char* filename = new char[100]; sprintf(filename, "tsln_%d.lin", ts); // Save Linearizer data. lin.save_data(filename); info("Linearizer data saved to file %s.", filename); // Save complete Solution. sprintf(filename, "tsln_%d.dat", ts); bool compress = false; // Gzip compression not used as it only works on Linux. tsln.save(filename, compress); info("Complete Solution saved to file %s.", filename); } // Update the time variable. current_time += time_step; } info("Let's assume that the remote computation has finished and you fetched the *.lin files."); info("Visualizing Linearizer data from file tsln_40.lin."); // First use ScalarView to read and show the Linearizer data. WinGeom* win_geom_1 = new WinGeom(0, 0, 450, 600); ScalarView sview_1("Saved Linearizer data", win_geom_1); sview_1.lin.load_data("tsln_40.lin"); sview_1.set_min_max_range(0,20); sview_1.fix_scale_width(3); sview_1.show_linearizer_data(); info("Visualizing Solution from file tsln_60.dat."); Solution sln_from_file; sln_from_file.load("tsln_60.dat"); WinGeom* win_geom_2 = new WinGeom(460, 0, 450, 600); ScalarView sview_2("Saved Solution data", win_geom_2); sview_2.set_min_max_range(0,20); sview_2.fix_scale_width(3); sview_2.show(&sln_from_file); info("Visualizing Mesh and Orders extracted from the Solution."); int p_init = 1; H1Space space_from_file(sln_from_file.get_mesh(), p_init); space_from_file.set_element_orders(sln_from_file.get_element_orders()); OrderView oview("Saved Solution -> Space", new WinGeom(920, 0, 450, 600)); oview.show(&space_from_file); // Clean up. delete solver; delete matrix; delete rhs; // Wait for the view to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { Hermes::vector<std::string> BDY_NATURAL_CONCENTRATION; BDY_NATURAL_CONCENTRATION.push_back("4"); // Load the mesh. Mesh basemesh; H2DReader mloader; mloader.load("GAMM-channel.mesh", &basemesh); // Initialize the meshes. Mesh mesh_flow, mesh_concentration; mesh_flow.copy(&basemesh); mesh_concentration.copy(&basemesh); for(unsigned int i = 0; i < INIT_REF_NUM_CONCENTRATION; i++) mesh_concentration.refine_all_elements(); mesh_concentration.refine_towards_boundary(BDY_DIRICHLET_CONCENTRATION, INIT_REF_NUM_CONCENTRATION_BDY); //mesh_flow.refine_towards_boundary(BDY_DIRICHLET_CONCENTRATION, INIT_REF_NUM_CONCENTRATION_BDY); for(unsigned int i = 0; i < INIT_REF_NUM_FLOW; i++) mesh_flow.refine_all_elements(); // Initialize boundary condition types and spaces with default shapesets. // For the concentration. EssentialBCs<double> bcs_concentration; bcs_concentration.add_boundary_condition(new ConcentrationTimedepEssentialBC(BDY_DIRICHLET_CONCENTRATION, CONCENTRATION_EXT, CONCENTRATION_EXT_STARTUP_TIME)); L2Space<double>space_rho(&mesh_flow, P_INIT_FLOW); L2Space<double>space_rho_v_x(&mesh_flow, P_INIT_FLOW); L2Space<double>space_rho_v_y(&mesh_flow, P_INIT_FLOW); L2Space<double>space_e(&mesh_flow, P_INIT_FLOW); // Space<double> for concentration. H1Space<double> space_c(&mesh_concentration, &bcs_concentration, P_INIT_CONCENTRATION); int ndof = Space<double>::get_num_dofs(Hermes::vector<Space<double>*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c)); info("ndof: %d", ndof); // Initialize solutions, set initial conditions. InitialSolutionEulerDensity sln_rho(&mesh_flow, RHO_EXT); InitialSolutionEulerDensityVelX sln_rho_v_x(&mesh_flow, RHO_EXT * V1_EXT); InitialSolutionEulerDensityVelY sln_rho_v_y(&mesh_flow, RHO_EXT * V2_EXT); InitialSolutionEulerDensityEnergy sln_e(&mesh_flow, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); InitialSolutionConcentration sln_c(&mesh_concentration, 0.0); InitialSolutionEulerDensity prev_rho(&mesh_flow, RHO_EXT); InitialSolutionEulerDensityVelX prev_rho_v_x(&mesh_flow, RHO_EXT * V1_EXT); InitialSolutionEulerDensityVelY prev_rho_v_y(&mesh_flow, RHO_EXT * V2_EXT); InitialSolutionEulerDensityEnergy prev_e(&mesh_flow, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); InitialSolutionConcentration prev_c(&mesh_concentration, 0.0); // Numerical flux. OsherSolomonNumericalFlux num_flux(KAPPA); // Initialize weak formulation. EulerEquationsWeakFormImplicitCoupled wf(&num_flux, KAPPA, RHO_EXT, V1_EXT, V2_EXT, P_EXT, BDY_SOLID_WALL_BOTTOM, BDY_SOLID_WALL_TOP, BDY_INLET, BDY_OUTLET, BDY_NATURAL_CONCENTRATION, &prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c, PRECONDITIONING, EPSILON); wf.set_time_step(time_step); // Initialize the FE problem. bool is_linear = false; DiscreteProblem<double> dp(&wf, Hermes::vector<Space<double>*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c)); // Project the initial solution on the FE space // in order to obtain initial vector for NOX. info("Projecting initial solution on the FE mesh."); double* coeff_vec = new double[Space<double>::get_num_dofs(Hermes::vector<Space<double>*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c))]; OGProjection<double>::project_global(Hermes::vector<Space<double>*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c), coeff_vec); // Filters for visualization of Mach number, pressure and entropy. MachNumberFilter Mach_number(Hermes::vector<MeshFunction<double>*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), KAPPA); PressureFilter pressure(Hermes::vector<MeshFunction<double>*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), KAPPA); EntropyFilter entropy(Hermes::vector<MeshFunction<double>*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), KAPPA, RHO_EXT, P_EXT); /* ScalarView<double> pressure_view("Pressure", new WinGeom(0, 0, 600, 300)); ScalarView<double> Mach_number_view("Mach number", new WinGeom(700, 0, 600, 300)); ScalarView<double> entropy_production_view("Entropy estimate", new WinGeom(0, 400, 600, 300)); ScalarView<double> s5("Concentration", new WinGeom(700, 400, 600, 300)); */ ScalarView<double> s1("1", new WinGeom(0, 0, 600, 300)); ScalarView<double> s2("2", new WinGeom(700, 0, 600, 300)); ScalarView<double> s3("3", new WinGeom(0, 400, 600, 300)); ScalarView<double> s4("4", new WinGeom(700, 400, 600, 300)); ScalarView<double> s5("Concentration", new WinGeom(350, 200, 600, 300)); // Initialize NOX solver. NoxSolver<double> solver(&dp); solver.set_ls_tolerance(NOX_LINEAR_TOLERANCE); solver.disable_abs_resid(); solver.set_conv_rel_resid(NOX_NONLINEAR_TOLERANCE); // Set up CFL calculation class. CFLCalculation CFL(CFL_NUMBER, KAPPA); // Set up Advection-Diffusion-Equation stability calculation class. ADEStabilityCalculation ADES(ADVECTION_STABILITY_CONSTANT, DIFFUSION_STABILITY_CONSTANT, EPSILON); // Select preconditioner. if(PRECONDITIONING) { RCP<Precond<double> > pc = rcp(new Preconditioners::MlPrecond<double>("sa")); solver.set_precond(pc); } int iteration = 0; double t = 0; for(t = 0.0; t < 100.0; t += time_step) { info("---- Time step %d, time %3.5f.", iteration++, t); OGProjection<double>::project_global(Hermes::vector<Space<double>*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c), coeff_vec); info("Assembling by DiscreteProblem, solving by NOX."); if (solver.solve(coeff_vec)) Solution<double>::vector_to_solutions(solver.get_sln_vector(), Hermes::vector<Space<double>*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<Solution<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c)); else error("NOX failed."); util_time_step = time_step; CFL.calculate(Hermes::vector<Solution<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), &mesh_flow, util_time_step); time_step = util_time_step; ADES.calculate(Hermes::vector<Solution<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y), &mesh_concentration, util_time_step); if(util_time_step < time_step) time_step = util_time_step; // Visualization. if((iteration - 1) % EVERY_NTH_STEP == 0) { // Hermes visualization. if(HERMES_VISUALIZATION) { /* Mach_number.reinit(); pressure.reinit(); entropy.reinit(); pressure_view.show(&pressure); entropy_production_view.show(&entropy); Mach_number_view.show(&Mach_number); s5.show(&prev_c); */ s1.show(&prev_rho); s2.show(&prev_rho_v_x); s3.show(&prev_rho_v_y); s4.show(&prev_e); s5.show(&prev_c); /* s1.save_numbered_screenshot("density%i.bmp", iteration, true); s2.save_numbered_screenshot("density_v_x%i.bmp", iteration, true); s3.save_numbered_screenshot("density_v_y%i.bmp", iteration, true); s4.save_numbered_screenshot("energy%i.bmp", iteration, true); s5.save_numbered_screenshot("concentration%i.bmp", iteration, true); */ //s5.wait_for_close(); } // Output solution in VTK format. if(VTK_VISUALIZATION) { pressure.reinit(); Mach_number.reinit(); Linearizer<double> lin; char filename[40]; sprintf(filename, "pressure-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", false); sprintf(filename, "pressure-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", true); sprintf(filename, "Mach number-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", false); sprintf(filename, "Mach number-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", true); sprintf(filename, "Concentration-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_c, filename, "Concentration", true); sprintf(filename, "Concentration-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_c, filename, "Concentration", true); } } } /* pressure_view.close(); entropy_production_view.close(); Mach_number_view.close(); s5.close(); */ s1.close(); s2.close(); s3.close(); s4.close(); s5.close(); return 0; }
int main(int argc, char* argv[]) { // Provide a possibility to change INITIAL_CONCENTRATION_STATE through an argument. if(argc > 1) INITIAL_CONCENTRATION_STATE = atoi(argv[1]); if(argc > 2) INIT_REF_NUM_FLOW = atoi(argv[2]); if(argc > 3) INIT_REF_NUM_CONCENTRATION = atoi(argv[3]); if(argc > 4) INIT_REF_NUM_CONCENTRATION_BDY = atoi(argv[4]); // Load the mesh. Mesh basemesh; H2DReader mloader; if(INITIAL_CONCENTRATION_STATE == 1) mloader.load("GAMM-channel-4-bnds.mesh", &basemesh); else mloader.load("channel-4-bnds.mesh", &basemesh); // Initialize the meshes. Mesh mesh_flow, mesh_concentration; mesh_flow.copy(&basemesh); mesh_concentration.copy(&basemesh); for(unsigned int i = 0; i < INIT_REF_NUM_CONCENTRATION; i++) mesh_concentration.refine_all_elements(); if(INITIAL_CONCENTRATION_STATE != 2) mesh_concentration.refine_towards_boundary(3, INIT_REF_NUM_CONCENTRATION_BDY); //mesh_concentration.refine_towards_boundary(1, INIT_REF_NUM_CONCENTRATION_BDY, false); for(unsigned int i = 0; i < INIT_REF_NUM_FLOW; i++) mesh_flow.refine_all_elements(); // Initialize boundary condition types and spaces with default shapesets. BCTypes bc_types_euler; bc_types_euler.add_bc_neumann(Hermes::vector<int>(BDY_SOLID_WALL_TOP, BDY_SOLID_WALL_BOTTOM, BDY_INLET, BDY_OUTLET)); BCTypes bc_types_concentration; BCValues bc_values_concentration; switch(INITIAL_CONCENTRATION_STATE) { case 0: bc_types_concentration.add_bc_neumann(Hermes::vector<int>(BDY_INLET, BDY_OUTLET, BDY_SOLID_WALL_TOP)); bc_types_concentration.add_bc_dirichlet(Hermes::vector<int>(BDY_SOLID_WALL_BOTTOM)); bc_values_concentration.add_const(Hermes::vector<int>(BDY_SOLID_WALL_BOTTOM), CONCENTRATION_EXT); break; case 1: bc_types_concentration.add_bc_neumann(Hermes::vector<int>(BDY_INLET, BDY_OUTLET, BDY_SOLID_WALL_TOP)); bc_types_concentration.add_bc_dirichlet(Hermes::vector<int>(BDY_SOLID_WALL_BOTTOM)); bc_values_concentration.add_const(Hermes::vector<int>(BDY_SOLID_WALL_BOTTOM), CONCENTRATION_EXT); break; case 2: bc_types_concentration.add_bc_neumann(Hermes::vector<int>(BDY_SOLID_WALL_BOTTOM, BDY_OUTLET, BDY_SOLID_WALL_TOP)); bc_types_concentration.add_bc_dirichlet(Hermes::vector<int>(BDY_INLET)); bc_values_concentration.add_const(Hermes::vector<int>(BDY_INLET), CONCENTRATION_EXT); break; } L2Space space_rho(&mesh_flow, &bc_types_euler, P_INIT_FLOW); L2Space space_rho_v_x(&mesh_flow, &bc_types_euler, P_INIT_FLOW); L2Space space_rho_v_y(&mesh_flow, &bc_types_euler, P_INIT_FLOW); L2Space space_e(&mesh_flow, &bc_types_euler, P_INIT_FLOW); // Space for concentration. H1Space space_c(&mesh_concentration, &bc_types_concentration, &bc_values_concentration, P_INIT_CONCENTRATION); // Initialize solutions, set initial conditions. Solution sln_rho, sln_rho_v_x, sln_rho_v_y, sln_e, sln_c, prev_rho, prev_rho_v_x, prev_rho_v_y, prev_e, prev_c; sln_rho.set_exact(&mesh_flow, ic_density); sln_rho_v_x.set_exact(&mesh_flow, ic_density_vel_x); sln_rho_v_y.set_exact(&mesh_flow, ic_density_vel_y); sln_e.set_exact(&mesh_flow, ic_energy); sln_c.set_exact(&mesh_concentration, ic_concentration); prev_rho.set_exact(&mesh_flow, ic_density); prev_rho_v_x.set_exact(&mesh_flow, ic_density_vel_x); prev_rho_v_y.set_exact(&mesh_flow, ic_density_vel_y); prev_e.set_exact(&mesh_flow, ic_energy); prev_c.set_exact(&mesh_concentration, ic_concentration); // Initialize weak formulation. bool is_matrix_free = true; WeakForm wf(5, is_matrix_free); // Volumetric linear forms. wf.add_vector_form(0, callback(linear_form_0_time)); wf.add_vector_form(1, callback(linear_form_1_time)); wf.add_vector_form(2, callback(linear_form_2_time)); wf.add_vector_form(3, callback(linear_form_3_time)); wf.add_vector_form(4, callback(linear_form_4_time)); // Volumetric linear forms. // Linear forms coming from the linearization by taking the Eulerian fluxes' Jacobian matrices // from the previous time step. // Unnecessary for FVM. if(P_INIT_FLOW.order_h > 0 || P_INIT_FLOW.order_v > 0) { // First flux. wf.add_vector_form(0, callback(linear_form_0_1), HERMES_ANY); wf.add_vector_form(1, callback(linear_form_1_0_first_flux), HERMES_ANY); wf.add_vector_form(1, callback(linear_form_1_1_first_flux), HERMES_ANY); wf.add_vector_form(1, callback(linear_form_1_2_first_flux), HERMES_ANY); wf.add_vector_form(1, callback(linear_form_1_3_first_flux), HERMES_ANY); wf.add_vector_form(2, callback(linear_form_2_0_first_flux), HERMES_ANY); wf.add_vector_form(2, callback(linear_form_2_1_first_flux), HERMES_ANY); wf.add_vector_form(2, callback(linear_form_2_2_first_flux), HERMES_ANY); wf.add_vector_form(2, callback(linear_form_2_3_first_flux), HERMES_ANY); wf.add_vector_form(3, callback(linear_form_3_0_first_flux), HERMES_ANY); wf.add_vector_form(3, callback(linear_form_3_1_first_flux), HERMES_ANY); wf.add_vector_form(3, callback(linear_form_3_2_first_flux), HERMES_ANY); wf.add_vector_form(3, callback(linear_form_3_3_first_flux), HERMES_ANY); // Second flux. wf.add_vector_form(0, callback(linear_form_0_2), HERMES_ANY); wf.add_vector_form(1, callback(linear_form_1_0_second_flux), HERMES_ANY); wf.add_vector_form(1, callback(linear_form_1_1_second_flux), HERMES_ANY); wf.add_vector_form(1, callback(linear_form_1_2_second_flux), HERMES_ANY); wf.add_vector_form(1, callback(linear_form_1_3_second_flux), HERMES_ANY); wf.add_vector_form(2, callback(linear_form_2_0_second_flux), HERMES_ANY); wf.add_vector_form(2, callback(linear_form_2_1_second_flux), HERMES_ANY); wf.add_vector_form(2, callback(linear_form_2_2_second_flux), HERMES_ANY); wf.add_vector_form(2, callback(linear_form_2_3_second_flux), HERMES_ANY); wf.add_vector_form(3, callback(linear_form_3_0_second_flux), HERMES_ANY); wf.add_vector_form(3, callback(linear_form_3_1_second_flux), HERMES_ANY); wf.add_vector_form(3, callback(linear_form_3_2_second_flux), HERMES_ANY); wf.add_vector_form(3, callback(linear_form_3_3_second_flux), HERMES_ANY); } // Volumetric linear forms coming from the time discretization. wf.add_vector_form(0, linear_form_time, linear_form_order, HERMES_ANY, &prev_rho); wf.add_vector_form(1, linear_form_time, linear_form_order, HERMES_ANY, &prev_rho_v_x); wf.add_vector_form(2, linear_form_time, linear_form_order, HERMES_ANY, &prev_rho_v_y); wf.add_vector_form(3, linear_form_time, linear_form_order, HERMES_ANY, &prev_e); wf.add_vector_form(4, callback(linear_form_time_concentration), HERMES_ANY, &prev_c); // Surface linear forms - inner edges coming from the DG formulation. wf.add_vector_form_surf(0, linear_form_interface_0, linear_form_order, H2D_DG_INNER_EDGE); wf.add_vector_form_surf(1, linear_form_interface_1, linear_form_order, H2D_DG_INNER_EDGE); wf.add_vector_form_surf(2, linear_form_interface_2, linear_form_order, H2D_DG_INNER_EDGE); wf.add_vector_form_surf(3, linear_form_interface_3, linear_form_order, H2D_DG_INNER_EDGE); // Surface linear forms - inlet / outlet edges. wf.add_vector_form_surf(0, bdy_flux_inlet_outlet_comp_0, linear_form_order, BDY_INLET); wf.add_vector_form_surf(1, bdy_flux_inlet_outlet_comp_1, linear_form_order, BDY_INLET); wf.add_vector_form_surf(2, bdy_flux_inlet_outlet_comp_2, linear_form_order, BDY_INLET); wf.add_vector_form_surf(3, bdy_flux_inlet_outlet_comp_3, linear_form_order, BDY_INLET); wf.add_vector_form_surf(0, bdy_flux_inlet_outlet_comp_0, linear_form_order, BDY_OUTLET); wf.add_vector_form_surf(1, bdy_flux_inlet_outlet_comp_1, linear_form_order, BDY_OUTLET); wf.add_vector_form_surf(2, bdy_flux_inlet_outlet_comp_2, linear_form_order, BDY_OUTLET); wf.add_vector_form_surf(3, bdy_flux_inlet_outlet_comp_3, linear_form_order, BDY_OUTLET); // Surface linear forms - Solid wall edges. wf.add_vector_form_surf(0, bdy_flux_solid_wall_comp_0, linear_form_order, BDY_SOLID_WALL_BOTTOM); wf.add_vector_form_surf(1, bdy_flux_solid_wall_comp_1, linear_form_order, BDY_SOLID_WALL_BOTTOM); wf.add_vector_form_surf(2, bdy_flux_solid_wall_comp_2, linear_form_order, BDY_SOLID_WALL_BOTTOM); wf.add_vector_form_surf(3, bdy_flux_solid_wall_comp_3, linear_form_order, BDY_SOLID_WALL_BOTTOM); wf.add_vector_form_surf(0, bdy_flux_solid_wall_comp_0, linear_form_order, BDY_SOLID_WALL_TOP); wf.add_vector_form_surf(1, bdy_flux_solid_wall_comp_1, linear_form_order, BDY_SOLID_WALL_TOP); wf.add_vector_form_surf(2, bdy_flux_solid_wall_comp_2, linear_form_order, BDY_SOLID_WALL_TOP); wf.add_vector_form_surf(3, bdy_flux_solid_wall_comp_3, linear_form_order, BDY_SOLID_WALL_TOP); // Forms for concentration. wf.add_vector_form(4, callback(volume_linear_form_concentration_grad_grad), HERMES_ANY); wf.add_vector_form(4, callback(volume_linear_form_concentration_convective), HERMES_ANY); wf.add_vector_form_surf(4, callback(surface_linear_form_concentration_inlet_outlet), BDY_INLET); wf.add_vector_form_surf(4, callback(surface_linear_form_concentration_inlet_outlet), BDY_OUTLET); wf.add_vector_form_surf(4, callback(surface_linear_form_concentration_solid_wall), BDY_SOLID_WALL_TOP); wf.add_vector_form_surf(4, callback(inner_linear_form_concentration), H2D_DG_INNER_EDGE); if(PRECONDITIONING) { // Preconditioning forms. wf.add_matrix_form(0, 0, callback(bilinear_form_precon)); wf.add_matrix_form(1, 1, callback(bilinear_form_precon)); wf.add_matrix_form(2, 2, callback(bilinear_form_precon)); wf.add_matrix_form(3, 3, callback(bilinear_form_precon)); wf.add_matrix_form(4, 4, callback(bilinear_form_precon)); } // Initialize the FE problem. bool is_linear = false; DiscreteProblem dp(&wf, Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), is_linear); // Project the initial solution on the FE space // in order to obtain initial vector for NOX. info("Projecting initial solution on the FE mesh."); scalar* coeff_vec = new scalar[Space::get_num_dofs(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c))]; OGProjection::project_global(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c), coeff_vec); // Filters for visualization of pressure and the two components of velocity. /* SimpleFilter pressure(calc_pressure_func, Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e)); SimpleFilter u(calc_u_func, Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e)); SimpleFilter w(calc_w_func, Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e)); SimpleFilter Mach_number(calc_Mach_func, Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e)); SimpleFilter entropy_estimate(calc_entropy_estimate_func, Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e)); ScalarView pressure_view("Pressure", new WinGeom(0, 0, 600, 300)); ScalarView Mach_number_view("Mach number", new WinGeom(700, 0, 600, 300)); ScalarView entropy_production_view("Entropy estimate", new WinGeom(0, 400, 600, 300)); VectorView vview("Velocity", new WinGeom(700, 400, 600, 300)); */ ScalarView s1("w0", new WinGeom(0, 0, 600, 300)); ScalarView s2("w1", new WinGeom(700, 0, 600, 300)); ScalarView s3("w2", new WinGeom(0, 400, 600, 300)); ScalarView s4("w3", new WinGeom(700, 400, 600, 300)); ScalarView s5("Concentration", new WinGeom(350, 200, 600, 300)); // Iteration number. int iteration = 0; // Output of the approximate time derivative. std::ofstream time_der_out("time_der"); // Initialize NOX solver. NoxSolver solver(&dp); solver.set_ls_tolerance(1E-2); solver.disable_abs_resid(); solver.set_conv_rel_resid(1.00); // Select preconditioner. if(PRECONDITIONING) { RCP<Precond> pc = rcp(new MlPrecond("sa")); solver.set_precond(pc); } for(t = 0.0; t < 3.0; t += TAU) { info("---- Time step %d, time %3.5f.", iteration++, t); OGProjection::project_global(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c), coeff_vec); info("Assembling by DiscreteProblem, solving by NOX."); solver.set_init_sln(coeff_vec); if (solver.solve()) Solution::vector_to_solutions(solver.get_solution(), Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<Solution *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c)); else error("NOX failed."); /* // Visualization. pressure.reinit(); u.reinit(); w.reinit(); Mach_number.reinit(); entropy_estimate.reinit(); pressure_view.show(&pressure); entropy_production_view.show(&entropy_estimate); Mach_number_view.show(&Mach_number); vview.show(&u, &w); */ info("Number of nonlin iterations: %d (norm of residual: %g)", solver.get_num_iters(), solver.get_residual()); info("Total number of iterations in linsolver: %d (achieved tolerance in the last step: %g)", solver.get_num_lin_iters(), solver.get_achieved_tol()); // Visualization. if((iteration - 1) % EVERY_NTH_STEP == 0) { // Hermes visualization. if(HERMES_VISUALIZATION) { s1.show(&prev_rho); s2.show(&prev_rho_v_x); s3.show(&prev_rho_v_y); s4.show(&prev_e); s5.show(&prev_c); } // Output solution in VTK format. if(VTK_OUTPUT) { Linearizer lin; char filename[40]; sprintf(filename, "w0-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_rho, filename, "w0", false); sprintf(filename, "w1-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_rho_v_x, filename, "w1", false); sprintf(filename, "w2-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_rho_v_y, filename, "w2", false); sprintf(filename, "w3-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_e, filename, "w3", false); sprintf(filename, "concentration-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_c, filename, "concentration", false); } } } s1.close(); s2.close(); s3.close(); s4.close(); s5.close(); time_der_out.close(); return 0; }
int main(int argc, char* argv[]) { Hermes::vector<std::string> BDY_NATURAL_CONCENTRATION; BDY_NATURAL_CONCENTRATION.push_back("2"); std::ofstream time_step_out("time_step"); // Load the mesh. Mesh basemesh; H2DReader mloader; mloader.load("GAMM-channel.mesh", &basemesh); // Initialize the meshes. Mesh mesh_flow, mesh_concentration; mesh_flow.copy(&basemesh); mesh_concentration.copy(&basemesh); for(unsigned int i = 0; i < INIT_REF_NUM_CONCENTRATION; i++) mesh_concentration.refine_all_elements(0, true); mesh_concentration.refine_towards_boundary(BDY_DIRICHLET_CONCENTRATION, INIT_REF_NUM_CONCENTRATION_BDY, true); //mesh_flow.refine_towards_boundary(BDY_DIRICHLET_CONCENTRATION, INIT_REF_NUM_CONCENTRATION_BDY); for(unsigned int i = 0; i < INIT_REF_NUM_FLOW; i++) mesh_flow.refine_all_elements(0, true); // Initialize boundary condition types and spaces with default shapesets. // For the concentration. EssentialBCs<double> bcs_concentration; bcs_concentration.add_boundary_condition(new ConcentrationTimedepEssentialBC(BDY_DIRICHLET_CONCENTRATION, CONCENTRATION_EXT, CONCENTRATION_EXT_STARTUP_TIME)); bcs_concentration.add_boundary_condition(new ConcentrationTimedepEssentialBC(BDY_SOLID_WALL_TOP, 0.0, CONCENTRATION_EXT_STARTUP_TIME)); bcs_concentration.add_boundary_condition(new ConcentrationTimedepEssentialBC(BDY_INLET, 0.0, CONCENTRATION_EXT_STARTUP_TIME)); L2Space<double>space_rho(&mesh_flow, P_INIT_FLOW); L2Space<double>space_rho_v_x(&mesh_flow, P_INIT_FLOW); L2Space<double>space_rho_v_y(&mesh_flow, P_INIT_FLOW); L2Space<double>space_e(&mesh_flow, P_INIT_FLOW); // Space<double> for concentration. H1Space<double> space_c(&mesh_concentration, &bcs_concentration, P_INIT_CONCENTRATION); int ndof = Space<double>::get_num_dofs(Hermes::vector<Space<double>*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c)); info("ndof: %d", ndof); // Initialize solutions, set initial conditions. InitialSolutionEulerDensity sln_rho(&mesh_flow, RHO_EXT); InitialSolutionEulerDensityVelX sln_rho_v_x(&mesh_flow, RHO_EXT * V1_EXT); InitialSolutionEulerDensityVelY sln_rho_v_y(&mesh_flow, RHO_EXT * V2_EXT); InitialSolutionEulerDensityEnergy sln_e(&mesh_flow, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); InitialSolutionConcentration sln_c(&mesh_concentration, 0.0); InitialSolutionEulerDensity prev_rho(&mesh_flow, RHO_EXT); InitialSolutionEulerDensityVelX prev_rho_v_x(&mesh_flow, RHO_EXT * V1_EXT); InitialSolutionEulerDensityVelY prev_rho_v_y(&mesh_flow, RHO_EXT * V2_EXT); InitialSolutionEulerDensityEnergy prev_e(&mesh_flow, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); InitialSolutionConcentration prev_c(&mesh_concentration, 0.0); Solution<double> rsln_rho, rsln_rho_v_x, rsln_rho_v_y, rsln_e, rsln_c; // Numerical flux. OsherSolomonNumericalFlux num_flux(KAPPA); // Initialize weak formulation. WeakForm<double>* wf = NULL; if(SEMI_IMPLICIT) wf = new EulerEquationsWeakFormSemiImplicitCoupled(&num_flux, KAPPA, RHO_EXT, V1_EXT, V2_EXT, P_EXT, BDY_SOLID_WALL_BOTTOM, BDY_SOLID_WALL_TOP, BDY_INLET, BDY_OUTLET, BDY_NATURAL_CONCENTRATION, &prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c, EPSILON, (P_INIT_FLOW == 0 && CAND_LIST_FLOW == H2D_H_ANISO)); else wf = new EulerEquationsWeakFormExplicitCoupled(&num_flux, KAPPA, RHO_EXT, V1_EXT, V2_EXT, P_EXT, BDY_SOLID_WALL_BOTTOM, BDY_SOLID_WALL_TOP, BDY_INLET, BDY_OUTLET, BDY_NATURAL_CONCENTRATION, &prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c, EPSILON, (P_INIT_FLOW == 0 && CAND_LIST_FLOW == H2D_H_ANISO)); // Filters for visualization of Mach number, pressure and entropy. MachNumberFilter Mach_number(Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); PressureFilter pressure(Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); EntropyFilter entropy(Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA, RHO_EXT, P_EXT); ScalarView<double> pressure_view("Pressure", new WinGeom(0, 0, 600, 400)); ScalarView<double> Mach_number_view("Mach number", new WinGeom(700, 0, 600, 400)); ScalarView<double> s5("Concentration", new WinGeom(700, 400, 600, 400)); OrderView<double> order_view_flow("Orders - flow", new WinGeom(700, 350, 600, 400)); OrderView<double> order_view_conc("Orders - concentration", new WinGeom(700, 700, 600, 400)); // Initialize refinement selector. L2ProjBasedSelector<double> l2selector_flow(CAND_LIST_FLOW, CONV_EXP, H2DRS_DEFAULT_ORDER); L2ProjBasedSelector<double> l2selector_concentration(CAND_LIST_CONCENTRATION, CONV_EXP, H2DRS_DEFAULT_ORDER); // Set up CFL calculation class. CFLCalculation CFL(CFL_NUMBER, KAPPA); // Set up Advection-Diffusion-Equation stability calculation class. ADEStabilityCalculation ADES(ADVECTION_STABILITY_CONSTANT, DIFFUSION_STABILITY_CONSTANT, EPSILON); int iteration = 0; double t = 0; for(t = 0.0; t < 100.0; t += time_step) { time_step_out << time_step << std::endl; info("---- Time step %d, time %3.5f.", iteration++, t); if(iteration == 2) { ERR_STOP_FLOW = 0.55; ERR_STOP_CONCENTRATION = 8.3; } // Periodic global derefinements. if (iteration > 1 && iteration % UNREF_FREQ == 0 && (REFINEMENT_COUNT_FLOW > 0 || REFINEMENT_COUNT_CONCENTRATION > 0)) { info("Global mesh derefinement."); if(REFINEMENT_COUNT_FLOW > 0) { REFINEMENT_COUNT_FLOW = 0; space_rho.unrefine_all_mesh_elements(); if(CAND_LIST_FLOW == H2D_HP_ANISO) space_rho.adjust_element_order(-1, P_INIT_FLOW); space_rho_v_x.copy_orders(&space_rho); space_rho_v_y.copy_orders(&space_rho); space_e.copy_orders(&space_rho); } if(REFINEMENT_COUNT_CONCENTRATION > 0) { REFINEMENT_COUNT_CONCENTRATION = 0; space_c.unrefine_all_mesh_elements(); space_c.adjust_element_order(-1, P_INIT_CONCENTRATION); } } // Adaptivity loop: int as = 1; bool done = false; do { info("---- Adaptivity step %d:", as); // Construct globally refined reference mesh and setup reference space. int order_increase = 0; if(CAND_LIST_FLOW == H2D_HP_ANISO) order_increase = 1; Hermes::vector<Space<double> *>* ref_spaces = Space<double>::construct_refined_spaces(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), order_increase); if(CAND_LIST_FLOW != H2D_HP_ANISO) (*ref_spaces)[4]->adjust_element_order(+1, P_INIT_CONCENTRATION); // Project the previous time level solution onto the new fine mesh. info("Projecting the previous time level solution onto the new fine mesh."); OGProjection<double>::project_global(*ref_spaces, Hermes::vector<Solution<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c), Hermes::vector<Solution<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c), matrix_solver_type); if(iteration == 1) { if(CAND_LIST_FLOW == H2D_HP_ANISO) { prev_rho.set_const((*ref_spaces)[4]->get_mesh(), RHO_EXT); prev_rho_v_x.set_const((*ref_spaces)[4]->get_mesh(), RHO_EXT * V1_EXT); prev_rho_v_y.set_const((*ref_spaces)[4]->get_mesh(), RHO_EXT * V2_EXT); prev_e.set_const((*ref_spaces)[4]->get_mesh(), QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); } prev_c.set_const((*ref_spaces)[4]->get_mesh(), 0.0); } if(as > 1) { delete rsln_rho.get_mesh(); delete rsln_rho_v_x.get_mesh(); delete rsln_rho_v_y.get_mesh(); delete rsln_e.get_mesh(); delete rsln_c.get_mesh(); } // Report NDOFs. info("ndof_coarse: %d, ndof_fine: %d.", Space<double>::get_num_dofs(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c)), Space<double>::get_num_dofs(*ref_spaces)); // Very imporant, set the meshes for the flow as the same. (*ref_spaces)[1]->get_mesh()->set_seq((*ref_spaces)[0]->get_mesh()->get_seq()); (*ref_spaces)[2]->get_mesh()->set_seq((*ref_spaces)[0]->get_mesh()->get_seq()); (*ref_spaces)[3]->get_mesh()->set_seq((*ref_spaces)[0]->get_mesh()->get_seq()); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix<double>* matrix = create_matrix<double>(matrix_solver_type); Vector<double>* rhs = create_vector<double>(matrix_solver_type); LinearSolver<double>* solver = create_linear_solver<double>(matrix_solver_type, matrix, rhs); // Initialize the FE problem. bool is_linear = true; DiscreteProblem<double> dp(wf, *ref_spaces); if(SEMI_IMPLICIT) static_cast<EulerEquationsWeakFormSemiImplicitCoupled*>(wf)->set_time_step(time_step); else static_cast<EulerEquationsWeakFormExplicitCoupled*>(wf)->set_time_step(time_step); // Assemble stiffness matrix and rhs. info("Assembling the stiffness matrix and right-hand side vector."); dp.assemble(matrix, rhs); // Solve the matrix problem. info("Solving the matrix problem."); if (solver->solve()) Solution<double>::vector_to_solutions(solver->get_sln_vector(), *ref_spaces, Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e, &rsln_c)); else error ("Matrix solver failed.\n"); Hermes::vector<Space<double>*> flow_spaces((*ref_spaces)[0], (*ref_spaces)[1], (*ref_spaces)[2], (*ref_spaces)[3]); double* flow_solution_vector = new double[Space<double>::get_num_dofs(flow_spaces)]; OGProjection<double>::project_global(flow_spaces, Hermes::vector<MeshFunction<double> *>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e), flow_solution_vector); FluxLimiter flux_limiter(FluxLimiter::Krivodonova, flow_solution_vector, flow_spaces); flux_limiter.limit_according_to_detector(); flux_limiter.get_limited_solutions(Hermes::vector<Solution<double> *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); if(SHOCK_CAPTURING) flux_limiter.get_limited_solutions(Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)); // Project the fine mesh solution onto the coarse mesh. info("Projecting reference solution on coarse mesh."); OGProjection<double>::project_global(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e, &rsln_c), Hermes::vector<Solution<double>*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e, &sln_c), matrix_solver_type, Hermes::vector<ProjNormType>(HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM)); util_time_step = time_step; if(SEMI_IMPLICIT) CFL.calculate_semi_implicit(Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e), &mesh_flow, util_time_step); else CFL.calculate(Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e), &mesh_flow, util_time_step); time_step = util_time_step; ADES.calculate(Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y), &mesh_concentration, util_time_step); // Calculate element errors and total error estimate. info("Calculating error estimates."); Adapt<double> adaptivity_flow(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<ProjNormType>(HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM)); double err_est_rel_total_flow = adaptivity_flow.calc_err_est(Hermes::vector<Solution<double>*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)) * 100; Adapt<double> adaptivity_concentration(&space_c, HERMES_L2_NORM); double err_est_rel_total_concentration = adaptivity_concentration.calc_err_est(&sln_c, &rsln_c) * 100; // Report results. info("Error estimate for the flow part: %g%%", err_est_rel_total_flow); info("Error estimate for the concentration part: %g%%", err_est_rel_total_concentration); // If err_est too large, adapt the mesh. if (err_est_rel_total_flow < ERR_STOP_FLOW && err_est_rel_total_concentration < ERR_STOP_CONCENTRATION) { done = true; if(SHOCK_CAPTURING) flux_limiter.limit_according_to_detector(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); } else { info("Adapting coarse meshes."); if(err_est_rel_total_flow > ERR_STOP_FLOW) { done = adaptivity_flow.adapt(Hermes::vector<RefinementSelectors::Selector<double> *>(&l2selector_flow, &l2selector_flow, &l2selector_flow, &l2selector_flow), THRESHOLD, STRATEGY, MESH_REGULARITY); REFINEMENT_COUNT_FLOW++; } else done = true; if(err_est_rel_total_concentration > ERR_STOP_CONCENTRATION) { if(!adaptivity_concentration.adapt(&l2selector_concentration, THRESHOLD, STRATEGY, MESH_REGULARITY)) done = false; REFINEMENT_COUNT_CONCENTRATION++; } if (Space<double>::get_num_dofs(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c)) >= NDOF_STOP) done = true; else // Increase the counter of performed adaptivity steps. as++; } // Save orders. if((iteration - 1) % EVERY_NTH_STEP == 0 && done) { if(HERMES_VISUALIZATION) { Hermes::vector<Space<double> *>* ref_spaces_local = Space<double>::construct_refined_spaces(Hermes::vector<Space<double> *>(&space_rho, &space_c), 0); order_view_flow.show((*ref_spaces_local)[0]); order_view_conc.show((*ref_spaces_local)[1]); order_view_flow.save_numbered_screenshot("FlowMesh%i.bmp", (int)(iteration / 5), true); order_view_conc.save_numbered_screenshot("ConcentrationMesh%i.bmp", (int)(iteration / 5), true); for(unsigned int i = 0; i < ref_spaces_local->size(); i++) { delete (*ref_spaces_local)[i]->get_mesh(); delete (*ref_spaces_local)[i]; } } if(VTK_VISUALIZATION) { Orderizer ord; char filename[40]; sprintf(filename, "Flow-mesh-%i.vtk", iteration - 1); ord.save_orders_vtk((*ref_spaces)[0], filename); sprintf(filename, "Concentration-mesh-%i.vtk", iteration - 1); ord.save_orders_vtk((*ref_spaces)[4], filename); } } // Clean up. delete solver; delete matrix; delete rhs; for(unsigned int i = 0; i < ref_spaces->size(); i++) delete (*ref_spaces)[i]; } while (done == false); // Copy the solutions into the previous time level ones. prev_rho.copy(&rsln_rho); prev_rho_v_x.copy(&rsln_rho_v_x); prev_rho_v_y.copy(&rsln_rho_v_y); prev_e.copy(&rsln_e); prev_c.copy(&rsln_c); delete rsln_rho.get_mesh(); delete rsln_rho_v_x.get_mesh(); delete rsln_rho_v_y.get_mesh(); delete rsln_e.get_mesh(); delete rsln_c.get_mesh(); // Visualization. if((iteration - 1) % EVERY_NTH_STEP == 0) { // Hermes visualization. if(HERMES_VISUALIZATION) { Mach_number.reinit(); pressure.reinit(); pressure_view.show_mesh(false); pressure_view.show(&pressure); pressure_view.set_scale_format("%1.3f"); Mach_number_view.show_mesh(false); Mach_number_view.set_scale_format("%1.3f"); Mach_number_view.show(&Mach_number); s5.show_mesh(false); s5.set_scale_format("%0.3f"); s5.show(&prev_c); pressure_view.save_numbered_screenshot("pressure%i.bmp", (int)(iteration / 5), true); Mach_number_view.save_numbered_screenshot("Mach_number%i.bmp", (int)(iteration / 5), true); s5.save_numbered_screenshot("concentration%i.bmp", (int)(iteration / 5), true); } // Output solution in VTK format. if(VTK_VISUALIZATION) { pressure.reinit(); Mach_number.reinit(); Linearizer<double> lin; char filename[40]; //sprintf(filename, "pressure-%i.vtk", iteration - 1); //lin.save_solution_vtk(&pressure, filename, "Pressure", false); sprintf(filename, "pressure-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", true); //sprintf(filename, "Mach number-%i.vtk", iteration - 1); //lin.save_solution_vtk(&Mach_number, filename, "MachNumber", false); sprintf(filename, "Mach number-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", true); //sprintf(filename, "Concentration-%i.vtk", iteration - 1); //lin.save_solution_vtk(&prev_c, filename, "Concentration", true); sprintf(filename, "Concentration-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_c, filename, "Concentration", true); } } } /* pressure_view.close(); entropy_production_view.close(); Mach_number_view.close(); s5.close(); */ return 0; }
int main(int argc, char* argv[]) { // Instantiate a class with global functions. Hermes2D hermes2d; // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("domain.mesh", &mesh); // Perform initial mesh refinements (optional). for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); // Initialize the weak formulation. CustomWeakForm wf; // Initialize boundary conditions. CustomDirichletCondition bc_essential(Hermes::vector<std::string>("Bdy"), BDY_A_PARAM, BDY_B_PARAM, BDY_C_PARAM); EssentialBCs bcs(&bc_essential); // Create an H1 space with default shapeset. H1Space space(&mesh, &bcs, P_INIT); int ndof = space.get_num_dofs(); info("ndof = %d", ndof); // Initialize the FE problem. DiscreteProblem dp(&wf, &space); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix = create_matrix(matrix_solver); Vector* rhs = create_vector(matrix_solver); Solver* solver = create_linear_solver(matrix_solver, matrix, rhs); // Initial coefficient vector for the Newton's method. scalar* coeff_vec = new scalar[ndof]; memset(coeff_vec, 0, ndof*sizeof(scalar)); // Perform Newton's iteration. bool jacobian_changed = true; double newton_tol = 1e-8; int newton_max_iter = 100; bool verbose = true; if (!hermes2d.solve_newton(coeff_vec, &dp, solver, matrix, rhs, jacobian_changed, newton_tol, newton_max_iter, verbose)) error("Newton's iteration failed."); // Translate the resulting coefficient vector into the Solution sln. Solution sln; Solution::vector_to_solution(coeff_vec, &space, &sln); // VTK output. if (VTK_VISUALIZATION) { // Output solution in VTK format. Linearizer lin; bool mode_3D = true; lin.save_solution_vtk(&sln, "sln.vtk", "Temperature", mode_3D); info("Solution in VTK format saved to file %s.", "sln.vtk"); // Output mesh and element orders in VTK format. Orderizer ord; ord.save_orders_vtk(&space, "ord.vtk"); info("Element orders in VTK format saved to file %s.", "ord.vtk"); } // Visualize the solution. if (HERMES_VISUALIZATION) { ScalarView view("Solution", new WinGeom(0, 0, 440, 350)); view.show(&sln, HERMES_EPS_HIGH); View::wait(); } // Clean up. delete solver; delete matrix; delete rhs; delete [] coeff_vec; return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("domain.mesh", &mesh); // Perform initial mesh refinements (optional). //mesh.refine_all_elements(); // Initialize boundary conditions DefaultEssentialBCConst bc_essential(Hermes::vector<std::string>(BDY_BOTTOM, BDY_OUTER, BDY_LEFT, BDY_INNER), 0.0); EssentialBCs bcs(&bc_essential); // Create an H1 space with default shapeset. H1Space space(&mesh, &bcs, P_INIT); int ndof = Space::get_num_dofs(&space); info("ndof = %d", ndof); // Initialize the weak formulation. Not providing the order determination form // (or callback) turns on adaptive numerical quadrature. The quadrature begins // with using a first-order rule in the entire element. Then the element is split // uniformly in space and the quadrature order is increased by "adapt_order_increase". // Then the form is calculated again by employing the new quadrature in subelements. // This provides a more accurate result. If relative error is less than // "adapt_rel_error_tol", the computation stops, otherwise the same procedure is // applied recursively to all four subelements. int adapt_order_increase = 1; double adapt_rel_error_tol = 1e1; WeakFormPoisson wf(CONST_F, ADAPTIVE_QUADRATURE, adapt_order_increase, adapt_rel_error_tol); if (ADAPTIVE_QUADRATURE) info("Adaptive quadrature ON."); else info("Adaptive quadrature OFF."); // Initialize the FE problem. bool is_linear = true; DiscreteProblem dp(&wf, &space, is_linear); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix = create_matrix(matrix_solver); Vector* rhs = create_vector(matrix_solver); Solver* solver = create_linear_solver(matrix_solver, matrix, rhs); // Initialize the solution. Solution sln; // Assemble the stiffness matrix and right-hand side vector. info("Assembling the stiffness matrix and right-hand side vector."); dp.assemble(matrix, rhs); // Solve the linear system and if successful, obtain the solution. info("Solving the matrix problem."); if(solver->solve()) Solution::vector_to_solution(solver->get_solution(), &space, &sln); else error ("Matrix solver failed.\n"); // VTK output. if (VTK_VISUALIZATION) { // Output solution in VTK format. Linearizer lin; bool mode_3D = true; lin.save_solution_vtk(&sln, "sln.vtk", "Temperature", mode_3D); info("Solution in VTK format saved to file %s.", "sln.vtk"); // Output mesh and element orders in VTK format. Orderizer ord; ord.save_orders_vtk(&space, "ord.vtk"); info("Element orders in VTK format saved to file %s.", "ord.vtk"); } // Visualize the solution. if (HERMES_VISUALIZATION) { ScalarView view("Solution", new WinGeom(0, 0, 440, 350)); view.show(&sln); View::wait(); } // Clean up. delete solver; delete matrix; delete rhs; return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; MeshReaderH2D mloader; if (ALIGN_MESH) mloader.load("oven_load_circle.mesh", &mesh); else mloader.load("oven_load_square.mesh", &mesh); // Perform initial mesh refinemets. for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); // Initialize boundary conditions DefaultEssentialBCConst<std::complex<double> > bc_essential(BDY_PERFECT_CONDUCTOR, std::complex<double>(0.0, 0.0)); EssentialBCs<std::complex<double> > bcs(&bc_essential); // Create an Hcurl space with default shapeset. HcurlSpace<std::complex<double> > space(&mesh, &bcs, P_INIT); int ndof = space.get_num_dofs(); Hermes::Mixins::Loggable::Static::info("ndof = %d", ndof); // Initialize the weak formulation. CustomWeakForm wf(e_0, mu_0, mu_r, kappa, omega, J, ALIGN_MESH, &mesh, BDY_CURRENT); // Initialize coarse and reference mesh solution. Solution<std::complex<double> > sln, ref_sln; // Initialize refinements selector. HcurlProjBasedSelector<std::complex<double> > selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER); // Initialize views. ScalarView eview("Electric field", new WinGeom(0, 0, 580, 400)); OrderView oview("Polynomial orders", new WinGeom(590, 0, 550, 400)); // DOF and CPU convergence graphs initialization. SimpleGraph graph_dof, graph_cpu; // Time measurement. Hermes::Mixins::TimeMeasurable cpu_time; cpu_time.tick(); // Adaptivity loop: int as = 1; bool done = false; do { Hermes::Mixins::Loggable::Static::info("---- Adaptivity step %d:", as); // Construct globally refined reference mesh and setup reference space. Mesh::ReferenceMeshCreator refMeshCreator(&mesh); Mesh* ref_mesh = refMeshCreator.create_ref_mesh(); Space<std::complex<double> >::ReferenceSpaceCreator refSpaceCreator(&space, ref_mesh); Space<std::complex<double> >* ref_space = refSpaceCreator.create_ref_space(); int ndof_ref = Space<std::complex<double> >::get_num_dofs(ref_space); // Initialize reference problem. Hermes::Mixins::Loggable::Static::info("Solving on reference mesh."); DiscreteProblem<std::complex<double> > dp(&wf, ref_space); // Time measurement. cpu_time.tick(); // Perform Newton's iteration. Hermes::Hermes2D::NewtonSolver<std::complex<double> > newton(&dp); try { newton.set_newton_max_iter(NEWTON_MAX_ITER); newton.set_newton_tol(NEWTON_TOL); newton.solve(); } catch(Hermes::Exceptions::Exception e) { e.print_msg(); throw Hermes::Exceptions::Exception("Newton's iteration failed."); }; // Translate the resulting coefficient vector into the Solution<std::complex<double> > sln. Hermes::Hermes2D::Solution<std::complex<double> >::vector_to_solution(newton.get_sln_vector(), ref_space, &ref_sln); // Project the fine mesh solution onto the coarse mesh. Hermes::Mixins::Loggable::Static::info("Projecting reference solution on coarse mesh."); OGProjection<std::complex<double> > ogProjection; ogProjection.project_global(&space, &ref_sln, &sln); // View the coarse mesh solution and polynomial orders. RealFilter real(&sln); MagFilter<double> magn(&real); ValFilter limited_magn(&magn, 0.0, 4e3); char title[100]; sprintf(title, "Electric field, adaptivity step %d", as); eview.set_title(title); //eview.set_min_max_range(0.0, 4e3); eview.show(&limited_magn); sprintf(title, "Polynomial orders, adaptivity step %d", as); oview.set_title(title); oview.show(&space); // Calculate element errors and total error estimate. Hermes::Mixins::Loggable::Static::info("Calculating error estimate."); Adapt<std::complex<double> >* adaptivity = new Adapt<std::complex<double> >(&space); // Set custom error form and calculate error estimate. CustomErrorForm cef(kappa); adaptivity->set_error_form(0, 0, &cef); double err_est_rel = adaptivity->calc_err_est(&sln, &ref_sln) * 100; // Report results. Hermes::Mixins::Loggable::Static::info("ndof_coarse: %d, ndof_fine: %d, err_est_rel: %g%%", Space<std::complex<double> >::get_num_dofs(&space), Space<std::complex<double> >::get_num_dofs(ref_space), err_est_rel); // Time measurement. cpu_time.tick(); // Add entry to DOF and CPU convergence graphs. graph_dof.add_values(Space<std::complex<double> >::get_num_dofs(&space), err_est_rel); graph_dof.save("conv_dof_est.dat"); graph_cpu.add_values(cpu_time.accumulated(), err_est_rel); graph_cpu.save("conv_cpu_est.dat"); // If err_est too large, adapt the mesh. if (err_est_rel < ERR_STOP) done = true; else { Hermes::Mixins::Loggable::Static::info("Adapting coarse mesh."); done = adaptivity->adapt(&selector, THRESHOLD, STRATEGY, MESH_REGULARITY); } if (space.get_num_dofs() >= NDOF_STOP) done = true; delete adaptivity; if(!done) { delete ref_space->get_mesh(); delete ref_space; } // Increase counter. as++; } while (done == false); Hermes::Mixins::Loggable::Static::info("Total running time: %g s", cpu_time.accumulated()); RealFilter ref_real(&sln); MagFilter<double> ref_magn(&ref_real); ValFilter ref_limited_magn(&ref_magn, 0.0, 4e3); eview.set_title("Fine mesh solution - magnitude"); eview.show(&ref_limited_magn); // Output solution in VTK format. Linearizer lin; bool mode_3D = true; lin.save_solution_vtk(&ref_limited_magn, "sln.vtk", "Magnitude of E", mode_3D); Hermes::Mixins::Loggable::Static::info("Solution in VTK format saved to file %s.", "sln.vtk"); // Wait for all views to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { // Instantiate a class with global functions. Hermes2D hermes2d; // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("../domain.mesh", &mesh); // Perform initial mesh refinements (optional). for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); // Initialize the weak formulation. CustomWeakFormPoissonDirichlet wf("Aluminum", LAMBDA_AL, "Copper", LAMBDA_CU, VOLUME_HEAT_SRC); // Initialize boundary conditions. CustomDirichletCondition bc_essential(Hermes::vector<std::string>("Bottom", "Inner", "Outer", "Left"), BDY_A_PARAM, BDY_B_PARAM, BDY_C_PARAM); EssentialBCs bcs(&bc_essential); // Create an H1 space with default shapeset. H1Space space(&mesh, &bcs, P_INIT); int ndof = space.get_num_dofs(); info("ndof = %d", ndof); // Initialize the FE problem. DiscreteProblem dp(&wf, &space); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix = create_matrix(matrix_solver); Vector* rhs = create_vector(matrix_solver); Solver* solver = create_linear_solver(matrix_solver, matrix, rhs); // Initial coefficient vector for the Newton's method. scalar* coeff_vec = new scalar[ndof]; memset(coeff_vec, 0, ndof*sizeof(scalar)); // Perform Newton's iteration. if (!hermes2d.solve_newton(coeff_vec, &dp, solver, matrix, rhs)) error("Newton's iteration failed."); // Translate the resulting coefficient vector into the Solution sln. Solution sln; Solution::vector_to_solution(coeff_vec, &space, &sln); // VTK output. if (VTK_VISUALIZATION) { // Output solution in VTK format. Linearizer lin; bool mode_3D = true; lin.save_solution_vtk(&sln, "sln.vtk", "Temperature", mode_3D); info("Solution in VTK format saved to file %s.", "sln.vtk"); // Output mesh and element orders in VTK format. Orderizer ord; ord.save_orders_vtk(&space, "ord.vtk"); info("Element orders in VTK format saved to file %s.", "ord.vtk"); } ndof = Space::get_num_dofs(&space); printf("ndof = %d\n", ndof); double sum = 0; for (int i=0; i < ndof; i++) sum += coeff_vec[i]; printf("coefficient sum = %g\n", sum); bool success = true; if (fabs(sum + 4.2471) > 1e-3) success = 0; if (success == 1) { printf("Success!\n"); return ERR_SUCCESS; } else { printf("Failure!\n"); return ERR_FAILURE; } }
int main(int argc, char* argv[]) { // Load the mesh. Mesh basemesh; H2DReader mloader; if(GAMM_CHANNEL) mloader.load("GAMM-channel.mesh", &basemesh); else mloader.load("channel.mesh", &basemesh); // Initialize the meshes. Mesh mesh_flow, mesh_concentration; mesh_flow.copy(&basemesh); mesh_concentration.copy(&basemesh); for(unsigned int i = 0; i < INIT_REF_NUM_CONCENTRATION; i++) mesh_concentration.refine_all_elements(); switch(SETUP_VARIANT) { case 0: mesh_concentration.refine_towards_boundary(BDY_INLET, INIT_REF_NUM_CONCENTRATION_BDY, false); break; case 1: mesh_concentration.refine_towards_boundary(BDY_SOLID_WALL_BOTTOM, INIT_REF_NUM_CONCENTRATION_BDY, false); break; case 2: mesh_concentration.refine_towards_boundary(BDY_SOLID_WALL_TOP, INIT_REF_NUM_CONCENTRATION_BDY, false); break; } for(unsigned int i = 0; i < INIT_REF_NUM_FLOW; i++) mesh_flow.refine_all_elements(); // Initialize boundary condition types and spaces with default shapesets. // For the flow. EssentialBCs bcs_flow; // For the concentration. EssentialBCs bcs_concentration; switch(SETUP_VARIANT) { case 0: //bcs_concentration.add_boundary_condition(new NaturalEssentialBC(Hermes::vector<std::string>(BDY_OUTLET, BDY_SOLID_WALL_BOTTOM, BDY_SOLID_WALL_TOP))); bcs_concentration.add_boundary_condition(new DefaultEssentialBCConst(BDY_INLET, CONCENTRATION_EXT)); break; case 1: //bcs_concentration.add_boundary_condition(new NaturalEssentialBC(Hermes::vector<std::string>(BDY_OUTLET, BDY_INLET, BDY_SOLID_WALL_TOP))); bcs_concentration.add_boundary_condition(new DefaultEssentialBCConst(BDY_SOLID_WALL_BOTTOM, CONCENTRATION_EXT)); break; case 2: //bcs_concentration.add_boundary_condition(new NaturalEssentialBC(Hermes::vector<std::string>(BDY_OUTLET, BDY_SOLID_WALL_BOTTOM, BDY_INLET))); bcs_concentration.add_boundary_condition(new DefaultEssentialBCConst(BDY_SOLID_WALL_TOP, CONCENTRATION_EXT)); break; } L2Space space_rho(&mesh_flow, &bcs_flow, P_INIT_FLOW); L2Space space_rho_v_x(&mesh_flow, &bcs_flow, P_INIT_FLOW); L2Space space_rho_v_y(&mesh_flow, &bcs_flow, P_INIT_FLOW); L2Space space_e(&mesh_flow, &bcs_flow, P_INIT_FLOW); // Space for concentration. H1Space space_c(&mesh_concentration, &bcs_concentration, P_INIT_CONCENTRATION); int ndof = Space::get_num_dofs(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c)); info("ndof: %d", ndof); // Initialize solutions, set initial conditions. InitialSolutionEulerDensity sln_rho(&mesh_flow, RHO_EXT); InitialSolutionEulerDensityVelX sln_rho_v_x(&mesh_flow, RHO_EXT * V1_EXT); InitialSolutionEulerDensityVelY sln_rho_v_y(&mesh_flow, RHO_EXT * V2_EXT); InitialSolutionEulerDensityEnergy sln_e(&mesh_flow, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); InitialSolutionConcentration sln_c(&mesh_concentration, 0.0); InitialSolutionEulerDensity prev_rho(&mesh_flow, RHO_EXT); InitialSolutionEulerDensityVelX prev_rho_v_x(&mesh_flow, RHO_EXT * V1_EXT); InitialSolutionEulerDensityVelY prev_rho_v_y(&mesh_flow, RHO_EXT * V2_EXT); InitialSolutionEulerDensityEnergy prev_e(&mesh_flow, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); InitialSolutionConcentration prev_c(&mesh_concentration, 0.0); // Numerical flux. OsherSolomonNumericalFlux num_flux(KAPPA); // Initialize weak formulation. EulerEquationsWeakFormImplicitCoupled wf(SETUP_VARIANT, &num_flux, KAPPA, RHO_EXT, V1_EXT, V2_EXT, P_EXT, BDY_SOLID_WALL_BOTTOM, BDY_SOLID_WALL_TOP, BDY_INLET, BDY_OUTLET, &prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c, PRECONDITIONING, EPSILON); wf.set_time_step(time_step); // Initialize the FE problem. bool is_linear = false; DiscreteProblem dp(&wf, Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), is_linear); // Project the initial solution on the FE space // in order to obtain initial vector for NOX. info("Projecting initial solution on the FE mesh."); scalar* coeff_vec = new scalar[Space::get_num_dofs(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c))]; OGProjection::project_global(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c), coeff_vec); // Filters for visualization of Mach number, pressure and entropy. MachNumberFilter Mach_number(Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), KAPPA); PressureFilter pressure(Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), KAPPA); EntropyFilter entropy(Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), KAPPA, RHO_EXT, P_EXT); ScalarView pressure_view("Pressure", new WinGeom(0, 0, 600, 300)); ScalarView Mach_number_view("Mach number", new WinGeom(700, 0, 600, 300)); ScalarView entropy_production_view("Entropy estimate", new WinGeom(0, 400, 600, 300)); ScalarView s5("Concentration", new WinGeom(700, 400, 600, 300)); /* ScalarView s1("1", new WinGeom(0, 0, 600, 300)); ScalarView s2("2", new WinGeom(700, 0, 600, 300)); ScalarView s3("3", new WinGeom(0, 400, 600, 300)); ScalarView s4("4", new WinGeom(700, 400, 600, 300)); ScalarView s5("Concentration", new WinGeom(350, 200, 600, 300)); */ // Initialize NOX solver. NoxSolver solver(&dp); solver.set_ls_tolerance(NOX_LINEAR_TOLERANCE); solver.disable_abs_resid(); solver.set_conv_rel_resid(1.00); // Select preconditioner. if(PRECONDITIONING) { RCP<Precond> pc = rcp(new MlPrecond("sa")); solver.set_precond(pc); } int iteration = 0; double t = 0; for(t = 0.0; t < 3.0; t += time_step) { info("---- Time step %d, time %3.5f.", iteration++, t); OGProjection::project_global(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c), coeff_vec); info("Assembling by DiscreteProblem, solving by NOX."); solver.set_init_sln(coeff_vec); if (solver.solve()) Solution::vector_to_solutions(solver.get_solution(), Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<Solution *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c)); else error("NOX failed."); // Visualization. if((iteration - 1) % EVERY_NTH_STEP == 0) { // Hermes visualization. if(HERMES_VISUALIZATION) { Mach_number.reinit(); pressure.reinit(); entropy.reinit(); pressure_view.show(&pressure); entropy_production_view.show(&entropy); Mach_number_view.show(&Mach_number); s5.show(&prev_c); /* s1.show(&prev_rho); s2.show(&prev_rho_v_x); s3.show(&prev_rho_v_y); s4.show(&prev_e); s5.show(&prev_c); */ } // Output solution in VTK format. if(VTK_VISUALIZATION) { Linearizer lin; char filename[40]; sprintf(filename, "w0-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_rho, filename, "w0", false); sprintf(filename, "w1-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_rho_v_x, filename, "w1", false); sprintf(filename, "w2-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_rho_v_y, filename, "w2", false); sprintf(filename, "w3-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_e, filename, "w3", false); sprintf(filename, "concentration-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_c, filename, "concentration", false); } } } pressure_view.close(); entropy_production_view.close(); Mach_number_view.close(); s5.close(); /* s1.close(); s2.close(); s3.close(); s4.close(); */ return 0; }
int main(int argc, char* argv[]) { // Provide a possibility to change INITIAL_CONCENTRATION_STATE through an argument. if(argc > 1) INITIAL_CONCENTRATION_STATE = atoi(argv[1]); if(argc > 2) INIT_REF_NUM_FLOW = atoi(argv[2]); if(argc > 3) INIT_REF_NUM_CONCENTRATION = atoi(argv[3]); // Load the mesh. Mesh basemesh; H2DReader mloader; if(INITIAL_CONCENTRATION_STATE == 0) mloader.load("GAMM-channel-4-bnds.mesh", &basemesh); else mloader.load("channel-4-bnds.mesh", &basemesh); // Initialize the meshes. Mesh mesh_flow, mesh_concentration; mesh_flow.copy(&basemesh); mesh_concentration.copy(&basemesh); for(unsigned int i = 0; i < INIT_REF_NUM_CONCENTRATION; i++) mesh_concentration.refine_all_elements(); for(unsigned int i = 0; i < INIT_REF_NUM_FLOW; i++) mesh_flow.refine_all_elements(); // Initialize boundary condition types and spaces with default shapesets. BCTypes bc_types_euler; bc_types_euler.add_bc_neumann(Hermes::vector<int>(BDY_SOLID_WALL_TOP, BDY_SOLID_WALL_BOTTOM, BDY_INLET, BDY_OUTLET)); BCTypes bc_types_concentration; BCValues bc_values_concentration; switch(INITIAL_CONCENTRATION_STATE) { case 0: bc_types_concentration.add_bc_neumann(Hermes::vector<int>(BDY_INLET, BDY_OUTLET, BDY_SOLID_WALL_TOP)); bc_types_concentration.add_bc_dirichlet(Hermes::vector<int>(BDY_SOLID_WALL_BOTTOM)); bc_values_concentration.add_const(Hermes::vector<int>(BDY_SOLID_WALL_BOTTOM), CONCENTRATION_EXT); break; case 1: bc_types_concentration.add_bc_neumann(Hermes::vector<int>(BDY_INLET, BDY_OUTLET, BDY_SOLID_WALL_TOP)); bc_types_concentration.add_bc_dirichlet(Hermes::vector<int>(BDY_SOLID_WALL_BOTTOM)); bc_values_concentration.add_const(Hermes::vector<int>(BDY_SOLID_WALL_BOTTOM), CONCENTRATION_EXT); break; case 2: bc_types_concentration.add_bc_neumann(Hermes::vector<int>(BDY_SOLID_WALL_BOTTOM, BDY_OUTLET, BDY_SOLID_WALL_TOP)); bc_types_concentration.add_bc_dirichlet(Hermes::vector<int>(BDY_INLET)); bc_values_concentration.add_const(Hermes::vector<int>(BDY_INLET), CONCENTRATION_EXT); break; } L2Space space_rho(&mesh_flow, &bc_types_euler, P_INIT_FLOW); L2Space space_rho_v_x(&mesh_flow, &bc_types_euler, P_INIT_FLOW); L2Space space_rho_v_y(&mesh_flow, &bc_types_euler, P_INIT_FLOW); L2Space space_e(&mesh_flow, &bc_types_euler, P_INIT_FLOW); // Space for concentration. H1Space space_c(&mesh_concentration, &bc_types_concentration, &bc_values_concentration, P_INIT_CONCENTRATION); // Initialize solutions, set initial conditions. Solution sln_rho, sln_rho_v_x, sln_rho_v_y, sln_e, sln_c, prev_rho, prev_rho_v_x, prev_rho_v_y, prev_e, prev_c; sln_rho.set_exact(&mesh_flow, ic_density); sln_rho_v_x.set_exact(&mesh_flow, ic_density_vel_x); sln_rho_v_y.set_exact(&mesh_flow, ic_density_vel_y); sln_e.set_exact(&mesh_flow, ic_energy); sln_c.set_exact(&mesh_concentration, ic_concentration); prev_rho.set_exact(&mesh_flow, ic_density); prev_rho_v_x.set_exact(&mesh_flow, ic_density_vel_x); prev_rho_v_y.set_exact(&mesh_flow, ic_density_vel_y); prev_e.set_exact(&mesh_flow, ic_energy); prev_c.set_exact(&mesh_concentration, ic_concentration); // Initialize weak formulation. WeakForm wf(5); // Bilinear forms coming from time discretization by explicit Euler's method. wf.add_matrix_form(0, 0, callback(bilinear_form_time)); wf.add_matrix_form(1, 1, callback(bilinear_form_time)); wf.add_matrix_form(2, 2, callback(bilinear_form_time)); wf.add_matrix_form(3, 3, callback(bilinear_form_time)); wf.add_matrix_form(4, 4, callback(bilinear_form_time)); // Volumetric linear forms. // Linear forms coming from the linearization by taking the Eulerian fluxes' Jacobian matrices // from the previous time step. // Unnecessary for FVM. if(P_INIT_FLOW.order_h > 0 || P_INIT_FLOW.order_v > 0) { // First flux. wf.add_vector_form(0, callback(linear_form_0_1), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho_v_x)); wf.add_vector_form(1, callback(linear_form_1_0_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(1, callback(linear_form_1_1_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(1, callback(linear_form_1_2_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(1, callback(linear_form_1_3_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form(2, callback(linear_form_2_0_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(2, callback(linear_form_2_1_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(2, callback(linear_form_2_2_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(2, callback(linear_form_2_3_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form(3, callback(linear_form_3_0_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form(3, callback(linear_form_3_1_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form(3, callback(linear_form_3_2_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form(3, callback(linear_form_3_3_first_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); // Second flux. wf.add_vector_form(0, callback(linear_form_0_2), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho_v_y)); wf.add_vector_form(1, callback(linear_form_1_0_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(1, callback(linear_form_1_1_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(1, callback(linear_form_1_2_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(1, callback(linear_form_1_3_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form(2, callback(linear_form_2_0_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(2, callback(linear_form_2_1_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(2, callback(linear_form_2_2_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form(2, callback(linear_form_2_3_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form(3, callback(linear_form_3_0_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form(3, callback(linear_form_3_1_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form(3, callback(linear_form_3_2_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form(3, callback(linear_form_3_3_second_flux), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); } // Volumetric linear forms coming from the time discretization. wf.add_vector_form(0, linear_form_time, linear_form_order, HERMES_ANY, &prev_rho); wf.add_vector_form(1, linear_form_time, linear_form_order, HERMES_ANY, &prev_rho_v_x); wf.add_vector_form(2, linear_form_time, linear_form_order, HERMES_ANY, &prev_rho_v_y); wf.add_vector_form(3, linear_form_time, linear_form_order, HERMES_ANY, &prev_e); wf.add_vector_form(4, callback(linear_form_time_concentration), HERMES_ANY, &prev_c); // Surface linear forms - inner edges coming from the DG formulation. wf.add_vector_form_surf(0, linear_form_interface_0, linear_form_order, H2D_DG_INNER_EDGE, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(1, linear_form_interface_1, linear_form_order, H2D_DG_INNER_EDGE, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(2, linear_form_interface_2, linear_form_order, H2D_DG_INNER_EDGE, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(3, linear_form_interface_3, linear_form_order, H2D_DG_INNER_EDGE, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); // Surface linear forms - inlet / outlet edges. wf.add_vector_form_surf(0, bdy_flux_inlet_outlet_comp_0, linear_form_order, BDY_INLET, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(1, bdy_flux_inlet_outlet_comp_1, linear_form_order, BDY_INLET, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(2, bdy_flux_inlet_outlet_comp_2, linear_form_order, BDY_INLET, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(3, bdy_flux_inlet_outlet_comp_3, linear_form_order, BDY_INLET, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(0, bdy_flux_inlet_outlet_comp_0, linear_form_order, BDY_OUTLET, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(1, bdy_flux_inlet_outlet_comp_1, linear_form_order, BDY_OUTLET, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(2, bdy_flux_inlet_outlet_comp_2, linear_form_order, BDY_OUTLET, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(3, bdy_flux_inlet_outlet_comp_3, linear_form_order, BDY_OUTLET, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); // Surface linear forms - Solid wall edges. wf.add_vector_form_surf(0, bdy_flux_solid_wall_comp_0, linear_form_order, BDY_SOLID_WALL_TOP, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(1, bdy_flux_solid_wall_comp_1, linear_form_order, BDY_SOLID_WALL_TOP, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(2, bdy_flux_solid_wall_comp_2, linear_form_order, BDY_SOLID_WALL_TOP, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(3, bdy_flux_solid_wall_comp_3, linear_form_order, BDY_SOLID_WALL_TOP, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(0, bdy_flux_solid_wall_comp_0, linear_form_order, BDY_SOLID_WALL_BOTTOM, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(1, bdy_flux_solid_wall_comp_1, linear_form_order, BDY_SOLID_WALL_BOTTOM, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(2, bdy_flux_solid_wall_comp_2, linear_form_order, BDY_SOLID_WALL_BOTTOM, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); wf.add_vector_form_surf(3, bdy_flux_solid_wall_comp_3, linear_form_order, BDY_SOLID_WALL_BOTTOM, Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); // Forms for concentration. wf.add_vector_form(4, callback(linear_form_concentration_grad_grad), HERMES_ANY, &prev_c); wf.add_vector_form(4, callback(linear_form_concentration_convective), HERMES_ANY, Hermes::vector<MeshFunction*>(&prev_c, &prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form_surf(4, callback(linear_form_concentration_inlet_outlet), BDY_INLET, Hermes::vector<MeshFunction*>(&prev_c, &prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form_surf(4, callback(linear_form_concentration_inlet_outlet), BDY_OUTLET, Hermes::vector<MeshFunction*>(&prev_c, &prev_rho, &prev_rho_v_x, &prev_rho_v_y)); wf.add_vector_form_surf(4, callback(linear_form_concentration_inner_edges), H2D_DG_INNER_EDGE, Hermes::vector<MeshFunction*>(&prev_c, &prev_rho, &prev_rho_v_x, &prev_rho_v_y)); // Initialize the FE problem. bool is_linear = true; DiscreteProblem dp(&wf, Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), is_linear); // Filters for visualization of pressure and the two components of velocity. /* SimpleFilter pressure(calc_pressure_func, Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e)); SimpleFilter u(calc_u_func, Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e)); SimpleFilter w(calc_w_func, Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e)); SimpleFilter Mach_number(calc_Mach_func, Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e)); SimpleFilter entropy_estimate(calc_entropy_estimate_func, Hermes::vector<MeshFunction*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e)); ScalarView pressure_view("Pressure", new WinGeom(0, 0, 600, 300)); ScalarView Mach_number_view("Mach number", new WinGeom(700, 0, 600, 300)); ScalarView entropy_production_view("Entropy estimate", new WinGeom(0, 400, 600, 300)); VectorView vview("Velocity", new WinGeom(700, 400, 600, 300)); */ ScalarView s1("w0", new WinGeom(0, 0, 600, 300)); ScalarView s2("w1", new WinGeom(700, 0, 600, 300)); ScalarView s3("w2", new WinGeom(0, 400, 600, 300)); ScalarView s4("w3", new WinGeom(700, 400, 600, 300)); ScalarView s5("Concentration", new WinGeom(350, 200, 600, 300)); // Iteration number. int iteration = 0; // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix = create_matrix(matrix_solver); Vector* rhs = create_vector(matrix_solver); Solver* solver = create_linear_solver(matrix_solver, matrix, rhs); // Output of the approximate time derivative. std::ofstream time_der_out("time_der"); for(t = 0.0; t < 3.0; t += TAU) { info("---- Time step %d, time %3.5f.", iteration++, t); bool rhs_only = (iteration == 1 ? false : true); // Assemble stiffness matrix and rhs or just rhs. if (rhs_only == false) info("Assembling the stiffness matrix and right-hand side vector."); else info("Assembling the right-hand side vector (only)."); dp.assemble(matrix, rhs, rhs_only); // Solve the matrix problem. info("Solving the matrix problem."); if(solver->solve()) Solution::vector_to_solutions(solver->get_solution(), Hermes::vector<Space *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<Solution *>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e, &sln_c)); else error ("Matrix solver failed.\n"); // Copy the solutions into the previous time level ones. prev_rho.copy(&sln_rho); prev_rho_v_x.copy(&sln_rho_v_x); prev_rho_v_y.copy(&sln_rho_v_y); prev_e.copy(&sln_e); prev_c.copy(&sln_c); // Visualization. /* pressure.reinit(); u.reinit(); w.reinit(); Mach_number.reinit(); entropy_estimate.reinit(); pressure_view.show(&pressure); entropy_production_view.show(&entropy_estimate); Mach_number_view.show(&Mach_number); vview.show(&u, &w); */ // Visualization. if((iteration - 1) % EVERY_NTH_STEP == 0) { // Hermes visualization. if(HERMES_VISUALIZATION) { s1.show(&prev_rho); s2.show(&prev_rho_v_x); s3.show(&prev_rho_v_y); s4.show(&prev_e); s5.show(&prev_c); } // Output solution in VTK format. if(VTK_OUTPUT) { Linearizer lin; char filename[40]; sprintf(filename, "w0-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_rho, filename, "w0", false); sprintf(filename, "w1-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_rho_v_x, filename, "w1", false); sprintf(filename, "w2-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_rho_v_y, filename, "w2", false); sprintf(filename, "w3-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_e, filename, "w3", false); sprintf(filename, "concentration-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_c, filename, "concentration", false); } } } s1.close(); s2.close(); s3.close(); s4.close(); s5.close(); time_der_out.close(); return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("channel.mesh", &mesh); // Perform initial mesh refinements. for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(0); // Initialize boundary condition types and spaces with default shapesets. L2Space<double> space_rho(&mesh, P_INIT); L2Space<double> space_rho_v_x(&mesh, P_INIT); L2Space<double> space_rho_v_y(&mesh, P_INIT); L2Space<double> space_e(&mesh, P_INIT); int ndof = Space<double>::get_num_dofs(Hermes::vector<Space<double>*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); info("ndof: %d", ndof); // Initialize solutions, set initial conditions. InitialSolutionEulerDensity prev_rho(&mesh, RHO_INIT); InitialSolutionEulerDensityVelX prev_rho_v_x(&mesh, RHO_INIT * V1_INIT); InitialSolutionEulerDensityVelY prev_rho_v_y(&mesh, RHO_INIT * V2_INIT); InitialSolutionEulerDensityEnergy prev_e(&mesh, QuantityCalculator::calc_energy(RHO_INIT, RHO_INIT * V1_INIT, RHO_INIT * V2_INIT, PRESSURE_INIT, KAPPA)); // Numerical flux. OsherSolomonNumericalFlux num_flux(KAPPA); // Initialize weak formulation. EulerEquationsWeakFormSemiImplicitMultiComponentTwoInflows wf(&num_flux, KAPPA, RHO_LEFT, V1_LEFT, V2_LEFT, PRESSURE_LEFT, RHO_TOP, V1_TOP, V2_TOP, PRESSURE_TOP, BDY_SOLID_WALL, BDY_INLET_LEFT, BDY_INLET_TOP, BDY_OUTLET, &prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, (P_INIT == 0)); // Initialize the FE problem. DiscreteProblem<double> dp(&wf, Hermes::vector<Space<double>*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); // If the FE problem is in fact a FV problem. if(P_INIT == 0) dp.set_fvm(); // Filters for visualization of Mach number, pressure and entropy. MachNumberFilter Mach_number(Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); PressureFilter pressure(Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); ScalarView<double> pressure_view("Pressure", new WinGeom(0, 0, 600, 300)); ScalarView<double> Mach_number_view("Mach number", new WinGeom(700, 0, 600, 300)); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix<double>* matrix = create_matrix<double>(matrix_solver_type); Vector<double>* rhs = create_vector<double>(matrix_solver_type); LinearSolver<double>* solver = create_linear_solver<double>(matrix_solver_type, matrix, rhs); // Set up CFL calculation class. CFLCalculation CFL(CFL_NUMBER, KAPPA); int iteration = 0; double t = 0; for(t = 0.0; t < 3.0; t += time_step) { info("---- Time step %d, time %3.5f.", iteration++, t); // Set the current time step. wf.set_time_step(time_step); // Assemble the stiffness matrix and rhs. info("Assembling the stiffness matrix and right-hand side vector."); dp.assemble(matrix, rhs); std::ofstream out("out"); for(int i = 0; i < matrix->get_size(); i++) for(int j = 0; j < matrix->get_size(); j++) out << matrix->get(i, j) << std::endl; out.close(); dp.get_last_profiling_output(std::cout); // Solve the matrix problem. info("Solving the matrix problem."); if(solver->solve()) if(!SHOCK_CAPTURING) Solution<double>::vector_to_solutions(solver->get_sln_vector(), Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<Solution<double> *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); else { FluxLimiter flux_limiter(FluxLimiter::Kuzmin, solver->get_sln_vector(), Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); flux_limiter.limit_second_orders_according_to_detector(); flux_limiter.limit_according_to_detector(); flux_limiter.get_limited_solutions(Hermes::vector<Solution<double> *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); } else error ("Matrix solver failed.\n"); CFL.calculate_semi_implicit(Hermes::vector<Solution<double> *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), &mesh, time_step); // Visualization. if((iteration - 1) % EVERY_NTH_STEP == 0) { // Hermes visualization. if(HERMES_VISUALIZATION) { Mach_number.reinit(); pressure.reinit(); pressure_view.show(&pressure); Mach_number_view.show(&Mach_number); } // Output solution in VTK format. if(VTK_VISUALIZATION) { pressure.reinit(); Mach_number.reinit(); Linearizer<double> lin; char filename[40]; sprintf(filename, "pressure-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", true); sprintf(filename, "Mach number-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", true); } } } pressure_view.close(); Mach_number_view.close(); return 0; }
int main() { // Time measurement. TimePeriod cpu_time; cpu_time.tick(); // Create coarse mesh, set Dirichlet BC, enumerate basis functions. Space* space = new Space(A, B, NELEM, DIR_BC_LEFT, DIR_BC_RIGHT, P_INIT, NEQ); info("N_dof = %d.", Space::get_num_dofs(space)); // Initialize the weak formulation. WeakForm wf; wf.add_matrix_form(jacobian); wf.add_vector_form(residual); double elem_errors[MAX_ELEM_NUM]; // This array decides what // elements will be refined. ElemPtr2 ref_elem_pairs[MAX_ELEM_NUM]; // To store element pairs from the // FTR solution. Decides how // elements will be hp-refined. for (int i=0; i < MAX_ELEM_NUM; i++) { ref_elem_pairs[i][0] = new Element(); ref_elem_pairs[i][1] = new Element(); } // DOF and CPU convergence graphs. SimpleGraph graph_dof_exact, graph_cpu_exact; // Adaptivity loop: int as = 1; bool done = false; do { info("---- Adaptivity step %d:", as); // Initialize the FE problem. bool is_linear = false; DiscreteProblem *dp_coarse = new DiscreteProblem(&wf, space, is_linear); // Newton's loop on coarse mesh. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec_coarse = new double[Space::get_num_dofs(space)]; get_coeff_vector(space, coeff_vec_coarse); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix_coarse = create_matrix(matrix_solver); Vector* rhs_coarse = create_vector(matrix_solver); Solver* solver_coarse = create_linear_solver(matrix_solver, matrix_coarse, rhs_coarse); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof_coarse = Space::get_num_dofs(space); // Assemble the Jacobian matrix and residual vector. dp_coarse->assemble(matrix_coarse, rhs_coarse); // Calculate the l2-norm of residual vector. double res_l2_norm = get_l2_norm(rhs_coarse); // Info for user. info("---- Newton iter %d, ndof %d, res. l2 norm %g", it, Space::get_num_dofs(space), res_l2_norm); // If l2 norm of the residual vector is within tolerance, then quit. // NOTE: at least one full iteration forced // here because sometimes the initial // residual on fine mesh is too small. if(res_l2_norm < NEWTON_TOL_COARSE && it > 1) break; // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). for(int i=0; i<ndof_coarse; i++) rhs_coarse->set(i, -rhs_coarse->get(i)); // Solve the linear system. if(!solver_coarse->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof_coarse; i++) coeff_vec_coarse[i] += solver_coarse->get_solution()[i]; // If the maximum number of iteration has been reached, then quit. if (it >= NEWTON_MAX_ITER) error ("Newton method did not converge."); // Copy coefficients from vector y to elements. set_coeff_vector(coeff_vec_coarse, space); it++; } // Cleanup. delete matrix_coarse; delete rhs_coarse; delete solver_coarse; delete [] coeff_vec_coarse; delete dp_coarse; // For every element perform its fast trial refinement (FTR), // calculate the norm of the difference between the FTR // solution and the coarse space solution, and store the // error in the elem_errors[] array. int n_elem = space->get_n_active_elem(); for (int i=0; i < n_elem; i++) { info("=== Starting FTR of Elem [%d].", i); // Replicate coarse space including solution. Space *space_ref_local = space->replicate(); // Perform FTR of element 'i' space_ref_local->reference_refinement(i, 1); info("Elem [%d]: fine space created (%d DOF).", i, space_ref_local->assign_dofs()); // Initialize the FE problem. bool is_linear = false; DiscreteProblem* dp = new DiscreteProblem(&wf, space_ref_local, is_linear); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix = create_matrix(matrix_solver); Vector* rhs = create_vector(matrix_solver); Solver* solver = create_linear_solver(matrix_solver, matrix, rhs); // Newton's loop on the FTR space. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec = new double[Space::get_num_dofs(space_ref_local)]; get_coeff_vector(space_ref_local, coeff_vec); memset(coeff_vec, 0, Space::get_num_dofs(space_ref_local)*sizeof(double)); int it = 1; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(space_ref_local); // Assemble the Jacobian matrix and residual vector. dp->assemble(matrix, rhs); // Calculate the l2-norm of residual vector. double res_l2_norm = get_l2_norm(rhs); // Info for user. info("---- Newton iter %d, ndof %d, res. l2 norm %g", it, Space::get_num_dofs(space_ref_local), res_l2_norm); // If l2 norm of the residual vector is within tolerance, then quit. // NOTE: at least one full iteration forced // here because sometimes the initial // residual on fine mesh is too small. if(res_l2_norm < NEWTON_TOL_REF && it > 1) break; // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). for(int i=0; i<ndof; i++) rhs->set(i, -rhs->get(i)); // Solve the linear system. if(!solver->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof; i++) coeff_vec[i] += solver->get_solution()[i]; // If the maximum number of iteration has been reached, then quit. if (it >= NEWTON_MAX_ITER) error ("Newton method did not converge."); // Copy coefficients from vector y to elements. set_coeff_vector(coeff_vec, space_ref_local); it++; } // Cleanup. delete matrix; delete rhs; delete solver; delete dp; delete [] coeff_vec; // Print FTR solution (enumerated). Linearizer *lxx = new Linearizer(space_ref_local); char out_filename[255]; sprintf(out_filename, "solution_ref_%d.gp", i); lxx->plot_solution(out_filename); delete lxx; // Calculate norm of the difference between the coarse space // and FTR solutions. // NOTE: later we want to look at the difference in some quantity // of interest rather than error in global norm. double err_est_array[MAX_ELEM_NUM]; elem_errors[i] = calc_err_est(NORM, space, space_ref_local, err_est_array) * 100; info("Elem [%d]: absolute error (est) = %g%%", i, elem_errors[i]); // Copy the reference element pair for element 'i'. // into the ref_elem_pairs[i][] array Iterator *I = new Iterator(space); Iterator *I_ref = new Iterator(space_ref_local); Element *e, *e_ref; while (1) { e = I->next_active_element(); e_ref = I_ref->next_active_element(); if (e->id == i) { e_ref->copy_into(ref_elem_pairs[e->id][0]); // coarse element 'e' was split in space. if (e->level != e_ref->level) { e_ref = I_ref->next_active_element(); e_ref->copy_into(ref_elem_pairs[e->id][1]); } break; } } delete I; delete I_ref; delete space_ref_local; } // Time measurement. cpu_time.tick(); // If exact solution available, also calculate exact error. if (EXACT_SOL_PROVIDED) { // Calculate element errors wrt. exact solution. double err_exact_rel = calc_err_exact(NORM, space, exact_sol, NEQ, A, B) * 100; // Info for user. info("Relative error (exact) = %g %%", err_exact_rel); // Add entry to DOF and CPU convergence graphs. graph_dof_exact.add_values(Space::get_num_dofs(space), err_exact_rel); graph_cpu_exact.add_values(cpu_time.accumulated(), err_exact_rel); } // Calculate max FTR error. double max_ftr_error = 0; for (int i=0; i < space->get_n_active_elem(); i++) { if (elem_errors[i] > max_ftr_error) max_ftr_error = elem_errors[i]; } info("Max FTR error = %g%%.", max_ftr_error); // Decide whether the max. FTR error is sufficiently small. if(max_ftr_error < TOL_ERR_FTR) break; // debug //if (as == 4) break; // Returns updated coarse space with the last solution on it. adapt(NORM, ADAPT_TYPE, THRESHOLD, elem_errors, space, ref_elem_pairs); // Plot spaces, results, and errors. adapt_plotting(space, ref_elem_pairs, NORM, EXACT_SOL_PROVIDED, exact_sol); as++; } while (done == false); info("Total running time: %g s", cpu_time.accumulated()); // Save convergence graphs. graph_dof_exact.save("conv_dof_exact.dat"); graph_cpu_exact.save("conv_cpu_exact.dat"); return 0; }
int main() { // Create coarse mesh, set Dirichlet BC, enumerate // basis functions Mesh *mesh = new Mesh(A, B, N_elem, P_init, N_eq); mesh->set_bc_left_dirichlet(0, Val_dir_left); mesh->set_bc_right_dirichlet(0, Val_dir_right); mesh->assign_dofs(); // Create discrete problem on coarse mesh DiscreteProblem *dp = new DiscreteProblem(); dp->add_matrix_form(0, 0, jacobian); dp->add_vector_form(0, residual); // Convergence graph wrt. the number of degrees of freedom // (goal-oriented adaptivity) GnuplotGraph graph_ftr; graph_ftr.set_log_y(); graph_ftr.set_captions("Convergence History", "Degrees of Freedom", "QOI error"); graph_ftr.add_row("QOI error - FTR (exact)", "k", "-", "o"); graph_ftr.add_row("QOI error - FTR (est)", "k", "--"); // Main adaptivity loop int adapt_iterations = 1; double ftr_errors[MAX_ELEM_NUM]; // This array decides what // elements will be refined. ElemPtr2 ref_ftr_pairs[MAX_ELEM_NUM]; // To store element pairs from the // FTR solution. Decides how // elements will be hp-refined. for (int i=0; i < MAX_ELEM_NUM; i++) { ref_ftr_pairs[i][0] = new Element(); ref_ftr_pairs[i][1] = new Element(); } while(1) { printf("============ Adaptivity step %d ============\n", adapt_iterations); printf("N_dof = %d\n", mesh->get_n_dof()); // Newton's loop on coarse mesh int success; if(JFNK == 0) { newton(dp, mesh, NULL, NEWTON_TOL_COARSE, NEWTON_MAXITER); } else { jfnk_cg(dp, mesh, MATRIX_SOLVER_TOL, MATRIX_SOLVER_MAXITER, JFNK_EPSILON, NEWTON_TOL_COARSE, NEWTON_MAXITER); } // For every element perform its fast trial refinement (FTR), // calculate the norm of the difference between the FTR // solution and the coarse mesh solution, and store the // error in the ftr_errors[] array. int n_elem = mesh->get_n_active_elem(); double max_qoi_err_est = 0; for (int i=0; i < n_elem; i++) { printf("=== Starting FTR of Elem [%d]\n", i); // Replicate coarse mesh including solution. Mesh *mesh_ref_local = mesh->replicate(); // Perform FTR of element 'i' mesh_ref_local->reference_refinement(i, 1); printf("Elem [%d]: fine mesh created (%d DOF).\n", i, mesh_ref_local->assign_dofs()); // Newton's loop on the FTR mesh if(JFNK == 0) { newton(dp, mesh_ref_local, NULL, NEWTON_TOL_COARSE, NEWTON_MAXITER); } else { jfnk_cg(dp, mesh_ref_local, MATRIX_SOLVER_TOL, MATRIX_SOLVER_MAXITER, JFNK_EPSILON, NEWTON_TOL_REF, NEWTON_MAXITER); } // Print FTR solution (enumerated) Linearizer *lxx = new Linearizer(mesh_ref_local); char out_filename[255]; sprintf(out_filename, "solution_ref_%d.gp", i); lxx->plot_solution(out_filename); delete lxx; // Calculate FTR errors for refinement purposes if (GOAL_ORIENTED == 1) { // Use quantity of interest. double qoi_est = quantity_of_interest(mesh, X_QOI); double qoi_ref_est = quantity_of_interest(mesh_ref_local, X_QOI); ftr_errors[i] = fabs(qoi_ref_est - qoi_est); } else { // Use global norm double err_est_array[MAX_ELEM_NUM]; ftr_errors[i] = calc_error_estimate(NORM, mesh, mesh_ref_local, err_est_array); } // Calculating maximum of QOI FTR error for plotting purposes if (GOAL_ORIENTED == 1) { if (ftr_errors[i] > max_qoi_err_est) max_qoi_err_est = ftr_errors[i]; } else { double qoi_est = quantity_of_interest(mesh, X_QOI); double qoi_ref_est = quantity_of_interest(mesh_ref_local, X_QOI); double err_est = fabs(qoi_ref_est - qoi_est); if (err_est > max_qoi_err_est) max_qoi_err_est = err_est; } // Copy the reference element pair for element 'i' // into the ref_ftr_pairs[i][] array Iterator *I = new Iterator(mesh); Iterator *I_ref = new Iterator(mesh_ref_local); Element *e, *e_ref; while (1) { e = I->next_active_element(); e_ref = I_ref->next_active_element(); if (e->id == i) { e_ref->copy_into(ref_ftr_pairs[e->id][0]); // coarse element 'e' was split in space if (e->level != e_ref->level) { e_ref = I_ref->next_active_element(); e_ref->copy_into(ref_ftr_pairs[e->id][1]); } break; } } delete I; delete I_ref; delete mesh_ref_local; } // Add entries to convergence graphs if (EXACT_SOL_PROVIDED) { double qoi_est = quantity_of_interest(mesh, X_QOI); double u[MAX_EQN_NUM], dudx[MAX_EQN_NUM]; exact_sol(X_QOI, u, dudx); double err_qoi_exact = fabs(u[0] - qoi_est); // plotting error in quantity of interest wrt. exact value graph_ftr.add_values(0, mesh->get_n_dof(), err_qoi_exact); } graph_ftr.add_values(1, mesh->get_n_dof(), max_qoi_err_est); // Decide whether the max. FTR error in the quantity of interest // is sufficiently small if(max_qoi_err_est < TOL_ERR_QOI) break; // debug if (adapt_iterations == 3) break; // Returns updated coarse mesh with the last solution on it. adapt(NORM, ADAPT_TYPE, THRESHOLD, ftr_errors, mesh, ref_ftr_pairs); adapt_iterations++; } // Plot meshes, results, and errors adapt_plotting(mesh, ref_ftr_pairs, NORM, EXACT_SOL_PROVIDED, exact_sol); // Save convergence graph graph_ftr.save("conv_dof.gp"); printf("Done.\n"); return 1; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("motor.mesh", &mesh); // Enter boundary markers. BCTypes bc_types; bc_types.add_bc_dirichlet(Hermes::vector<int>(OUTER_BDY, STATOR_BDY)); // Enter Dirichlet boundary values. BCValues bc_values; bc_values.add_const(STATOR_BDY, VOLTAGE); bc_values.add_const(OUTER_BDY, 0.0); // Create an H1 space with default shapeset. H1Space space(&mesh, &bc_types, &bc_values, P_INIT); // Initialize the weak formulation. int adapt_order_increase = 1; double adapt_rel_error_tol = 1e1; WeakForm wf; if (ADAPTIVE_QUADRATURE) { info("Adaptive quadrature ON."); wf.add_matrix_form(biform1, HERMES_SYM, MATERIAL_1, Hermes::vector<MeshFunction*>(), adapt_order_increase, adapt_rel_error_tol); wf.add_matrix_form(biform2, HERMES_SYM, MATERIAL_2, Hermes::vector<MeshFunction*>(), adapt_order_increase, adapt_rel_error_tol); } else { info("Adaptive quadrature OFF."); wf.add_matrix_form(callback(biform1), HERMES_SYM, MATERIAL_1); wf.add_matrix_form(callback(biform2), HERMES_SYM, MATERIAL_2); } // Initialize coarse and reference mesh solution. Solution sln, ref_sln; // Initialize refinement selector. H1ProjBasedSelector selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER); // Initialize views. ScalarView sview("Solution", new WinGeom(0, 0, 410, 600)); sview.fix_scale_width(50); sview.show_mesh(false); OrderView oview("Polynomial orders", new WinGeom(420, 0, 400, 600)); // DOF and CPU convergence graphs initialization. SimpleGraph graph_dof, graph_cpu; // Time measurement. TimePeriod cpu_time; cpu_time.tick(); // Adaptivity loop: int as = 1; bool done = false; do { info("---- Adaptivity step %d:", as); // Construct globally refined reference mesh and setup reference space. Space* ref_space = construct_refined_space(&space); // Initialize matrix solver. SparseMatrix* matrix = create_matrix(matrix_solver); Vector* rhs = create_vector(matrix_solver); Solver* solver = create_linear_solver(matrix_solver, matrix, rhs); // Assemble reference problem. info("Solving on reference mesh."); bool is_linear = true; DiscreteProblem* dp = new DiscreteProblem(&wf, ref_space, is_linear); dp->assemble(matrix, rhs); // Time measurement. cpu_time.tick(); // Solve the linear system of the reference problem. // If successful, obtain the solution. if(solver->solve()) Solution::vector_to_solution(solver->get_solution(), ref_space, &ref_sln); else error ("Matrix solver failed.\n"); // Project the fine mesh solution onto the coarse mesh. info("Projecting reference solution on coarse mesh."); OGProjection::project_global(&space, &ref_sln, &sln, matrix_solver); // Time measurement. cpu_time.tick(); // VTK output. if (VTK_OUTPUT) { // Output solution in VTK format. Linearizer lin; char* title = new char[100]; sprintf(title, "sln-%d.vtk", as); lin.save_solution_vtk(&sln, title, "Potential", false); info("Solution in VTK format saved to file %s.", title); // Output mesh and element orders in VTK format. Orderizer ord; sprintf(title, "ord-%d.vtk", as); ord.save_orders_vtk(&space, title); info("Element orders in VTK format saved to file %s.", title); } // View the coarse mesh solution and polynomial orders. if (HERMES_VISUALIZATION) { sview.show(&sln); oview.show(&space); } // Skip visualization time. cpu_time.tick(HERMES_SKIP); // Calculate element errors and total error estimate. info("Calculating error estimate."); Adapt* adaptivity = new Adapt(&space); bool solutions_for_adapt = true; // In the following function, the Boolean parameter "solutions_for_adapt" determines whether // the calculated errors are intended for use with adaptivity (this may not be the case, for example, // when error wrt. an exact solution is calculated). The default value is solutions_for_adapt = true, // The last parameter "error_flags" determine whether the total and element errors are treated as // absolute or relative. Its default value is error_flags = HERMES_TOTAL_ERROR_REL | HERMES_ELEMENT_ERROR_REL. // In subsequent examples and benchmarks, these two parameters will be often used with // their default values, and thus they will not be present in the code explicitly. double err_est_rel = adaptivity->calc_err_est(&sln, &ref_sln, solutions_for_adapt, HERMES_TOTAL_ERROR_REL | HERMES_ELEMENT_ERROR_REL) * 100; // Report results. info("ndof_coarse: %d, ndof_fine: %d, err_est_rel: %g%%", Space::get_num_dofs(&space), Space::get_num_dofs(ref_space), err_est_rel); // Time measurement. cpu_time.tick(); // Add entry to DOF and CPU convergence graphs. graph_dof.add_values(Space::get_num_dofs(&space), err_est_rel); graph_dof.save("conv_dof_est.dat"); graph_cpu.add_values(cpu_time.accumulated(), err_est_rel); graph_cpu.save("conv_cpu_est.dat"); // If err_est too large, adapt the mesh. if (err_est_rel < ERR_STOP) done = true; else { info("Adapting coarse mesh."); done = adaptivity->adapt(&selector, THRESHOLD, STRATEGY, MESH_REGULARITY); // Increase the counter of performed adaptivity steps. if (done == false) as++; } if (Space::get_num_dofs(&space) >= NDOF_STOP) done = true; // Clean up. delete solver; delete matrix; delete rhs; delete adaptivity; if(done == false) delete ref_space->get_mesh(); delete ref_space; delete dp; } while (done == false); verbose("Total running time: %g s", cpu_time.accumulated()); // Show the reference solution - the final result. sview.set_title("Fine mesh solution"); sview.show_mesh(false); sview.show(&ref_sln); // Wait for all views to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; MeshReaderH2DXML mloader; mloader.load("domain-arcs.xml", &mesh); mesh.refine_towards_boundary(BDY_SOLID_WALL_PROFILE, INIT_REF_NUM_BOUNDARY_ANISO, true, true); mesh.refine_towards_vertex(0, INIT_REF_NUM_VERTEX, true); MeshView m; m.show(&mesh); m.wait_for_close(); // Initialize boundary condition types and spaces with default shapesets. L2Space<double>space_rho(&mesh, P_INIT); L2Space<double>space_rho_v_x(&mesh, P_INIT); L2Space<double>space_rho_v_y(&mesh, P_INIT); L2Space<double>space_e(&mesh, P_INIT); int ndof = Space<double>::get_num_dofs(Hermes::vector<const Space<double>*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); info("Initial coarse ndof: %d", ndof); // Initialize solutions, set initial conditions. ConstantSolution<double> sln_rho(&mesh, RHO_EXT); ConstantSolution<double> sln_rho_v_x(&mesh, RHO_EXT * V1_EXT); ConstantSolution<double> sln_rho_v_y(&mesh, RHO_EXT * V2_EXT); ConstantSolution<double> sln_e(&mesh, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); ConstantSolution<double> prev_rho(&mesh, RHO_EXT); ConstantSolution<double> prev_rho_v_x(&mesh, RHO_EXT * V1_EXT); ConstantSolution<double> prev_rho_v_y(&mesh, RHO_EXT * V2_EXT); ConstantSolution<double> prev_e(&mesh, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); Solution<double> rsln_rho, rsln_rho_v_x, rsln_rho_v_y, rsln_e; // Numerical flux. VijayasundaramNumericalFlux num_flux(KAPPA); // Initialize weak formulation. EulerEquationsWeakFormSemiImplicitMultiComponent wf(&num_flux, KAPPA, RHO_EXT, V1_EXT, V2_EXT, P_EXT, BDY_SOLID_WALL, BDY_SOLID_WALL_PROFILE, BDY_INLET, BDY_OUTLET, &prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e); // Filters for visualization of Mach number, pressure and entropy. MachNumberFilter Mach_number(Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); PressureFilter pressure(Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); EntropyFilter entropy(Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA, RHO_EXT, P_EXT); ScalarView pressure_view("Pressure", new WinGeom(0, 0, 600, 300)); ScalarView Mach_number_view("Mach number", new WinGeom(700, 0, 600, 300)); ScalarView entropy_production_view("Entropy estimate", new WinGeom(0, 400, 600, 300)); OrderView space_view("Space", new WinGeom(700, 400, 600, 300)); // Initialize refinement selector. L2ProjBasedSelector<double> selector(CAND_LIST, CONV_EXP, MAX_P_ORDER); selector.set_error_weights(1.0, 1.0, 1.0); // Set up CFL calculation class. CFLCalculation CFL(CFL_NUMBER, KAPPA); // Look for a saved solution on the disk. Continuity<double> continuity(Continuity<double>::onlyTime); int iteration = 0; double t = 0; bool loaded_now = false; if(REUSE_SOLUTION && continuity.have_record_available()) { continuity.get_last_record()->load_mesh(&mesh); continuity.get_last_record()->load_spaces(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<SpaceType>(HERMES_L2_SPACE, HERMES_L2_SPACE, HERMES_L2_SPACE, HERMES_L2_SPACE), Hermes::vector<Mesh *>(&mesh, &mesh, &mesh, &mesh)); continuity.get_last_record()->load_time_step_length(time_step); t = continuity.get_last_record()->get_time() + time_step; iteration = continuity.get_num() * EVERY_NTH_STEP + 1; loaded_now = true; } // Time stepping loop. for(; t < 5.0; t += time_step) { CFL.set_number(CFL_NUMBER + (t/5.0) * 10.0); info("---- Time step %d, time %3.5f.", iteration++, t); // Periodic global derefinements. if (iteration > 1 && iteration % UNREF_FREQ == 0 && REFINEMENT_COUNT > 0) { info("Global mesh derefinement."); REFINEMENT_COUNT = 0; space_rho.unrefine_all_mesh_elements(true); space_rho.adjust_element_order(-1, P_INIT); space_rho_v_x.copy_orders(&space_rho); space_rho_v_y.copy_orders(&space_rho); space_e.copy_orders(&space_rho); } // Adaptivity loop: int as = 1; int ndofs_prev = 0; bool done = false; do { info("---- Adaptivity step %d:", as); // Construct globally refined reference mesh and setup reference space. int order_increase = 1; Hermes::vector<Space<double> *>* ref_spaces = Space<double>::construct_refined_spaces(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), order_increase); Hermes::vector<const Space<double> *> ref_spaces_const((*ref_spaces)[0], (*ref_spaces)[1], (*ref_spaces)[2], (*ref_spaces)[3]); if(ndofs_prev != 0) if(Space<double>::get_num_dofs(ref_spaces_const) == ndofs_prev) selector.set_error_weights(2.0 * selector.get_error_weight_h(), 1.0, 1.0); else selector.set_error_weights(1.0, 1.0, 1.0); ndofs_prev = Space<double>::get_num_dofs(ref_spaces_const); // Project the previous time level solution onto the new fine mesh. info("Projecting the previous time level solution onto the new fine mesh."); if(loaded_now) { loaded_now = false; continuity.get_last_record()->load_solutions(Hermes::vector<Solution<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), Hermes::vector<Space<double> *>((*ref_spaces)[0], (*ref_spaces)[1], (*ref_spaces)[2], (*ref_spaces)[3])); } else { OGProjection<double>::project_global(ref_spaces_const, Hermes::vector<Solution<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), Hermes::vector<Solution<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), matrix_solver, Hermes::vector<Hermes::Hermes2D::ProjNormType>()); if(iteration > std::max((int)(continuity.get_num() * EVERY_NTH_STEP + 2), 1) && as > 1) { delete rsln_rho.get_mesh(); delete rsln_rho.get_space(); rsln_rho.own_mesh = false; delete rsln_rho_v_x.get_mesh(); delete rsln_rho_v_x.get_space(); rsln_rho_v_x.own_mesh = false; delete rsln_rho_v_y.get_mesh(); delete rsln_rho_v_y.get_space(); rsln_rho_v_y.own_mesh = false; delete rsln_e.get_mesh(); delete rsln_e.get_space(); rsln_e.own_mesh = false; } } // Report NDOFs. info("ndof_coarse: %d, ndof_fine: %d.", Space<double>::get_num_dofs(Hermes::vector<const Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)), Space<double>::get_num_dofs(ref_spaces_const)); // Assemble the reference problem. info("Solving on reference mesh."); DiscreteProblem<double> dp(&wf, ref_spaces_const); SparseMatrix<double>* matrix = create_matrix<double>(matrix_solver); Vector<double>* rhs = create_vector<double>(matrix_solver); LinearSolver<double>* solver = create_linear_solver<double>(matrix_solver, matrix, rhs); wf.set_time_step(time_step); // Assemble the stiffness matrix and rhs. info("Assembling the stiffness matrix and right-hand side vector."); dp.assemble(matrix, rhs); // Solve the matrix problem. info("Solving the matrix problem."); if(solver->solve()) if(!SHOCK_CAPTURING) Solution<double>::vector_to_solutions(solver->get_sln_vector(), ref_spaces_const, Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)); else { FluxLimiter flux_limiter(FluxLimiter::Kuzmin, solver->get_sln_vector(), ref_spaces_const, true); flux_limiter.limit_second_orders_according_to_detector(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); flux_limiter.limit_according_to_detector(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); flux_limiter.get_limited_solutions(Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)); } else error ("Matrix solver failed.\n"); // Project the fine mesh solution onto the coarse mesh. info("Projecting reference solution on coarse mesh."); OGProjection<double>::project_global(Hermes::vector<const Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e), Hermes::vector<Solution<double>*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), matrix_solver, Hermes::vector<ProjNormType>(HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM)); // Calculate element errors and total error estimate. info("Calculating error estimate."); Adapt<double>* adaptivity = new Adapt<double>(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<ProjNormType>(HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM)); double err_est_rel_total = adaptivity->calc_err_est(Hermes::vector<Solution<double>*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)) * 100; CFL.calculate_semi_implicit(Hermes::vector<Solution<double> *>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e), (*ref_spaces)[0]->get_mesh(), time_step); // Report results. info("err_est_rel: %g%%", err_est_rel_total); // If err_est too large, adapt the mesh. if (err_est_rel_total < ERR_STOP) done = true; else { info("Adapting coarse mesh."); if (Space<double>::get_num_dofs(Hermes::vector<const Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)) >= NDOF_STOP) done = true; else { REFINEMENT_COUNT++; done = adaptivity->adapt(Hermes::vector<RefinementSelectors::Selector<double> *>(&selector, &selector, &selector, &selector), THRESHOLD, STRATEGY, MESH_REGULARITY); } if(!done) as++; } // Visualization and saving on disk. if(done && (iteration - 1) % EVERY_NTH_STEP == 0 && iteration > 1) { // Hermes visualization. if(HERMES_VISUALIZATION) { Mach_number.reinit(); pressure.reinit(); entropy.reinit(); pressure_view.show(&pressure); entropy_production_view.show(&entropy); Mach_number_view.show(&Mach_number); pressure_view.save_numbered_screenshot("Pressure-%u.bmp", iteration - 1, true); Mach_number_view.save_numbered_screenshot("Mach-%u.bmp", iteration - 1, true); } // Output solution in VTK format. if(VTK_VISUALIZATION) { pressure.reinit(); Mach_number.reinit(); Linearizer lin; char filename[40]; sprintf(filename, "Pressure-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", false); sprintf(filename, "Mach number-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", false); } // Save a current state on the disk. if(iteration > 1) { continuity.add_record(t); continuity.get_last_record()->save_mesh(&mesh); continuity.get_last_record()->save_spaces(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); continuity.get_last_record()->save_solutions(Hermes::vector<Solution<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); continuity.get_last_record()->save_time_step_length(time_step); } } // Clean up. delete solver; delete matrix; delete rhs; delete adaptivity; } while (done == false); // Copy the solutions into the previous time level ones. prev_rho.copy(&rsln_rho); prev_rho_v_x.copy(&rsln_rho_v_x); prev_rho_v_y.copy(&rsln_rho_v_y); prev_e.copy(&rsln_e); delete rsln_rho.get_mesh(); delete rsln_rho.get_space(); rsln_rho.own_mesh = false; delete rsln_rho_v_x.get_mesh(); delete rsln_rho_v_x.get_space(); rsln_rho_v_x.own_mesh = false; delete rsln_rho_v_y.get_mesh(); delete rsln_rho_v_y.get_space(); rsln_rho_v_y.own_mesh = false; delete rsln_e.get_mesh(); delete rsln_e.get_space(); rsln_e.own_mesh = false; } pressure_view.close(); entropy_production_view.close(); Mach_number_view.close(); return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("GAMM-channel.mesh", &mesh); // Perform initial mesh refinements. for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(0, true); mesh.refine_towards_boundary(BDY_SOLID_WALL_BOTTOM, INIT_REF_NUM_BOUNDARY_ANISO, true, false, true); mesh.refine_towards_boundary(BDY_SOLID_WALL_BOTTOM, INIT_REF_NUM_BOUNDARY_ISO, false, false, true); // Initialize boundary condition types and spaces with default shapesets. L2Space space_rho(&mesh, P_INIT); L2Space space_rho_v_x(&mesh, P_INIT); L2Space space_rho_v_y(&mesh,P_INIT); L2Space space_e(&mesh, P_INIT); int ndof = Space::get_num_dofs(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); info("ndof: %d", ndof); // Initialize solutions, set initial conditions. InitialSolutionEulerDensity sln_rho(&mesh, RHO_EXT); InitialSolutionEulerDensityVelX sln_rho_v_x(&mesh, RHO_EXT * V1_EXT); InitialSolutionEulerDensityVelY sln_rho_v_y(&mesh, RHO_EXT * V2_EXT); InitialSolutionEulerDensityEnergy sln_e(&mesh, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); InitialSolutionEulerDensity prev_rho(&mesh, RHO_EXT); InitialSolutionEulerDensityVelX prev_rho_v_x(&mesh, RHO_EXT * V1_EXT); InitialSolutionEulerDensityVelY prev_rho_v_y(&mesh, RHO_EXT * V2_EXT); InitialSolutionEulerDensityEnergy prev_e(&mesh, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); Solution rsln_rho, rsln_rho_v_x, rsln_rho_v_y, rsln_e; // Numerical flux. OsherSolomonNumericalFlux num_flux(KAPPA); // Initialize weak formulation. EulerEquationsWeakFormImplicitMultiComponent wf(&num_flux, KAPPA, RHO_EXT, V1_EXT, V2_EXT, P_EXT, BDY_SOLID_WALL_BOTTOM, BDY_SOLID_WALL_TOP, BDY_INLET, BDY_OUTLET, &prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, PRECONDITIONING); wf.set_time_step(time_step); // Filters for visualization of Mach number, pressure and entropy. MachNumberFilter Mach_number(Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); PressureFilter pressure(Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); EntropyFilter entropy(Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA, RHO_EXT, P_EXT); ScalarView pressure_view("Pressure", new WinGeom(0, 0, 600, 300)); ScalarView Mach_number_view("Mach number", new WinGeom(700, 0, 600, 300)); ScalarView entropy_production_view("Entropy estimate", new WinGeom(0, 400, 600, 300)); /* ScalarView s1("1", new WinGeom(0, 0, 600, 300)); ScalarView s2("2", new WinGeom(700, 0, 600, 300)); ScalarView s3("3", new WinGeom(0, 400, 600, 300)); ScalarView s4("4", new WinGeom(700, 400, 600, 300)); */ // Initialize refinement selector. L2ProjBasedSelector selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER); // Select preconditioner. RCP<Precond> pc = rcp(new IfpackPrecond("point-relax")); int iteration = 0; double t = 0; for(t = 0.0; t < 3.0; t += time_step) { info("---- Time step %d, time %3.5f.", iteration++, t); // Periodic global derefinements. if (iteration > 1 && iteration % UNREF_FREQ == 0 && REFINEMENT_COUNT > 0) { REFINEMENT_COUNT = 0; info("Global mesh derefinement."); mesh.unrefine_all_elements(); space_rho.adjust_element_order(-1, P_INIT); space_rho_v_x.adjust_element_order(-1, P_INIT); space_rho_v_y.adjust_element_order(-1, P_INIT); space_e.adjust_element_order(-1, P_INIT); } // Adaptivity loop: int as = 1; bool done = false; do { info("---- Adaptivity step %d:", as); // Construct globally refined reference mesh and setup reference space. // Global polynomial order increase; int order_increase = 1; Hermes::vector<Space *>* ref_spaces = Space::construct_refined_spaces(Hermes::vector<Space *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), order_increase); // Report NDOFs. info("ndof_coarse: %d, ndof_fine: %d.", Space::get_num_dofs(Hermes::vector<Space *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)), Space::get_num_dofs(*ref_spaces)); // Project the previous time level solution onto the new fine mesh // in order to obtain initial vector for NOX. info("Projecting initial solution on the FE mesh."); scalar* coeff_vec = new scalar[Space::get_num_dofs(*ref_spaces)]; OGProjection::project_global(*ref_spaces, Hermes::vector<MeshFunction *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), coeff_vec); // Initialize the FE problem. bool is_linear = false; DiscreteProblem dp(&wf, *ref_spaces, is_linear); // Initialize NOX solver. NoxSolver solver(&dp, NOX_MESSAGE_TYPE); solver.set_ls_tolerance(NOX_LINEAR_TOLERANCE); solver.disable_abs_resid(); solver.set_conv_rel_resid(NOX_NONLINEAR_TOLERANCE); if(PRECONDITIONING) solver.set_precond(pc); info("Assembling by DiscreteProblem, solving by NOX."); solver.set_init_sln(coeff_vec); scalar* solution_vector = NULL; if (solver.solve()) { solution_vector = solver.get_solution(); Solution::vector_to_solutions(solution_vector, *ref_spaces, Hermes::vector<Solution *>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)); } else error("NOX failed."); info("Number of nonlin iterations: %d (norm of residual: %g)", solver.get_num_iters(), solver.get_residual()); info("Total number of iterations in linsolver: %d (achieved tolerance in the last step: %g)", solver.get_num_lin_iters(), solver.get_achieved_tol()); if(SHOCK_CAPTURING) { DiscontinuityDetector discontinuity_detector(*ref_spaces, Hermes::vector<Solution *>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)); std::set<int> discontinuous_elements = discontinuity_detector.get_discontinuous_element_ids(DISCONTINUITY_DETECTOR_PARAM); FluxLimiter flux_limiter(solution_vector, *ref_spaces, Hermes::vector<Solution *>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)); flux_limiter.limit_according_to_detector(discontinuous_elements); } // Project the fine mesh solution onto the coarse mesh. info("Projecting reference solution on coarse mesh."); OGProjection::project_global(Hermes::vector<Space *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<Solution *>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e), Hermes::vector<Solution *>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), matrix_solver, Hermes::vector<ProjNormType>(HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM)); // Calculate element errors and total error estimate. info("Calculating error estimate."); Adapt* adaptivity = new Adapt(Hermes::vector<Space *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<ProjNormType>(HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM)); double err_est_rel_total = adaptivity->calc_err_est(Hermes::vector<Solution *>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), Hermes::vector<Solution *>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)) * 100; // Report results. info("err_est_rel: %g%%", err_est_rel_total); // If err_est too large, adapt the mesh. if (err_est_rel_total < ERR_STOP) done = true; else { info("Adapting coarse mesh."); done = adaptivity->adapt(Hermes::vector<RefinementSelectors::Selector *>(&selector, &selector, &selector, &selector), THRESHOLD, STRATEGY, MESH_REGULARITY); REFINEMENT_COUNT++; if (Space::get_num_dofs(Hermes::vector<Space *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)) >= NDOF_STOP) done = true; else // Increase the counter of performed adaptivity steps. as++; } // Clean up. delete adaptivity; if(!done) for(unsigned int i = 0; i < ref_spaces->size(); i++) delete (*ref_spaces)[i]->get_mesh(); for(unsigned int i = 0; i < ref_spaces->size(); i++) delete (*ref_spaces)[i]; } while (done == false); // Copy the solutions into the previous time level ones. prev_rho.copy(&rsln_rho); prev_rho_v_x.copy(&rsln_rho_v_x); prev_rho_v_y.copy(&rsln_rho_v_y); prev_e.copy(&rsln_e); // Visualization. if((iteration - 1) % EVERY_NTH_STEP == 0) { // Hermes visualization. if(HERMES_VISUALIZATION) { Mach_number.reinit(); pressure.reinit(); entropy.reinit(); pressure_view.show(&pressure); entropy_production_view.show(&entropy); Mach_number_view.show(&Mach_number); /* s1.show(&prev_rho); s2.show(&prev_rho_v_x); s3.show(&prev_rho_v_y); s4.show(&prev_e); */ } // Output solution in VTK format. if(VTK_VISUALIZATION) { pressure.reinit(); Mach_number.reinit(); Linearizer lin; char filename[40]; sprintf(filename, "pressure-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", false); sprintf(filename, "pressure-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", true); sprintf(filename, "Mach number-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", false); sprintf(filename, "Mach number-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", true); } } } pressure_view.close(); entropy_production_view.close(); Mach_number_view.close(); /* s1.close(); s2.close(); s3.close(); s4.close(); */ return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh basemesh; H2DReader mloader; mloader.load("GAMM-channel.mesh", &basemesh); // Initialize the meshes. Mesh mesh_flow, mesh_concentration; mesh_flow.copy(&basemesh); mesh_concentration.copy(&basemesh); for(unsigned int i = 0; i < INIT_REF_NUM_CONCENTRATION; i++) mesh_concentration.refine_all_elements(); mesh_concentration.refine_towards_boundary(BDY_DIRICHLET_CONCENTRATION, INIT_REF_NUM_CONCENTRATION_BDY); mesh_flow.refine_towards_boundary(BDY_DIRICHLET_CONCENTRATION, INIT_REF_NUM_CONCENTRATION_BDY); for(unsigned int i = 0; i < INIT_REF_NUM_FLOW; i++) mesh_flow.refine_all_elements(); // Initialize boundary condition types and spaces with default shapesets. // For the concentration. EssentialBCs bcs_concentration; bcs_concentration.add_boundary_condition(new ConcentrationTimedepEssentialBC(BDY_DIRICHLET_CONCENTRATION, CONCENTRATION_EXT, CONCENTRATION_EXT_STARTUP_TIME)); bcs_concentration.add_boundary_condition(new ConcentrationTimedepEssentialBC(BDY_SOLID_WALL_TOP, 0.0, CONCENTRATION_EXT_STARTUP_TIME)); L2Space space_rho(&mesh_flow, P_INIT_FLOW); L2Space space_rho_v_x(&mesh_flow, P_INIT_FLOW); L2Space space_rho_v_y(&mesh_flow, P_INIT_FLOW); L2Space space_e(&mesh_flow, P_INIT_FLOW); // Space for concentration. H1Space space_c(&mesh_concentration, &bcs_concentration, P_INIT_CONCENTRATION); int ndof = Space::get_num_dofs(Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c)); info("ndof: %d", ndof); // Initialize solutions, set initial conditions. InitialSolutionEulerDensity prev_rho(&mesh_flow, RHO_EXT); InitialSolutionEulerDensityVelX prev_rho_v_x(&mesh_flow, RHO_EXT * V1_EXT); InitialSolutionEulerDensityVelY prev_rho_v_y(&mesh_flow, RHO_EXT * V2_EXT); InitialSolutionEulerDensityEnergy prev_e(&mesh_flow, QuantityCalculator::calc_energy(RHO_EXT, RHO_EXT * V1_EXT, RHO_EXT * V2_EXT, P_EXT, KAPPA)); InitialSolutionConcentration prev_c(&mesh_concentration, 0.0); // Numerical flux. OsherSolomonNumericalFlux num_flux(KAPPA); // Initialize weak formulation. EulerEquationsWeakFormSemiImplicitCoupled wf(&num_flux, KAPPA, RHO_EXT, V1_EXT, V2_EXT, P_EXT, BDY_SOLID_WALL_BOTTOM, BDY_SOLID_WALL_TOP, BDY_INLET, BDY_OUTLET, BDY_NATURAL_CONCENTRATION, &prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c, EPSILON, (P_INIT_FLOW == 0)); wf.set_time_step(time_step); // Initialize the FE problem. DiscreteProblem dp(&wf, Hermes::vector<Space*>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c)); // If the FE problem is in fact a FV problem. //if(P_INIT == 0) dp.set_fvm(); // Filters for visualization of Mach number, pressure and entropy. MachNumberFilter Mach_number(Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); PressureFilter pressure(Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); EntropyFilter entropy(Hermes::vector<MeshFunction*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA, RHO_EXT, P_EXT); /* ScalarView pressure_view("Pressure", new WinGeom(0, 0, 600, 300)); ScalarView Mach_number_view("Mach number", new WinGeom(700, 0, 600, 300)); ScalarView entropy_production_view("Entropy estimate", new WinGeom(0, 400, 600, 300)); ScalarView s5("Concentration", new WinGeom(700, 400, 600, 300)); */ ScalarView s1("1", new WinGeom(0, 0, 600, 300)); ScalarView s2("2", new WinGeom(700, 0, 600, 300)); ScalarView s3("3", new WinGeom(0, 400, 600, 300)); ScalarView s4("4", new WinGeom(700, 400, 600, 300)); ScalarView s5("Concentration", new WinGeom(350, 200, 600, 300)); // Set up the solver, matrix, and rhs according to the solver selection. SparseMatrix* matrix = create_matrix(matrix_solver); Vector* rhs = create_vector(matrix_solver); Solver* solver = create_linear_solver(matrix_solver, matrix, rhs); // Set up CFL calculation class. CFLCalculation CFL(CFL_NUMBER, KAPPA); // Set up Advection-Diffusion-Equation stability calculation class. ADEStabilityCalculation ADES(ADVECTION_STABILITY_CONSTANT, DIFFUSION_STABILITY_CONSTANT, EPSILON); int iteration = 0; double t = 0; for(t = 0.0; t < 100.0; t += time_step) { info("---- Time step %d, time %3.5f.", iteration++, t); // Set the current time step. wf.set_time_step(time_step); Space::update_essential_bc_values(&space_c, t); // Assemble stiffness matrix and rhs. info("Assembling the stiffness matrix and right-hand side vector."); dp.assemble(matrix, rhs); // Solve the matrix problem. info("Solving the matrix problem."); scalar* solution_vector = NULL; if(solver->solve()) { solution_vector = solver->get_solution(); Solution::vector_to_solutions(solution_vector, Hermes::vector<Space *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e, &space_c), Hermes::vector<Solution *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e, &prev_c)); } else error ("Matrix solver failed.\n"); if(SHOCK_CAPTURING) { DiscontinuityDetector discontinuity_detector(Hermes::vector<Space *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<Solution *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); std::set<int> discontinuous_elements = discontinuity_detector.get_discontinuous_element_ids(DISCONTINUITY_DETECTOR_PARAM); FluxLimiter flux_limiter(solution_vector, Hermes::vector<Space *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<Solution *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e)); flux_limiter.limit_according_to_detector(discontinuous_elements); } util_time_step = time_step; CFL.calculate_semi_implicit(Hermes::vector<Solution *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), &mesh_flow, util_time_step); time_step = util_time_step; ADES.calculate(Hermes::vector<Solution *>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y), &mesh_concentration, util_time_step); if(util_time_step < time_step) time_step = util_time_step; // Visualization. if((iteration - 1) % EVERY_NTH_STEP == 0) { // Hermes visualization. if(HERMES_VISUALIZATION) { /* Mach_number.reinit(); pressure.reinit(); entropy.reinit(); pressure_view.show(&pressure); entropy_production_view.show(&entropy); Mach_number_view.show(&Mach_number); s5.show(&prev_c); */ s1.show(&prev_rho); s2.show(&prev_rho_v_x); s3.show(&prev_rho_v_y); s4.show(&prev_e); s5.show(&prev_c); /* s1.save_numbered_screenshot("density%i.bmp", iteration, true); s2.save_numbered_screenshot("density_v_x%i.bmp", iteration, true); s3.save_numbered_screenshot("density_v_y%i.bmp", iteration, true); s4.save_numbered_screenshot("energy%i.bmp", iteration, true); s5.save_numbered_screenshot("concentration%i.bmp", iteration, true); */ //s5.wait_for_close(); } // Output solution in VTK format. if(VTK_VISUALIZATION) { pressure.reinit(); Mach_number.reinit(); Linearizer lin; char filename[40]; sprintf(filename, "pressure-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", false); sprintf(filename, "pressure-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", true); sprintf(filename, "Mach number-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", false); sprintf(filename, "Mach number-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", true); sprintf(filename, "Concentration-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_c, filename, "Concentration", true); sprintf(filename, "Concentration-3D-%i.vtk", iteration - 1); lin.save_solution_vtk(&prev_c, filename, "Concentration", true); } } } /* pressure_view.close(); entropy_production_view.close(); Mach_number_view.close(); s5.close(); */ s1.close(); s2.close(); s3.close(); s4.close(); s5.close(); return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; if (USE_XML_FORMAT == true) { MeshReaderH2DXML mloader; info("Reading mesh in XML format."); mloader.load("domain.xml", &mesh); } else { MeshReaderH2D mloader; info("Reading mesh in original format."); mloader.load("domain.mesh", &mesh); } // Perform initial mesh refinements. for(int i=0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); // Initialize boundary conditions DefaultEssentialBCConst<double> bc_essential("Bottom", T1); EssentialBCs<double> bcs(&bc_essential); // Create an H1 space with default shapeset. H1Space<double> space(&mesh, &bcs, P_INIT); int ndof = space.get_num_dofs(); info("ndof = %d", ndof); // Initialize the weak formulation. CustomWeakFormPoissonNewton wf(LAMBDA, ALPHA, T0, "Heat_flux"); // Initialize the FE problem. DiscreteProblem<double> dp(&wf, &space); // Initial coefficient vector for the Newton's method. double* coeff_vec = new double[ndof]; memset(coeff_vec, 0, ndof*sizeof(double)); // Initialize Newton solver. NewtonSolver<double> newton(&dp, matrix_solver); // Perform Newton's iteration. try { newton.solve(coeff_vec); } catch(Hermes::Exceptions::Exception e) { e.printMsg(); error("Newton's iteration failed."); } // Translate the resulting coefficient vector into a Solution. Solution<double> sln; Solution<double>::vector_to_solution(newton.get_sln_vector(), &space, &sln); // VTK output. if (VTK_VISUALIZATION) { // Output solution in VTK format. Linearizer lin; bool mode_3D = true; lin.save_solution_vtk(&sln, "sln.vtk", "Temperature", mode_3D); info("Solution in VTK format saved to file %s.", "sln.vtk"); // Output mesh and element orders in VTK format. Orderizer ord; ord.save_orders_vtk(&space, "ord.vtk"); info("Element orders in VTK format saved to file %s.", "ord.vtk"); } // Visualize the solution. if (HERMES_VISUALIZATION) { ScalarView view("Solution", new WinGeom(0, 0, 440, 350)); // Hermes uses adaptive FEM to approximate higher-order FE solutions with linear // triangles for OpenGL. The second parameter of View::show() sets the error // tolerance for that. Options are HERMES_EPS_LOW, HERMES_EPS_NORMAL (default), // HERMES_EPS_HIGH and HERMES_EPS_VERYHIGH. The size of the graphics file grows // considerably with more accurate representation, so use it wisely. view.show(&sln, HERMES_EPS_HIGH); View::wait(); } // Clean up. delete [] coeff_vec; return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh, basemesh; MeshReaderH2D mloader; mloader.load("domain.mesh", &basemesh); /* MeshView meshview("mesh", new WinGeom(0, 0, 500, 400)); meshview.show(&basemesh); View::wait();*/ // Perform initial mesh refinements (optional). for (int i=0; i < INIT_REF_NUM; i++) basemesh.refine_all_elements(); mesh.copy(&basemesh); // Initialize boundary conditions. DefaultEssentialBCConst<double> bc_essential(BDY_IN, 0.0); EssentialBCs<double> bcs(&bc_essential); // Create an H1 space with default shapeset. H1Space<double> space(&mesh, &bcs, P_INIT); // Initialize solution of lower & higher order Solution<double> low_sln, ref_sln, high_sln, sln; PrevSolution u_prev_time; // Previous time level solution (initialized by the initial condition). CustomInitialCondition initial_condition(&mesh); // Initialize the weak formulation. CustomWeakFormMassmatrix massmatrix(time_step); CustomWeakFormConvection convection; // Initialize views. ScalarView sview("Solution", new WinGeom(0, 500, 500, 400)); OrderView mview("mesh", new WinGeom(0, 0, 500, 400)); OrderView ref_mview("ref_mesh", new WinGeom(500, 0, 500, 400)); char title[100]; // Output solution in VTK format. Linearizer lin; Orderizer ord; bool mode_3D = true; // Create a refinement selector. H1ProjBasedSelector<double> selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER); //Initialize UMFPackMatrix<double> * mass_matrix = new UMFPackMatrix<double> ; //M_c/tau UMFPackMatrix<double> * conv_matrix = new UMFPackMatrix<double> ; //K double* u_L = NULL; double* u_H =NULL; double* ref_sln_double =NULL; int ref_ndof, ndof; double err_est_rel_total; Adapt<double> adaptivity(&space, HERMES_L2_NORM); OGProjection<double> ogProjection; Lumped_Projection lumpedProjection; Low_Order lowOrder(theta); High_Order highOrd(theta); Flux_Correction fluxCorrection(theta); Regularity_Estimator regEst(EPS_smooth); DiscreteProblem<double> dp_mass(&massmatrix, &space); DiscreteProblem<double> dp_convection(&convection, &space); // Time stepping loop: double current_time = 0.0; int ts = 1; do { Hermes::Mixins::Loggable::Static::info("Time step %d, time %3.5f", ts, current_time); Hermes::Hermes2D::Hermes2DApi.set_integral_param_value(Hermes::Hermes2D::numThreads,1); // Periodic global derefinement. if ((ts > 1 && ts % UNREF_FREQ == 0)||(space.get_num_dofs() >= NDOF_STOP)) { Hermes::Mixins::Loggable::Static::info("Global mesh derefinement."); switch (UNREF_METHOD) { case 1: mesh.copy(&basemesh); space.set_uniform_order(P_INIT); break; case 2: mesh.unrefine_all_elements(); space.set_uniform_order(P_INIT); break; case 3: mesh.unrefine_all_elements(); space.adjust_element_order(-1, -1, P_INIT, P_INIT); break; default: Exceptions::Exception("Wrong global derefinement method."); } } bool done = false; int as = 1; do { Hermes::Mixins::Loggable::Static::info("Time step %i, adap_step %i", ts, as); ndof = space.get_num_dofs(); //Unrefinement step /* if(as==1) { double* coeff_vec_smooth = new double[ndof]; if(ts==1) ogProjection.project_global(&space,&initial_condition, coeff_vec_smooth, HERMES_L2_NORM); else ogProjection.project_global(&space,&u_prev_time, coeff_vec_smooth, HERMES_L2_NORM); Solution<double>::vector_to_solution(coeff_vec_smooth, &space, &low_sln); // Calculate element errors and total error estimate. if(ts==1) err_est_rel_total = adaptivity.calc_err_est(&low_sln, &initial_condition) * 100; else err_est_rel_total = adaptivity.calc_err_est(&low_sln, &u_prev_time) * 100; adaptivity.unrefine(THRESHOLD_UNREF); delete [] coeff_vec_smooth; // Visualize the solution. if(HERMES_VISUALIZATION) { sprintf(title, "unrefined Mesh: Time %3.2f,timestep %i", current_time,ts); mview.set_title(title); mview.show(&space); } } */ ndof = space.get_num_dofs(); double* coeff_vec_smooth = new double[ndof]; int* smooth_elem_ref; //smoothness-check for projected data Hermes::Mixins::Loggable::Static::info("Projecting..."); if(ts==1) ogProjection.project_global(&space,&initial_condition, coeff_vec_smooth, HERMES_L2_NORM); else ogProjection.project_global(&space,&u_prev_time, coeff_vec_smooth, HERMES_L2_NORM); Hermes::Mixins::Loggable::Static::info("Calling get_smooth_elems()..."); smooth_elem_ref = regEst.get_smooth_elems(&space,coeff_vec_smooth); // Construct reference mesh and setup reference space. Mesh* ref_mesh = new Mesh; ref_mesh->copy(space.get_mesh()); Space<double>::ReferenceSpaceCreator ref_space_creator(&space, ref_mesh, 0); Space<double>* ref_space = ref_space_creator.create_ref_space(); HPAdapt * adapting = new HPAdapt(ref_space, HERMES_L2_NORM); // increase p in smooth regions, h refine in non-smooth regions Hermes::Mixins::Loggable::Static::info("Calling adapt_smooth()..."); if(adapting->adapt_smooth(smooth_elem_ref, P_MAX)==false) throw Exceptions::Exception("reference space couldn't be constructed"); delete adapting; delete [] coeff_vec_smooth; ref_ndof = ref_space->get_num_dofs(); Hermes::Mixins::Loggable::Static::info("Visualization..."); if(HERMES_VISUALIZATION) { sprintf(title, "Ref_Mesh: Time %3.2f,timestep %i,as=%i,", current_time,ts,as); ref_mview.set_title(title); ref_mview.show(ref_space); } dp_mass.set_space(ref_space); dp_convection.set_space(ref_space); fluxCorrection.init(ref_space); double* coeff_vec = new double[ref_ndof]; double* coeff_vec_2 = new double[ref_ndof]; double* limited_flux = new double[ref_ndof]; dp_mass.assemble(mass_matrix); //M_c/tau dp_convection.assemble(conv_matrix, NULL,true); //K //----------------------MassLumping & Artificial Diffusion -------------------------------------------------------------------- UMFPackMatrix<double>* lumped_matrix = fluxCorrection.massLumping(mass_matrix); // M_L/tau UMFPackMatrix<double>* diffusion = fluxCorrection.artificialDiffusion(conv_matrix); //-----------------Assembling of matrices --------------------------------------------------------------------- lowOrder.assemble_Low_Order(conv_matrix,diffusion,lumped_matrix); highOrd.assemble_High_Order(conv_matrix,mass_matrix); mass_matrix->multiply_with_Scalar(time_step); // massmatrix = M_C lumped_matrix->multiply_with_Scalar(time_step); // M_L //--------- Project the previous timestep solution on the FE space (FCT is applied )---------------- // coeff_vec : FCT -Projection, coeff_vec_2: L2 Projection (ogProjection) if(ts==1) fluxCorrection.project_FCT(&initial_condition, coeff_vec, coeff_vec_2,mass_matrix,lumped_matrix,time_step,&ogProjection,&lumpedProjection, ®Est); else fluxCorrection.project_FCT(&u_prev_time, coeff_vec, coeff_vec_2,mass_matrix,lumped_matrix,time_step,&ogProjection,&lumpedProjection, ®Est); //------------------------- lower order solution------------ u_L = lowOrder.solve_Low_Order(lumped_matrix, coeff_vec,time_step); //-------------high order solution (standard galerkin) ------ u_H = highOrd.solve_High_Order(coeff_vec); //------------------------------Assemble antidiffusive fluxes and limit these----------------------------------- fluxCorrection.antidiffusiveFlux(mass_matrix,lumped_matrix,conv_matrix,diffusion,u_H, u_L,coeff_vec, limited_flux,time_step,®Est); //-------------Compute final solution --------------- ref_sln_double = lowOrder.explicit_Correction(limited_flux); Solution<double> ::vector_to_solution(ref_sln_double, ref_space, &ref_sln); // Project the fine mesh solution onto the coarse mesh. ogProjection.project_global(&space, &ref_sln, &sln, HERMES_L2_NORM); // Calculate element errors and total error estimate. err_est_rel_total = adaptivity.calc_err_est(&sln, &ref_sln) * 100; // Report results. Hermes::Mixins::Loggable::Static::info("ndof_coarse: %d, ndof_fine: %d, err_est_rel: %g%%", ndof,ref_ndof, err_est_rel_total); // If err_est_rel too large, adapt the mesh. if((err_est_rel_total < ERR_STOP)||(as>=ADAPSTEP_MAX)) done = true; else { done = adaptivity.adapt(&selector, THRESHOLD, STRATEGY, MESH_REGULARITY); // Increase the counter of performed adaptivity steps. if(done == false) as++; } if(space.get_num_dofs() >= NDOF_STOP) done = true; if(done) { u_prev_time.copy(&ref_sln); u_prev_time.set_own_mesh(ref_mesh); //ref_mesh can be deleted } // Visualize the solution and mesh. if(HERMES_VISUALIZATION) { sprintf(title, "Ref-Loesung: Time %3.2f,timestep %i,as=%i,", current_time,ts,as); sview.set_title(title); sview.show(&ref_sln); sprintf(title, "Mesh: Time %3.2f,timestep %i,as=%i,", current_time,ts,as); mview.set_title(title); mview.show(&space); } if((VTK_VISUALIZATION) &&((done==true)&&(ts % VTK_FREQ == 0))) { // Output solution in VTK format. char filename[40]; sprintf(filename, "solution-%i.vtk", ts ); lin.save_solution_vtk(&u_prev_time, filename, "solution", mode_3D); sprintf(filename, "ref_space_order-%i.vtk", ts); ord.save_orders_vtk(ref_space, filename); sprintf(filename, "ref_mesh-%i.vtk", ts ); ord.save_mesh_vtk(ref_space, filename); } // Clean up. delete lumped_matrix; delete diffusion; delete [] coeff_vec_2; delete [] coeff_vec; delete [] limited_flux; delete ref_mesh; delete ref_space; } while (done == false); // Update global time. current_time += time_step; // Increase time step counter ts++; } while (current_time < T_FINAL); // Visualize the solution. if(VTK_VISUALIZATION) { lin.save_solution_vtk(&u_prev_time, "end_solution.vtk", "solution", mode_3D); ord.save_mesh_vtk(&space, "end_mesh"); ord.save_orders_vtk(&space, "end_order.vtk"); } delete mass_matrix; delete conv_matrix; // Wait for the view to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; MeshReaderH2D mloader; mloader.load("channel.mesh", &mesh); // Perform initial mesh refinements. for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(0, true); // Initialize boundary condition types and spaces with default shapesets. L2Space<double> space_rho(&mesh, P_INIT); L2Space<double> space_rho_v_x(&mesh, P_INIT); L2Space<double> space_rho_v_y(&mesh, P_INIT); L2Space<double> space_e(&mesh, P_INIT); // Initialize solutions, set initial conditions. ConstantSolution<double> sln_rho(&mesh, RHO_INIT); ConstantSolution<double> sln_rho_v_x(&mesh, RHO_INIT * V1_INIT); ConstantSolution<double> sln_rho_v_y(&mesh, RHO_INIT * V2_INIT); ConstantSolution<double> sln_e(&mesh, QuantityCalculator::calc_energy(RHO_INIT, RHO_INIT * V1_INIT, RHO_INIT * V2_INIT, PRESSURE_INIT, KAPPA)); ConstantSolution<double> prev_rho(&mesh, RHO_INIT); ConstantSolution<double> prev_rho_v_x(&mesh, RHO_INIT * V1_INIT); ConstantSolution<double> prev_rho_v_y(&mesh, RHO_INIT * V2_INIT); ConstantSolution<double> prev_e(&mesh, QuantityCalculator::calc_energy(RHO_INIT, RHO_INIT * V1_INIT, RHO_INIT * V2_INIT, PRESSURE_INIT, KAPPA)); Solution<double> rsln_rho, rsln_rho_v_x, rsln_rho_v_y, rsln_e; // Numerical flux. OsherSolomonNumericalFlux num_flux(KAPPA); // For saving to the disk. Continuity<double> continuity(Continuity<double>::onlyNumber); // Initialize weak formulation. EulerEquationsWeakFormSemiImplicitMultiComponentTwoInflows wf(&num_flux, KAPPA, RHO_LEFT, V1_LEFT, V2_LEFT, PRESSURE_LEFT, RHO_TOP, V1_TOP, V2_TOP, PRESSURE_TOP, BDY_SOLID_WALL, BDY_INLET_LEFT, BDY_INLET_TOP, BDY_OUTLET, &prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e); // Filters for visualization of Mach number, pressure and entropy. MachNumberFilter Mach_number(Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); PressureFilter pressure(Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA); EntropyFilter entropy(Hermes::vector<MeshFunction<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), KAPPA, RHO_INIT, P_INIT); ScalarView pressure_view("Pressure", new WinGeom(0, 0, 600, 300)); ScalarView Mach_number_view("Mach number", new WinGeom(700, 0, 600, 300)); ScalarView entropy_production_view("Entropy estimate", new WinGeom(0, 400, 600, 300)); // Initialize refinement selector. L2ProjBasedSelector<double> selector(CAND_LIST, CONV_EXP, MAX_P_ORDER); selector.set_error_weights(1.0, 1.0, 1.0); // Set up CFL calculation class. CFLCalculation CFL(CFL_NUMBER, KAPPA); // Time stepping loop. int iteration = 0; double t = 0; for(; t < 4.0; t += time_step) { info("---- Time step %d, time %3.5f.", iteration++, t); // Periodic global derefinements. if (iteration > 1 && iteration % UNREF_FREQ == 0 && REFINEMENT_COUNT > 0) { info("Global mesh derefinement."); REFINEMENT_COUNT = 0; space_rho.unrefine_all_mesh_elements(true); space_rho.adjust_element_order(-1, P_INIT); space_rho_v_x.copy_orders(&space_rho); space_rho_v_y.copy_orders(&space_rho); space_e.copy_orders(&space_rho); } // Adaptivity loop: int as = 1; int ndofs_prev = 0; bool done = false; do { info("---- Adaptivity step %d:", as); // Construct globally refined reference mesh and setup reference space. int order_increase = 1; Hermes::vector<Space<double> *>* ref_spaces = Space<double>::construct_refined_spaces(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), order_increase); if(ndofs_prev != 0) if(Space<double>::get_num_dofs(*ref_spaces) == ndofs_prev) selector.set_error_weights(2.0 * selector.get_error_weight_h(), 1.0, 1.0); else selector.set_error_weights(1.0, 1.0, 1.0); ndofs_prev = Space<double>::get_num_dofs(*ref_spaces); // Project the previous time level solution onto the new fine mesh. info("Projecting the previous time level solution onto the new fine mesh."); OGProjection<double>::project_global(*ref_spaces, Hermes::vector<Solution<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), Hermes::vector<Solution<double>*>(&prev_rho, &prev_rho_v_x, &prev_rho_v_y, &prev_e), matrix_solver_type, Hermes::vector<Hermes::Hermes2D::ProjNormType>(), iteration > 1); // Report NDOFs. info("ndof_coarse: %d, ndof_fine: %d.", Space<double>::get_num_dofs(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)), Space<double>::get_num_dofs(*ref_spaces)); // Assemble the reference problem. info("Solving on reference mesh."); DiscreteProblem<double> dp(&wf, *ref_spaces); SparseMatrix<double>* matrix = create_matrix<double>(matrix_solver_type); Vector<double>* rhs = create_vector<double>(matrix_solver_type); LinearSolver<double>* solver = create_linear_solver<double>(matrix_solver_type, matrix, rhs); wf.set_time_step(time_step); dp.assemble(matrix, rhs); // Solve the matrix problem. info("Solving the matrix problem."); if(solver->solve()) if(!SHOCK_CAPTURING) Solution<double>::vector_to_solutions(solver->get_sln_vector(), *ref_spaces, Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)); else { FluxLimiter flux_limiter(FluxLimiter::Kuzmin, solver->get_sln_vector(), *ref_spaces, true); flux_limiter.limit_second_orders_according_to_detector(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); flux_limiter.limit_according_to_detector(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)); flux_limiter.get_limited_solutions(Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)); } else error ("Matrix solver failed.\n"); // Project the fine mesh solution onto the coarse mesh. info("Projecting reference solution on coarse mesh."); OGProjection<double>::project_global(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e), Hermes::vector<Solution<double>*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), matrix_solver_type, Hermes::vector<ProjNormType>(HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM)); // Calculate element errors and total error estimate. info("Calculating error estimate."); Adapt<double>* adaptivity = new Adapt<double>(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e), Hermes::vector<ProjNormType>(HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM, HERMES_L2_NORM)); double err_est_rel_total = adaptivity->calc_err_est(Hermes::vector<Solution<double>*>(&sln_rho, &sln_rho_v_x, &sln_rho_v_y, &sln_e), Hermes::vector<Solution<double>*>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e)) * 100; CFL.calculate_semi_implicit(Hermes::vector<Solution<double> *>(&rsln_rho, &rsln_rho_v_x, &rsln_rho_v_y, &rsln_e), (*ref_spaces)[0]->get_mesh(), time_step); // Report results. info("err_est_rel: %g%%", err_est_rel_total); // If err_est too large, adapt the mesh. if (err_est_rel_total < ERR_STOP) done = true; else { info("Adapting coarse mesh."); done = adaptivity->adapt(Hermes::vector<RefinementSelectors::Selector<double> *>(&selector, &selector, &selector, &selector), THRESHOLD, STRATEGY, MESH_REGULARITY); REFINEMENT_COUNT++; if (Space<double>::get_num_dofs(Hermes::vector<Space<double> *>(&space_rho, &space_rho_v_x, &space_rho_v_y, &space_e)) >= NDOF_STOP) done = true; else as++; } // Clean up. delete solver; delete matrix; delete rhs; delete adaptivity; if(!done) for(unsigned int i = 0; i < ref_spaces->size(); i++) delete (*ref_spaces)[i]; } while (done == false); // Copy the solutions into the previous time level ones. prev_rho.copy(&rsln_rho); prev_rho_v_x.copy(&rsln_rho_v_x); prev_rho_v_y.copy(&rsln_rho_v_y); prev_e.copy(&rsln_e); delete rsln_rho.get_mesh(); rsln_rho.own_mesh = false; delete rsln_rho_v_x.get_mesh(); rsln_rho_v_x.own_mesh = false; delete rsln_rho_v_y.get_mesh(); rsln_rho_v_y.own_mesh = false; delete rsln_e.get_mesh(); rsln_e.own_mesh = false; // Visualization and saving on disk. if((iteration - 1) % EVERY_NTH_STEP == 0) { continuity.add_record((unsigned int)(iteration - 1)); continuity.get_last_record()->save_mesh(prev_rho.get_mesh()); continuity.get_last_record()->save_space(prev_rho.get_space()); continuity.get_last_record()->save_time_step_length(time_step); // Hermes visualization. if(HERMES_VISUALIZATION) { Mach_number.reinit(); pressure.reinit(); entropy.reinit(); pressure_view.show(&pressure, 1); entropy_production_view.show(&entropy, 1); Mach_number_view.show(&Mach_number, 1); pressure_view.save_numbered_screenshot("pressure %i.bmp", iteration); Mach_number_view.save_numbered_screenshot("Mach no %i.bmp", iteration); } // Output solution in VTK format. if(VTK_VISUALIZATION) { pressure.reinit(); Mach_number.reinit(); entropy.reinit(); Linearizer lin; char filename[40]; sprintf(filename, "Pressure-%i.vtk", iteration - 1); lin.save_solution_vtk(&pressure, filename, "Pressure", false); sprintf(filename, "Mach number-%i.vtk", iteration - 1); lin.save_solution_vtk(&Mach_number, filename, "MachNumber", false); if((iteration - 1) % (EVERY_NTH_STEP * EVERY_NTH_STEP) == 0) { sprintf(filename, "Entropy-%i.vtk", iteration - 1); lin.save_solution_vtk(&entropy, filename, "Entropy", false); } } } } pressure_view.close(); entropy_production_view.close(); Mach_number_view.close(); return 0; }
int main(int argc, char* argv[]) { // Instantiate a class with global functions. Hermes2D hermes2d; // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("motor.mesh", &mesh); // Initialize the weak formulation. CustomWeakFormPoisson wf("Motor", EPS_MOTOR, "Air", EPS_AIR); // Initialize boundary conditions DefaultEssentialBCConst bc_essential_out("Outer", 0.0); DefaultEssentialBCConst bc_essential_stator("Stator", VOLTAGE); EssentialBCs bcs(Hermes::vector<EssentialBoundaryCondition *>(&bc_essential_out, &bc_essential_stator)); // Create an H1 space with default shapeset. H1Space space(&mesh, &bcs, P_INIT); // Initialize coarse and reference mesh solution. Solution sln, ref_sln; // Initialize refinement selector. H1ProjBasedSelector selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER); // Initialize views. ScalarView sview("Solution", new WinGeom(0, 0, 410, 600)); sview.fix_scale_width(50); sview.show_mesh(false); OrderView oview("Polynomial orders", new WinGeom(420, 0, 400, 600)); // DOF and CPU convergence graphs initialization. SimpleGraph graph_dof, graph_cpu; // Time measurement. TimePeriod cpu_time; cpu_time.tick(); // Adaptivity loop: int as = 1; bool done = false; do { info("---- Adaptivity step %d:", as); // Construct globally refined reference mesh and setup reference space. Space* ref_space = Space::construct_refined_space(&space); int ndof_ref = Space::get_num_dofs(ref_space); // Initialize matrix solver. SparseMatrix* matrix = create_matrix(matrix_solver); Vector* rhs = create_vector(matrix_solver); Solver* solver = create_linear_solver(matrix_solver, matrix, rhs); // Initialize reference problem. info("Solving on reference mesh."); DiscreteProblem* dp = new DiscreteProblem(&wf, ref_space); // Time measurement. cpu_time.tick(); // Initial coefficient vector for the Newton's method. scalar* coeff_vec = new scalar[ndof_ref]; memset(coeff_vec, 0, ndof_ref * sizeof(scalar)); // Perform Newton's iteration. if (!hermes2d.solve_newton(coeff_vec, dp, solver, matrix, rhs)) error("Newton's iteration failed."); // Translate the resulting coefficient vector into the Solution sln. Solution::vector_to_solution(coeff_vec, ref_space, &ref_sln); // Project the fine mesh solution onto the coarse mesh. info("Projecting reference solution on coarse mesh."); OGProjection::project_global(&space, &ref_sln, &sln, matrix_solver); // Time measurement. cpu_time.tick(); // VTK output. if (VTK_VISUALIZATION) { // Output solution in VTK format. Linearizer lin; char* title = new char[100]; sprintf(title, "sln-%d.vtk", as); lin.save_solution_vtk(&sln, title, "Potential", false); info("Solution in VTK format saved to file %s.", title); // Output mesh and element orders in VTK format. Orderizer ord; sprintf(title, "ord-%d.vtk", as); ord.save_orders_vtk(&space, title); info("Element orders in VTK format saved to file %s.", title); } // View the coarse mesh solution and polynomial orders. if (HERMES_VISUALIZATION) { sview.show(&sln); oview.show(&space); } // Skip visualization time. cpu_time.tick(HERMES_SKIP); // Calculate element errors and total error estimate. info("Calculating error estimate."); Adapt* adaptivity = new Adapt(&space); bool solutions_for_adapt = true; // In the following function, the Boolean parameter "solutions_for_adapt" determines whether // the calculated errors are intended for use with adaptivity (this may not be the case, for example, // when error wrt. an exact solution is calculated). The default value is solutions_for_adapt = true, // The last parameter "error_flags" determine whether the total and element errors are treated as // absolute or relative. Its default value is error_flags = HERMES_TOTAL_ERROR_REL | HERMES_ELEMENT_ERROR_REL. // In subsequent examples and benchmarks, these two parameters will be often used with // their default values, and thus they will not be present in the code explicitly. double err_est_rel = adaptivity->calc_err_est(&sln, &ref_sln, solutions_for_adapt, HERMES_TOTAL_ERROR_REL | HERMES_ELEMENT_ERROR_REL) * 100; // Report results. info("ndof_coarse: %d, ndof_fine: %d, err_est_rel: %g%%", Space::get_num_dofs(&space), Space::get_num_dofs(ref_space), err_est_rel); // Time measurement. cpu_time.tick(); // Add entry to DOF and CPU convergence graphs. graph_dof.add_values(Space::get_num_dofs(&space), err_est_rel); graph_dof.save("conv_dof_est.dat"); graph_cpu.add_values(cpu_time.accumulated(), err_est_rel); graph_cpu.save("conv_cpu_est.dat"); // If err_est too large, adapt the mesh. if (err_est_rel < ERR_STOP) done = true; else { info("Adapting coarse mesh."); done = adaptivity->adapt(&selector, THRESHOLD, STRATEGY, MESH_REGULARITY); // Increase the counter of performed adaptivity steps. if (done == false) as++; } if (Space::get_num_dofs(&space) >= NDOF_STOP) done = true; // Clean up. delete [] coeff_vec; delete solver; delete matrix; delete rhs; delete adaptivity; if(done == false) delete ref_space->get_mesh(); delete ref_space; delete dp; } while (done == false); verbose("Total running time: %g s", cpu_time.accumulated()); // Show the reference solution - the final result. sview.set_title("Fine mesh solution"); sview.show_mesh(false); sview.show(&ref_sln); // Wait for all views to be closed. View::wait(); return 0; }