int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; MeshReaderH2D mloader; mloader.load("motor.mesh", &mesh); // Initialize the weak formulation. CustomWeakFormPoisson wf("Motor", EPS_MOTOR, "Air", EPS_AIR, &mesh); // Initialize boundary conditions DefaultEssentialBCConst<double> bc_essential_out("Outer", 0.0); DefaultEssentialBCConst<double> bc_essential_stator("Stator", VOLTAGE); EssentialBCs<double> bcs(Hermes::vector<EssentialBoundaryCondition<double> *>(&bc_essential_out, &bc_essential_stator)); // Create an H1 space with default shapeset. H1Space<double> space(&mesh, &bcs, P_INIT); // Initialize coarse and reference mesh solution. Solution<double> sln; // Initialize views. Views::ScalarView sview("Solution", new Views::WinGeom(0, 0, 410, 600)); sview.fix_scale_width(50); sview.show_mesh(false); Views::OrderView oview("Polynomial orders", new Views::WinGeom(420, 0, 400, 600)); // DOF and CPU convergence graphs initialization. SimpleGraph graph_dof, graph_cpu; // Time measurement. Hermes::Mixins::TimeMeasurable cpu_time; // Adaptivity loop: int as = 1; bool done = false; do { Hermes::Mixins::Loggable::Static::info("---- Adaptivity step %d:", as); // Time measurement. cpu_time.tick(); // Initialize reference problem. Hermes::Mixins::Loggable::Static::info("Solving."); DiscreteProblem<double> dp(&wf, &space); NewtonSolver<double> newton(&dp); newton.set_verbose_output(false); // Initial ndof. int ndof = space.get_num_dofs(); // Perform Newton's iteration. try { newton.solve(); } catch(std::exception& e) { std::cout << e.what(); } // Translate the resulting coefficient vector into the instance of Solution. Solution<double>::vector_to_solution(newton.get_sln_vector(), &space, &sln); // Time measurement. cpu_time.tick(); // VTK output. if (VTK_VISUALIZATION) { // Output solution in VTK format. Views::Linearizer lin; char* title = new char[100]; sprintf(title, "sln-%d.vtk", as); lin.save_solution_vtk(&sln, title, "Potential", false); Hermes::Mixins::Loggable::Static::info("Solution in VTK format saved to file %s.", title); // Output mesh and element orders in VTK format. Views::Orderizer ord; sprintf(title, "ord-%d.vtk", as); ord.save_orders_vtk(&space, title); Hermes::Mixins::Loggable::Static::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(); // Calculate element errors and total error estimate. Hermes::Mixins::Loggable::Static::info("Calculating error estimate."); bool ignore_visited_segments = true; KellyTypeAdapt<double> adaptivity(&space, ignore_visited_segments, USE_EPS_IN_INTERFACE_ESTIMATOR ? new CustomInterfaceEstimatorScalingFunction("Motor", EPS_MOTOR, "Air", EPS_AIR) : new CustomInterfaceEstimatorScalingFunction); adaptivity.add_error_estimator_surf(new Hermes::Hermes2D::BasicKellyAdapt<double>::ErrorEstimatorFormKelly()); if (USE_RESIDUAL_ESTIMATOR) { adaptivity.add_error_estimator_vol(new ResidualErrorFormMotor("Motor", EPS_MOTOR)); adaptivity.add_error_estimator_vol(new ResidualErrorFormAir("Air", EPS_AIR)); } if (USE_EPS_IN_INTERFACE_ESTIMATOR) // Use normalization by energy norm. adaptivity.set_error_form(new EnergyErrorForm(&wf)); // Note that there is only one solution (the only one available) passed to BasicKellyAdapt::calc_err_est // and there is also no "solutions_for_adapt" parameter. The last parameter, "error_flags", is left // intact and has the meaning explained in P04-adaptivity/01-intro. You may however still call // adaptivity.calc_err_est with a solution, an exact solution and solutions_for_adapt=false to calculate // error wrt. an exact solution (if provided). double err_est_rel = adaptivity.calc_err_est(&sln, HERMES_TOTAL_ERROR_REL | HERMES_ELEMENT_ERROR_REL) * 100; // Report results. Hermes::Mixins::Loggable::Static::info("ndof: %d, err_est_rel: %g%%", space.get_num_dofs(), err_est_rel); // Add entry to DOF and CPU convergence graphs. cpu_time.tick(); graph_cpu.add_values(cpu_time.accumulated(), err_est_rel); graph_cpu.save("conv_cpu_est.dat"); graph_dof.add_values(space.get_num_dofs(), err_est_rel); graph_dof.save("conv_dof_est.dat"); // Skip the time spent to save the convergence graphs. cpu_time.tick(); // 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."); // h-refinement is automatically selected here, no need for parameter "selector". done = adaptivity.adapt(THRESHOLD, STRATEGY, MESH_REGULARITY); // Increase the counter of performed adaptivity steps. if (done == false) as++; } if (space.get_num_dofs() >= NDOF_STOP) done = true; } while (done == false); Hermes::Mixins::Loggable::Static::info("Total running time: %g s", cpu_time.accumulated()); // The final result has already been shown in the final step of the adaptivity loop, so we only // adjust the title and hide the mesh here. sview.set_title("Fine mesh solution"); sview.show_mesh(false); // Wait for all views to be closed. Views::View::wait(); return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; MeshReaderH2D mloader; mloader.load("domain.mesh", &mesh); // Initialize the weak formulation. CustomWeakFormPoisson wf("Motor", EPS_MOTOR, "Air", EPS_AIR); // Initialize boundary conditions DefaultEssentialBCConst<double> bc_essential_out("Outer", 0.0); DefaultEssentialBCConst<double> bc_essential_stator("Stator", VOLTAGE); EssentialBCs<double> bcs(Hermes::vector<EssentialBoundaryCondition<double> *>(&bc_essential_out, &bc_essential_stator)); // Create an H1 space with default shapeset. H1Space<double> space(&mesh, &bcs, P_INIT); // Initialize coarse and fine mesh solution. Solution<double> sln, ref_sln; // Initialize refinement selector. H1ProjBasedSelector<double> selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER); // Initialize views. Views::ScalarView sview("Solution", new Views::WinGeom(0, 0, 410, 600)); sview.fix_scale_width(50); sview.show_mesh(false); Views::OrderView oview("Polynomial orders", new Views::WinGeom(420, 0, 400, 600)); // DOF and CPU convergence graphs initialization. SimpleGraph graph_dof, graph_cpu; // Time measurement. Hermes::Mixins::TimeMeasurable cpu_time; DiscreteProblem<double> dp(&wf, &space); NewtonSolver<double> newton(&dp); newton.set_verbose_output(true); // Adaptivity loop: int as = 1; bool done = false; do { Hermes::Mixins::Loggable::Static::info("---- Adaptivity step %d:", as); // Time measurement. cpu_time.tick(); // Construct globally refined mesh and setup fine mesh space. Mesh::ReferenceMeshCreator ref_mesh_creator(&mesh); Mesh* ref_mesh = ref_mesh_creator.create_ref_mesh(); Space<double>::ReferenceSpaceCreator ref_space_creator(&space, ref_mesh); Space<double>* ref_space = ref_space_creator.create_ref_space(); int ndof_ref = ref_space->get_num_dofs(); // Initialize fine mesh problem. Hermes::Mixins::Loggable::Static::info("Solving on fine mesh."); newton.set_space(ref_space); // Perform Newton's iteration. try { newton.solve(); } catch(std::exception& e) { std::cout << e.what(); } // Translate the resulting coefficient vector into the instance of Solution. Solution<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 fine mesh solution on coarse mesh."); OGProjection<double> ogProjection; ogProjection.project_global(&space, &ref_sln, &sln); // Time measurement. cpu_time.tick(); // VTK output. if (VTK_VISUALIZATION) { // Output solution in VTK format. Views::Linearizer lin; char* title = new char[100]; sprintf(title, "sln-%d.vtk", as); lin.save_solution_vtk(&sln, title, "Potential", false); Hermes::Mixins::Loggable::Static::info("Solution in VTK format saved to file %s.", title); // Output mesh and element orders in VTK format. Views::Orderizer ord; sprintf(title, "ord-%d.vtk", as); ord.save_orders_vtk(&space, title); Hermes::Mixins::Loggable::Static::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(); // Calculate element errors and total error estimate. Hermes::Mixins::Loggable::Static::info("Calculating error estimate."); Adapt<double> adaptivity(&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. Hermes::Mixins::Loggable::Static::info("ndof_coarse: %d, ndof_fine: %d, err_est_rel: %g%%", space.get_num_dofs(), ref_space->get_num_dofs(), err_est_rel); // Add entry to DOF and CPU convergence graphs. cpu_time.tick(); graph_cpu.add_values(cpu_time.accumulated(), err_est_rel); graph_cpu.save("conv_cpu_est.dat"); graph_dof.add_values(space.get_num_dofs(), err_est_rel); graph_dof.save("conv_dof_est.dat"); // Skip the time spent to save the convergence graphs. cpu_time.tick(); // 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); // Increase the counter of performed adaptivity steps. if (done == false) as++; } if (space.get_num_dofs() >= NDOF_STOP) done = true; // Keep the mesh from final step to allow further work with the final fine mesh solution. if(done == false) delete ref_space->get_mesh(); delete ref_space; } while (done == false); Hermes::Mixins::Loggable::Static::info("Total running time: %g s", cpu_time.accumulated()); // Show the fine mesh solution - final result. sview.set_title("Fine mesh solution"); sview.show_mesh(false); sview.show(&ref_sln); // Wait for all views to be closed. Views::View::wait(); return 0; }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh; MeshReaderH1DXML mloader; mloader.load("domain.xml", &mesh); // Perform initial mesh refinements (optional). // Split elements vertically. int refinement_type = 2; for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(refinement_type); // Initialize the weak formulation. CustomWeakFormPoisson wf("Al", new Hermes::Hermes1DFunction<double>(LAMBDA_AL), "Cu", new Hermes::Hermes1DFunction<double>(LAMBDA_CU), new Hermes::Hermes2DFunction<double>(-VOLUME_HEAT_SRC)); // Initialize essential boundary conditions. DefaultEssentialBCConst<double> bc_essential(Hermes::vector<std::string>("Left", "Right"), FIXED_BDY_TEMP); 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(); Hermes::Mixins::Loggable::Static::info("ndof = %d", ndof); // Show the mesh and poly degrees. Views::OrderView oview("Mesh", new Views::WinGeom(0, 0, 900, 250)); if (HERMES_VISUALIZATION) oview.show(&space); // Initialize the FE problem. DiscreteProblem<double> dp(&wf, &space); // Perform Newton's iteration and translate the resulting coefficient vector into a Solution. Solution<double> sln; NewtonSolver<double> newton(&dp); try { newton.solve(); } catch(Hermes::Exceptions::Exception e) { e.printMsg(); throw Hermes::Exceptions::Exception("Newton's iteration failed."); }; Solution<double>::vector_to_solution(newton.get_sln_vector(), &space, &sln); // Get info about time spent during assembling in its respective parts. //dp.get_all_profiling_output(std::cout); // VTK output. if (VTK_VISUALIZATION) { // Output solution in VTK format. Views::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. Views::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) { Views::ScalarView view("Solution", new Views::WinGeom(0, 300, 900, 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, Views::HERMES_EPS_HIGH); Views::View::wait(); } return 0; }
int main(int argc, char* argv[]) { // Load the mesh. MeshSharedPtr mesh(new Mesh); MeshReaderH2D mloader; mloader.load("domain.mesh", mesh); // Initialize the weak formulation. CustomWeakFormPoisson wf("Motor", EPS_MOTOR, "Air", EPS_AIR); // Initialize boundary conditions DefaultEssentialBCConst<double> bc_essential_out("Outer", 0.0); DefaultEssentialBCConst<double> bc_essential_stator("Stator", VOLTAGE); EssentialBCs<double> bcs(Hermes::vector<EssentialBoundaryCondition<double> *>(&bc_essential_out, &bc_essential_stator)); // Create an H1 space with default shapeset. SpaceSharedPtr<double> space(new H1Space<double>(mesh, &bcs, P_INIT)); // Set the space to adaptivity. adaptivity.set_space(space); // Initialize coarse and fine mesh solution. MeshFunctionSharedPtr<double> sln(new Solution<double>), ref_sln(new Solution<double>); // Initialize refinement selector. H1ProjBasedSelector<double> selector(CAND_LIST, H2DRS_DEFAULT_ORDER); // Initialize views. Views::ScalarView sview("Solution", new Views::WinGeom(0, 0, 410, 600)); sview.fix_scale_width(50); sview.show_mesh(false); Views::OrderView oview("Polynomial orders", new Views::WinGeom(420, 0, 400, 600)); // DOF and CPU convergence graphs initialization. SimpleGraph graph_dof, graph_cpu; // Time measurement. Hermes::Mixins::TimeMeasurable cpu_time; DiscreteProblem<double> dp(&wf, space); NewtonSolver<double> newton(&dp); newton.set_verbose_output(true); // Adaptivity loop: int as = 1; bool done = false; do { Hermes::Mixins::Loggable::Static::info("---- Adaptivity step %d:", as); // Time measurement. cpu_time.tick(); // Construct globally refined mesh and setup fine mesh space. Mesh::ReferenceMeshCreator ref_mesh_creator(mesh); MeshSharedPtr ref_mesh = ref_mesh_creator.create_ref_mesh(); Space<double>::ReferenceSpaceCreator ref_space_creator(space, ref_mesh); SpaceSharedPtr<double> ref_space = ref_space_creator.create_ref_space(); int ndof_ref = ref_space->get_num_dofs(); // Initialize fine mesh problem. Hermes::Mixins::Loggable::Static::info("Solving on fine mesh."); newton.set_space(ref_space); // Perform Newton's iteration. try { newton.solve(); } catch(std::exception& e) { std::cout << e.what(); } // Translate the resulting coefficient vector into the instance of Solution. Solution<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 fine mesh solution on coarse mesh."); OGProjection<double>::project_global(space, ref_sln, sln); // Time measurement. cpu_time.tick(); // VTK output. if (VTK_VISUALIZATION) { // Output solution in VTK format. Views::Linearizer lin; char* title = new char[100]; sprintf(title, "sln-%d.vtk", as); lin.save_solution_vtk(ref_sln, title, "Potential", false); Hermes::Mixins::Loggable::Static::info("Solution in VTK format saved to file %s.", title); // Output mesh and element orders in VTK format. Views::Orderizer ord; sprintf(title, "ord-%d.vtk", as); ord.save_orders_vtk(space, title); Hermes::Mixins::Loggable::Static::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(); // Calculate element errors and total error estimate. Hermes::Mixins::Loggable::Static::info("Calculating error estimate."); errorCalculator.calculate_errors(sln, ref_sln); double err_est_rel = errorCalculator.get_total_error_squared() * 100; // Report results. Hermes::Mixins::Loggable::Static::info("ndof_coarse: %d, ndof_fine: %d, err_est_rel: %g%%", space->get_num_dofs(), ref_space->get_num_dofs(), err_est_rel); // Add entry to DOF and CPU convergence graphs. cpu_time.tick(); graph_cpu.add_values(cpu_time.accumulated(), err_est_rel); graph_cpu.save("conv_cpu_est.dat"); graph_dof.add_values(space->get_num_dofs(), err_est_rel); graph_dof.save("conv_dof_est.dat"); // Skip the time spent to save the convergence graphs. cpu_time.tick(); // 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); // Increase the counter of performed adaptivity steps. if (done == false) as++; } } while (done == false); Hermes::Mixins::Loggable::Static::info("Total running time: %g s", cpu_time.accumulated()); // Show the fine mesh solution - final result. sview.set_title("Fine mesh solution"); sview.show_mesh(false); sview.show(ref_sln); // Wait for all views to be closed. Views::View::wait(); return 0; }