int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh_whole_domain, mesh_with_hole; Hermes::vector<Mesh*> meshes (&mesh_whole_domain, &mesh_with_hole); MeshReaderH2DXML mloader; mloader.load("domain.xml", meshes); // Temperature mesh: Initial uniform mesh refinements in graphite. meshes[0]->refine_by_criterion(element_in_graphite, INIT_REF_NUM_TEMPERATURE_GRAPHITE); // Temperature mesh: Initial uniform mesh refinements in fluid. meshes[0]->refine_by_criterion(element_in_fluid, INIT_REF_NUM_TEMPERATURE_FLUID); // Fluid mesh: Initial uniform mesh refinements. for(int i = 0; i < INIT_REF_NUM_FLUID; i++) meshes[1]->refine_all_elements(); // Initial refinements towards boundary of graphite. for(unsigned int meshes_i = 0; meshes_i < meshes.size(); meshes_i++) meshes[meshes_i]->refine_towards_boundary("Inner Wall", INIT_REF_NUM_BDY_GRAPHITE); // Initial refinements towards the top and bottom edges. for(unsigned int meshes_i = 0; meshes_i < meshes.size(); meshes_i++) meshes[meshes_i]->refine_towards_boundary("Outer Wall", INIT_REF_NUM_BDY_WALL); /* View both meshes. */ MeshView m1("Mesh for temperature"), m2("Mesh for fluid"); m1.show(&mesh_whole_domain); m2.show(&mesh_with_hole); // Initialize boundary conditions. EssentialBCNonConst bc_inlet_vel_x("Inlet", VEL_INLET, H, STARTUP_TIME); DefaultEssentialBCConst<double> bc_other_vel_x(Hermes::vector<std::string>("Outer Wall", "Inner Wall"), 0.0); EssentialBCs<double> bcs_vel_x(Hermes::vector<EssentialBoundaryCondition<double> *>(&bc_inlet_vel_x, &bc_other_vel_x)); DefaultEssentialBCConst<double> bc_vel_y(Hermes::vector<std::string>("Inlet", "Outer Wall", "Inner Wall"), 0.0); EssentialBCs<double> bcs_vel_y(&bc_vel_y); EssentialBCs<double> bcs_pressure; DefaultEssentialBCConst<double> bc_temperature(Hermes::vector<std::string>("Outer Wall", "Inlet"), 20.0); EssentialBCs<double> bcs_temperature(&bc_temperature); // Spaces for velocity components, pressure and temperature. H1Space<double> xvel_space(&mesh_with_hole, &bcs_vel_x, P_INIT_VEL); H1Space<double> yvel_space(&mesh_with_hole, &bcs_vel_y, P_INIT_VEL); #ifdef PRESSURE_IN_L2 L2Space<double> p_space(&mesh_with_hole, P_INIT_PRESSURE); #else H1Space<double> p_space(&mesh_with_hole, &bcs_pressure, P_INIT_PRESSURE); #endif H1Space<double> temperature_space(&mesh_whole_domain, &bcs_temperature, P_INIT_TEMPERATURE); Hermes::vector<Space<double> *> all_spaces(&xvel_space, &yvel_space, &p_space, &temperature_space); Hermes::vector<const Space<double> *> all_spaces_const(&xvel_space, &yvel_space, &p_space, &temperature_space); // Calculate and report the number of degrees of freedom. int ndof = Space<double>::get_num_dofs(Hermes::vector<const Space<double> *>(&xvel_space, &yvel_space, &p_space, &temperature_space)); info("ndof = %d.", ndof); // Define projection norms. ProjNormType vel_proj_norm = HERMES_H1_NORM; #ifdef PRESSURE_IN_L2 ProjNormType p_proj_norm = HERMES_L2_NORM; #else ProjNormType p_proj_norm = HERMES_H1_NORM; #endif ProjNormType temperature_proj_norm = HERMES_H1_NORM; Hermes::vector<ProjNormType> all_proj_norms = Hermes::vector<ProjNormType>(vel_proj_norm, vel_proj_norm, p_proj_norm, temperature_proj_norm); // Initial conditions and such. info("Setting initial conditions."); ZeroSolution xvel_prev_time(&mesh_with_hole), yvel_prev_time(&mesh_with_hole), p_prev_time(&mesh_with_hole); CustomInitialConditionTemperature temperature_init_cond(&mesh_whole_domain, HOLE_MID_X, HOLE_MID_Y, 0.5*OBSTACLE_DIAMETER, TEMPERATURE_INIT_FLUID, TEMPERATURE_INIT_GRAPHITE); Solution<double> temperature_prev_time; Hermes::vector<Solution<double> *> all_solutions = Hermes::vector<Solution<double> *>(&xvel_prev_time, &yvel_prev_time, &p_prev_time, &temperature_prev_time); Hermes::vector<MeshFunction<double> *> all_meshfns = Hermes::vector<MeshFunction<double> *>(&xvel_prev_time, &yvel_prev_time, &p_prev_time, &temperature_init_cond); // Project all initial conditions on their FE spaces to obtain aninitial // coefficient vector for the Newton's method. We use local projection // to avoid oscillations in temperature on the graphite-fluid interface // FIXME - currently the LocalProjection only does the lowest-order part (linear // interpolation) at the moment. Higher-order part needs to be added. double* coeff_vec = new double[ndof]; info("Projecting initial condition to obtain initial vector for the Newton's method."); //OGProjection<double>::project_global(all_spaces, all_meshfns, coeff_vec, matrix_solver, all_proj_norms); LocalProjection<double>::project_local(all_spaces_const, all_meshfns, coeff_vec, matrix_solver, all_proj_norms); // Translate the solution vector back to Solutions. This is needed to replace // the discontinuous initial condition for temperature_prev_time with its projection. Solution<double>::vector_to_solutions(coeff_vec, all_spaces_const, all_solutions); // Calculate Reynolds number. double reynolds_number = VEL_INLET * OBSTACLE_DIAMETER / KINEMATIC_VISCOSITY_FLUID; info("RE = %g", reynolds_number); if (reynolds_number < 1e-8) error("Re == 0 will not work - the equations use 1/Re."); // Initialize weak formulation. CustomWeakFormHeatAndFlow wf(STOKES, reynolds_number, time_step, &xvel_prev_time, &yvel_prev_time, &temperature_prev_time, HEAT_SOURCE_GRAPHITE, SPECIFIC_HEAT_GRAPHITE, SPECIFIC_HEAT_FLUID, RHO_GRAPHITE, RHO_FLUID, THERMAL_CONDUCTIVITY_GRAPHITE, THERMAL_CONDUCTIVITY_FLUID, SIMPLE_TEMPERATURE_ADVECTION); // Initialize the FE problem. DiscreteProblem<double> dp(&wf, all_spaces_const); // Initialize the Newton solver. NewtonSolver<double> newton(&dp, matrix_solver); // Initialize views. Views::VectorView vview("velocity [m/s]", new Views::WinGeom(0, 0, 700, 360)); Views::ScalarView pview("pressure [Pa]", new Views::WinGeom(0, 415, 700, 350)); Views::ScalarView tempview("temperature [C]", new Views::WinGeom(0, 795, 700, 350)); //vview.set_min_max_range(0, 0.5); vview.fix_scale_width(80); //pview.set_min_max_range(-0.9, 1.0); pview.fix_scale_width(80); pview.show_mesh(false); tempview.fix_scale_width(80); tempview.show_mesh(false); // Time-stepping loop: char title[100]; int num_time_steps = T_FINAL / time_step; double current_time = 0.0; for (int ts = 1; ts <= num_time_steps; ts++) { current_time += time_step; info("---- Time step %d, time = %g:", ts, current_time); // Update time-dependent essential BCs. if (current_time <= STARTUP_TIME) { info("Updating time-dependent essential BC."); Space<double>::update_essential_bc_values(Hermes::vector<Space<double> *>(&xvel_space, &yvel_space, &p_space, &temperature_space), current_time); } // Perform Newton's iteration. info("Solving nonlinear problem:"); bool verbose = true; // Perform Newton's iteration and translate the resulting coefficient vector into previous time level solutions. newton.set_verbose_output(verbose); try { newton.solve(coeff_vec, NEWTON_TOL, NEWTON_MAX_ITER); } catch(Hermes::Exceptions::Exception e) { e.printMsg(); error("Newton's iteration failed."); }; { Hermes::vector<Solution<double> *> tmp(&xvel_prev_time, &yvel_prev_time, &p_prev_time, &temperature_prev_time); Solution<double>::vector_to_solutions(newton.get_sln_vector(), Hermes::vector<const Space<double> *>(&xvel_space, &yvel_space, &p_space, &temperature_space), tmp); } // Show the solution at the end of time step. sprintf(title, "Velocity [m/s], time %g s", current_time); vview.set_title(title); vview.show(&xvel_prev_time, &yvel_prev_time); sprintf(title, "Pressure [Pa], time %g s", current_time); pview.set_title(title); pview.show(&p_prev_time); sprintf(title, "Temperature [C], time %g s", current_time); tempview.set_title(title); tempview.show(&temperature_prev_time, Views::HERMES_EPS_HIGH); } delete [] coeff_vec; // Wait for all views to be closed. Views::View::wait(); return 0; }
bool Adapt<Scalar>::adapt(Hermes::vector<RefinementSelectors::Selector<Scalar> *> refinement_selectors, double thr, int strat, int regularize, double to_be_processed) { error_if(!have_errors, "element errors have to be calculated first, call Adapt<Scalar>::calc_err_est()."); error_if(refinement_selectors == Hermes::vector<RefinementSelectors::Selector<Scalar> *>(), "selector not provided"); if (spaces.size() != refinement_selectors.size()) error("Wrong number of refinement selectors."); Hermes::TimePeriod cpu_time; //get meshes int max_id = -1; Mesh* meshes[H2D_MAX_COMPONENTS]; for (int j = 0; j < this->num; j++) { meshes[j] = this->spaces[j]->get_mesh(); if (rsln[j] != NULL) { rsln[j]->set_quad_2d(&g_quad_2d_std); rsln[j]->enable_transform(false); } if (meshes[j]->get_max_element_id() > max_id) max_id = meshes[j]->get_max_element_id(); } //reset element refinement info int** idx = new int*[max_id]; for(int i = 0; i < max_id; i++) idx[i] = new int[num]; for(int j = 0; j < max_id; j++) for(int l = 0; l < this->num; l++) idx[j][l] = -1; // element not refined double err0_squared = 1000.0; double processed_error_squared = 0.0; std::vector<ElementToRefine> elem_inx_to_proc; //list of indices of elements that are going to be processed elem_inx_to_proc.reserve(num_act_elems); //adaptivity loop double error_squared_threshod = -1; //an error threshold that breaks the adaptivity loop in a case of strategy 1 int num_exam_elem = 0; //a number of examined elements int num_ignored_elem = 0; //a number of ignored elements int num_not_changed = 0; //a number of element that were not changed int num_priority_elem = 0; //a number of elements that were processed using priority queue bool first_regular_element = true; //true if first regular element was not processed yet int inx_regular_element = 0; while (inx_regular_element < num_act_elems || !priority_queue.empty()) { int id, comp, inx_element; //get element identification if (priority_queue.empty()) { id = regular_queue[inx_regular_element].id; comp = regular_queue[inx_regular_element].comp; inx_element = inx_regular_element; inx_regular_element++; } else { id = priority_queue.front().id; comp = priority_queue.front().comp; inx_element = -1; priority_queue.pop(); num_priority_elem++; } num_exam_elem++; //get info linked with the element double err_squared = errors[comp][id]; Mesh* mesh = meshes[comp]; Element* e = mesh->get_element(id); if (!should_ignore_element(inx_element, mesh, e)) { //check if adaptivity loop should end if (inx_element >= 0) { //prepare error threshold for strategy 1 if (first_regular_element) { error_squared_threshod = thr * err_squared; first_regular_element = false; } // first refinement strategy: // refine elements until prescribed amount of error is processed // if more elements have similar error refine all to keep the mesh symmetric if ((strat == 0) && (processed_error_squared > sqrt(thr) * errors_squared_sum) && fabs((err_squared - err0_squared)/err0_squared) > 1e-3) break; // second refinement strategy: // refine all elements whose error is bigger than some portion of maximal error if ((strat == 1) && (err_squared < error_squared_threshod)) break; if ((strat == 2) && (err_squared < thr)) break; if ((strat == 3) && ( (err_squared < error_squared_threshod) || ( processed_error_squared > 1.5 * to_be_processed )) ) break; } // get refinement suggestion ElementToRefine elem_ref(id, comp); int current = this->spaces[comp]->get_element_order(id); // rsln[comp] may be unset if refinement_selectors[comp] == HOnlySelector or POnlySelector bool refined = refinement_selectors[comp]->select_refinement(e, current, rsln[comp], elem_ref); //add to a list of elements that are going to be refined if (can_refine_element(mesh, e, refined, elem_ref) ) { idx[id][comp] = (int)elem_inx_to_proc.size(); elem_inx_to_proc.push_back(elem_ref); err0_squared = err_squared; processed_error_squared += err_squared; } else { debug_log("Element (id:%d, comp:%d) not changed", e->id, comp); num_not_changed++; } } else { num_ignored_elem++; } } verbose("Examined elements: %d", num_exam_elem); verbose(" Elements taken from priority queue: %d", num_priority_elem); verbose(" Ignored elements: %d", num_ignored_elem); verbose(" Not changed elements: %d", num_not_changed); verbose(" Elements to process: %d", elem_inx_to_proc.size()); bool done = false; if (num_exam_elem == 0) done = true; else if (elem_inx_to_proc.empty()) { warn("None of the elements selected for refinement could be refined. Adaptivity step not successful, returning 'true'."); done = true; } //fix refinement if multimesh is used fix_shared_mesh_refinements(meshes, elem_inx_to_proc, idx, refinement_selectors); //apply refinements apply_refinements(elem_inx_to_proc); // in singlemesh case, impose same orders across meshes homogenize_shared_mesh_orders(meshes); // mesh regularization if (regularize >= 0) { if (regularize == 0) { regularize = 1; warn("Total mesh regularization is not supported in adaptivity. 1-irregular mesh is used instead."); } for (int i = 0; i < this->num; i++) { int* parents; parents = meshes[i]->regularize(regularize); this->spaces[i]->distribute_orders(meshes[i], parents); ::free(parents); } } for (int j = 0; j < this->num; j++) if (rsln[j] != NULL) rsln[j]->enable_transform(true); verbose("Refined elements: %d", elem_inx_to_proc.size()); report_time("Refined elements in: %g s", cpu_time.tick().last()); //store for the user to retrieve last_refinements.swap(elem_inx_to_proc); have_errors = false; if (strat == 2 && done == true) have_errors = true; // space without changes // since space changed, assign dofs: Space<Scalar>::assign_dofs(this->spaces); return done; }
void NeighborSearch<Scalar>::clear_initial_sub_idx() { if(neighborhood_type != H2D_DG_GO_DOWN) return; // Obtain the transformations sequence. Hermes::vector<unsigned int> transformations = get_transforms(original_central_el_transform); Hermes::vector<unsigned int> updated_transformations; for(int i = 0; i < transformations.size(); i++) { if(! ((active_edge == 0 && transformations[i] == 4) || (active_edge == 1 && transformations[i] == 7) || (active_edge == 2 && transformations[i] == 5) || (active_edge == 3 && transformations[i] == 6)) ) { if(active_edge == 0 && transformations[i] == 6) updated_transformations.push_back(0); else if(active_edge == 0 && transformations[i] == 7) updated_transformations.push_back(1); else if(active_edge == 1 && transformations[i] == 4) updated_transformations.push_back(1); else if(active_edge == 1 && transformations[i] == 5) updated_transformations.push_back(2); else if(active_edge == 2 && transformations[i] == 6) updated_transformations.push_back(3); else if(active_edge == 2 && transformations[i] == 7) updated_transformations.push_back(2); else if(active_edge == 3 && transformations[i] == 4) updated_transformations.push_back(0); else if(active_edge == 3 && transformations[i] == 5) updated_transformations.push_back(3); else updated_transformations.push_back(transformations[i]); } } // Test for active element. if(updated_transformations.size() == 0) return; for(unsigned int i = 0; i < n_neighbors; i++) { // Find the index where the additional subelement mapping (on top of the initial one from assembling) starts. unsigned int j = 0; // Note that we do not have to test if central_transformations is empty or how long it is, because it has to be // longer than transformations (and that is tested). // Also the function compatible_transformations() does not have to be used, as now the array central_transformations // has been adjusted so that it contains the array transformations. while(central_transformations.get(i)->transf[j] == updated_transformations[j]) if(++j > updated_transformations.size() - 1) break; if(j > central_transformations.get(i)->num_levels) j = central_transformations.get(i)->num_levels; for(unsigned int level = central_transformations.get(i)->num_levels; level < updated_transformations.size(); level++) { if(!neighbor_transformations.present(i)) neighbor_transformations.add(new Transformations, i); Transformations* neighbor_transforms = neighbor_transformations.get(i); // Triangles. if(central_el->get_mode() == HERMES_MODE_TRIANGLE) if((active_edge == 0 && updated_transformations[level] == 0) || (active_edge == 1 && updated_transformations[level] == 1) || (active_edge == 2 && updated_transformations[level] == 2)) neighbor_transforms->transf[neighbor_transforms->num_levels++] = (!neighbor_edge.orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 3); else neighbor_transforms->transf[neighbor_transforms->num_levels++] = (neighbor_edge.orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 3); // Quads. else if((active_edge == 0 && (updated_transformations[level] == 0 || updated_transformations[level] == 6)) || (active_edge == 1 && (updated_transformations[level] == 1 || updated_transformations[level] == 4)) || (active_edge == 2 && (updated_transformations[level] == 2 || updated_transformations[level] == 7)) || (active_edge == 3 && (updated_transformations[level] == 3 || updated_transformations[level] == 5))) neighbor_transforms->transf[neighbor_transforms->num_levels++] = (!neighbor_edge.orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 4); else if((active_edge == 0 && (updated_transformations[level] == 1 || updated_transformations[level] == 7)) || (active_edge == 1 && (updated_transformations[level] == 2 || updated_transformations[level] == 5)) || (active_edge == 2 && (updated_transformations[level] == 3 || updated_transformations[level] == 6)) || (active_edge == 3 && (updated_transformations[level] == 0 || updated_transformations[level] == 4))) neighbor_transforms->transf[neighbor_transforms->num_levels++] = (neighbor_edge.orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 4); } central_transformations.get(i)->strip_initial_transformations(j); } }
bool select_refinement(Element* element, int order, MeshFunction<complex>* rsln, ElementToRefine& refinement) { switch(strategy) { case(noSelectionH): { refinement.split = H2D_REFINEMENT_H; refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][0] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][1] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][2] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][3] = order; ElementToRefine::copy_orders(refinement.refinement_polynomial_order, refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H]); return true; } break; case(noSelectionHP): { int max_allowed_order = this->max_order; if(this->max_order == H2DRS_DEFAULT_ORDER) max_allowed_order = H2DRS_MAX_ORDER; int order_h = H2D_GET_H_ORDER(order), order_v = H2D_GET_V_ORDER(order); int increased_order_h = std::min(max_allowed_order, order_h + 1), increased_order_v = std::min(max_allowed_order, order_v + 1); int increased_order; if(element->is_triangle()) increased_order = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][0] = H2D_MAKE_QUAD_ORDER(increased_order_h, increased_order_h); else increased_order = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][0] = H2D_MAKE_QUAD_ORDER(increased_order_h, increased_order_v); refinement.split = H2D_REFINEMENT_H; refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][0] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][1] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][2] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][3] = increased_order; ElementToRefine::copy_orders(refinement.refinement_polynomial_order, refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H]); return true; } case(hXORpSelectionBasedOnError): { //make an uniform order in a case of a triangle int order_h = H2D_GET_H_ORDER(order), order_v = H2D_GET_V_ORDER(order); int current_min_order, current_max_order; this->get_current_order_range(element, current_min_order, current_max_order); if(current_max_order < std::max(order_h, order_v)) current_max_order = std::max(order_h, order_v); int last_order_h = std::min(current_max_order, order_h + 1), last_order_v = std::min(current_max_order, order_v + 1); int last_order = H2D_MAKE_QUAD_ORDER(last_order_h, last_order_v); //build candidates. Hermes::vector<Cand> candidates; candidates.push_back(Cand(H2D_REFINEMENT_P, last_order)); candidates.push_back(Cand(H2D_REFINEMENT_H, order, order, order, order)); this->evaluate_cands_error(candidates, element, rsln); Cand* best_candidate = (candidates[0].error < candidates[1].error) ? &candidates[0] : &candidates[1]; Cand* best_candidates_specific_type[4]; best_candidates_specific_type[H2D_REFINEMENT_P] = &candidates[0]; best_candidates_specific_type[H2D_REFINEMENT_H] = &candidates[1]; best_candidates_specific_type[2] = NULL; best_candidates_specific_type[3] = NULL; //copy result to output refinement.split = best_candidate->split; ElementToRefine::copy_orders(refinement.refinement_polynomial_order, best_candidate->p); for(int i = 0; i < 4; i++) if(best_candidates_specific_type[i] != NULL) ElementToRefine::copy_orders(refinement.best_refinement_polynomial_order_type[i], best_candidates_specific_type[i]->p); ElementToRefine::copy_errors(refinement.errors, best_candidate->errors); //modify orders in a case of a triangle such that order_v is zero if(element->is_triangle()) for(int i = 0; i < H2D_MAX_ELEMENT_SONS; i++) refinement.refinement_polynomial_order[i] = H2D_MAKE_QUAD_ORDER(H2D_GET_H_ORDER(refinement.refinement_polynomial_order[i]), 0); return true; } default: H1ProjBasedSelector<complex>::select_refinement(element, order, rsln, refinement); return true; break; } }
double KellyTypeAdapt::eval_interface_estimator(KellyTypeAdapt::ErrorEstimatorForm* err_est_form, RefMap *rm, SurfPos* surf_pos, LightArray<NeighborSearch*>& neighbor_searches, int neighbor_index) { NeighborSearch* nbs = neighbor_searches.get(neighbor_index); Hermes::vector<MeshFunction*> slns; for (int i = 0; i < num; i++) slns.push_back(this->sln[i]); // Determine integration order. ExtData<Ord>* fake_ui = dp.init_ext_fns_ord(slns, neighbor_searches); // Order of additional external functions. // ExtData<Ord>* fake_ext = dp.init_ext_fns_ord(err_est_form->ext, nbs); // Order of geometric attributes (eg. for multiplication of a solution with coordinates, normals, etc.). Geom<Ord>* fake_e = new InterfaceGeom<Ord>(init_geom_ord(), nbs->neighb_el->marker, nbs->neighb_el->id, nbs->neighb_el->get_diameter()); double fake_wt = 1.0; Ord o = err_est_form->ord(1, &fake_wt, fake_ui->fn, fake_ui->fn[err_est_form->i], fake_e, NULL); int order = rm->get_inv_ref_order(); order += o.get_order(); limit_order(order); // Clean up. if (fake_ui != NULL) { for (int i = 0; i < num; i++) delete fake_ui->fn[i]; fake_ui->free_ord(); delete fake_ui; } delete fake_e; //delete fake_ext; Quad2D* quad = this->sln[err_est_form->i]->get_quad_2d(); int eo = quad->get_edge_points(surf_pos->surf_num, order); int np = quad->get_num_points(eo); double3* pt = quad->get_points(eo); // Init geometry and jacobian*weights (do not use the NeighborSearch caching mechanism). double3* tan = rm->get_tangent(surf_pos->surf_num, eo); double* jwt = new double[np]; for(int i = 0; i < np; i++) jwt[i] = pt[i][2] * tan[i][2]; Geom<double>* e = new InterfaceGeom<double>(init_geom_surf(rm, surf_pos, eo), nbs->neighb_el->marker, nbs->neighb_el->id, nbs->neighb_el->get_diameter()); // function values ExtData<scalar>* ui = dp.init_ext_fns(slns, neighbor_searches, order); //ExtData<scalar>* ext = dp.init_ext_fns(err_est_form->ext, nbs); scalar res = interface_scaling_const * err_est_form->value(np, jwt, ui->fn, ui->fn[err_est_form->i], e, NULL); if (ui != NULL) { ui->free(); delete ui; } //if (ext != NULL) { ext->free(); delete ext; } e->free(); delete e; delete [] jwt; return std::abs(0.5*res); // Edges are parameterized from 0 to 1 while integration weights // are defined in (-1, 1). Thus multiplying with 0.5 to correct // the weights. }
void NewtonSolver<Scalar>::solve(Scalar* coeff_vec, double newton_tol, int newton_max_iter, bool residual_as_function) { _F_ // Obtain the number of degrees of freedom. int ndof = this->dp->get_num_dofs(); // Delete the old solution vector, if there is any. if(this->sln_vector != NULL) delete [] this->sln_vector; this->sln_vector = new Scalar[ndof]; if(coeff_vec == NULL) memset(this->sln_vector, 0, ndof*sizeof(Scalar)); else for (int i = 0; i < ndof; i++) this->sln_vector[i] = coeff_vec[i]; // The Newton's loop. double residual_norm; int it = 1; bool delete_timer = false; if (this->timer == NULL) { this->timer = new TimePeriod; delete_timer = true; } this->timer->tick(); setup_time += this->timer->last(); while (true) { // Assemble just the residual vector. this->dp->assemble(this->sln_vector, residual); this->timer->tick(); assemble_time += this->timer->last(); // Measure the residual norm. if (residual_as_function) { // Prepare solutions for measuring residual norm. Hermes::vector<Solution<Scalar>*> solutions; Hermes::vector<bool> dir_lift_false; for (unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++) { solutions.push_back(new Solution<Scalar>()); dir_lift_false.push_back(false); } Solution<Scalar>::vector_to_solutions(residual, static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces(), solutions, dir_lift_false); // Calculate the norm. residual_norm = Global<Scalar>::calc_norms(solutions); // Clean up. for (unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++) delete solutions[i]; } else { // Calculate the l2-norm of residual vector, this is the traditional way. residual_norm = Global<Scalar>::get_l2_norm(residual); } // Info for the user. if(it == 1) { if(this->verbose_output) info("---- Newton initial residual norm: %g", residual_norm); } else if(this->verbose_output) info("---- Newton iter %d, residual norm: %g", it - 1, residual_norm); // If maximum allowed residual norm is exceeded, fail. if (residual_norm > max_allowed_residual_norm) { throw Exceptions::ValueException("residual norm", residual_norm, max_allowed_residual_norm); } // If residual norm is within tolerance, return 'true'. // This is the only correct way of ending. if (residual_norm < newton_tol && it > 1) { this->timer->tick(); solve_time += this->timer->last(); if (delete_timer) { delete this->timer; this->timer = NULL; } return; } this->timer->tick(); solve_time += this->timer->last(); // Assemble just the jacobian. this->dp->assemble(this->sln_vector, jacobian); this->timer->tick(); assemble_time += this->timer->last(); // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n + 1} = -F(Y^n). residual->change_sign(); // Solve the linear system. if(!linear_solver->solve()) { if (delete_timer) { delete this->timer; this->timer = NULL; } throw Exceptions::LinearSolverException(); } // Add \deltaY^{n + 1} to Y^n. for (int i = 0; i < ndof; i++) this->sln_vector[i] += this->damping_coeff * linear_solver->get_sln_vector()[i]; // Increase the number of iterations and test if we are still under the limit. if (it++ >= newton_max_iter) { if (delete_timer) { delete this->timer; this->timer = NULL; } throw Exceptions::ValueException("iterations", it, newton_max_iter); } this->timer->tick(); solve_time += this->timer->last(); } }
// Filter for entropy which uses the constants defined above. static void calc_entropy_estimate_func(int n, Hermes::vector<scalar*> scalars, scalar* result) { for (int i = 0; i < n; i++) result[i] = std::log((calc_pressure(scalars.at(0)[i], scalars.at(1)[i], scalars.at(2)[i], scalars.at(3)[i]) / P_EXT) / pow((scalars.at(0)[i] / RHO_EXT), KAPPA)); };
void L2ProjBasedSelector<Scalar>::precalc_ortho_shapes(const double3* gip_points, const int num_gip_points, const Trf* trfs, const int num_noni_trfs, const Hermes::vector<typename OptimumSelector<Scalar>::ShapeInx>& shapes, const int max_shape_inx, typename ProjBasedSelector<Scalar>::TrfShape& svals) { //calculate values precalc_shapes(gip_points, num_gip_points, trfs, num_noni_trfs, shapes, max_shape_inx, svals); //calculate orthonormal basis const int num_shapes = (int)shapes.size(); for(int i = 0; i < num_shapes; i++) { const int inx_shape_i = shapes[i].inx; //orthogonalize for(int j = 0; j < i; j++) { const int inx_shape_j = shapes[j].inx; //calculate product of non-transformed functions double product = 0.0; for(int k = 0; k < num_gip_points; k++) { double sum = 0.0; sum += svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_L2FE_VALUE][k] * svals[H2D_TRF_IDENTITY][inx_shape_j][H2D_L2FE_VALUE][k]; product += gip_points[k][H2D_GIP2D_W] * sum; } //for all transformations int inx_trf = 0; bool done = false; while (!done && inx_trf < H2D_TRF_NUM) { //for all integration points for(int k = 0; k < num_gip_points; k++) { svals[inx_trf][inx_shape_i][H2D_L2FE_VALUE][k] -= product * svals[inx_trf][inx_shape_j][H2D_L2FE_VALUE][k]; } //move to the next transformation if (inx_trf == H2D_TRF_IDENTITY) done = true; else { inx_trf++; if (inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation inx_trf = H2D_TRF_IDENTITY; } } error_if(!done, "All transformation processed but identity transformation not found."); //identity transformation has to be the last transformation } //normalize //calculate norm double norm_squared = 0.0; for(int k = 0; k < num_gip_points; k++) { double sum = 0.0; sum += sqr(svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_L2FE_VALUE][k]); norm_squared += gip_points[k][H2D_GIP2D_W] * sum; } double norm = sqrt(norm_squared); assert_msg(finite(1/norm), "Norm (%g) is almost zero.", norm); //for all transformations: normalize int inx_trf = 0; bool done = false; while (!done && inx_trf < H2D_TRF_NUM) { //for all integration points for(int k = 0; k < num_gip_points; k++) { svals[inx_trf][inx_shape_i][H2D_L2FE_VALUE][k] /= norm; } //move to the next transformation if (inx_trf == H2D_TRF_IDENTITY) done = true; else { inx_trf++; if (inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation inx_trf = H2D_TRF_IDENTITY; } } error_if(!done, "All transformation processed but identity transformation not found."); //identity transformation has to be the last transformation } }
QList<SolutionArray *> SolutionAgros::solveSolutioArray(Hermes::vector<EssentialBCs> bcs) { QTime time; // solution agros array QList<SolutionArray *> solutionArrayList; // load the mesh file mesh = readMeshFromFile(tempProblemFileName() + ".mesh"); refineMesh(mesh, true, true); // create an H1 space Hermes::vector<Space *> space; // create hermes solution array Hermes::vector<Solution *> solution; // create reference solution Hermes::vector<Solution *> solutionReference; // projection norms Hermes::vector<ProjNormType> projNormType; // prepare selector Hermes::vector<RefinementSelectors::Selector *> selector; // error marker bool isError = false; RefinementSelectors::Selector *select = NULL; switch (adaptivityType) { case AdaptivityType_H: select = new RefinementSelectors::HOnlySelector(); break; case AdaptivityType_P: select = new RefinementSelectors::H1ProjBasedSelector(RefinementSelectors::H2D_P_ANISO, Util::config()->convExp, H2DRS_DEFAULT_ORDER); break; case AdaptivityType_HP: select = new RefinementSelectors::H1ProjBasedSelector(RefinementSelectors::H2D_HP_ANISO, Util::config()->convExp, H2DRS_DEFAULT_ORDER); break; } for (int i = 0; i < numberOfSolution; i++) { space.push_back(new H1Space(mesh, &bcs[i], polynomialOrder)); // set order by element for (int j = 0; j < Util::scene()->labels.count(); j++) if (Util::scene()->labels[j]->material != Util::scene()->materials[0]) space.at(i)->set_uniform_order(Util::scene()->labels[j]->polynomialOrder > 0 ? Util::scene()->labels[j]->polynomialOrder : polynomialOrder, QString::number(j).toStdString()); // solution agros array solution.push_back(new Solution()); if (adaptivityType != AdaptivityType_None) { // add norm projNormType.push_back(Util::config()->projNormType); // add refinement selector selector.push_back(select); // reference solution solutionReference.push_back(new Solution()); } } // check for DOFs if (Space::get_num_dofs(space) == 0) { m_progressItemSolve->emitMessage(QObject::tr("DOF is zero"), true); } else { for (int i = 0; i < numberOfSolution; i++) { // transient if (analysisType == AnalysisType_Transient) { // constant initial solution solution.at(i)->set_const(mesh, initialCondition); solutionArrayList.append(solutionArray(solution.at(i))); } // nonlinear if ((linearityType != LinearityType_Linear) && (analysisType != AnalysisType_Transient)) { solution.at(i)->set_const(mesh, 0.0); } } actualTime = 0.0; // update time function Util::scene()->problemInfo()->hermes()->updateTimeFunctions(actualTime); m_wf->set_current_time(actualTime); m_wf->solution = solution; m_wf->delete_all(); m_wf->registerForms(); // emit message if (adaptivityType != AdaptivityType_None) m_progressItemSolve->emitMessage(QObject::tr("Adaptivity type: %1").arg(adaptivityTypeString(adaptivityType)), false); double error = 0.0; // solution int maxAdaptivitySteps = (adaptivityType == AdaptivityType_None) ? 1 : adaptivitySteps; int actualAdaptivitySteps = -1; for (int i = 0; i<maxAdaptivitySteps; i++) { // set up the solver, matrix, and rhs according to the solver selection. SparseMatrix *matrix = create_matrix(matrixSolver); Vector *rhs = create_vector(matrixSolver); Solver *solver = create_linear_solver(matrixSolver, matrix, rhs); if (adaptivityType == AdaptivityType_None) { if (analysisType != AnalysisType_Transient) solve(space, solution, solver, matrix, rhs); } else { // construct globally refined reference mesh and setup reference space. Hermes::vector<Space *> spaceReference = *Space::construct_refined_spaces(space); // assemble reference problem. solve(spaceReference, solutionReference, solver, matrix, rhs); if (!isError) { // project the fine mesh solution onto the coarse mesh. OGProjection::project_global(space, solutionReference, solution, matrixSolver); // Calculate element errors and total error estimate. Adapt adaptivity(space, projNormType); // Calculate error estimate for each solution component and the total error estimate. error = adaptivity.calc_err_est(solution, solutionReference) * 100; // emit signal m_progressItemSolve->emitMessage(QObject::tr("Adaptivity rel. error (step: %2/%3, DOFs: %4/%5): %1%"). arg(error, 0, 'f', 3). arg(i + 1). arg(maxAdaptivitySteps). arg(Space::get_num_dofs(space)). arg(Space::get_num_dofs(spaceReference)), false, 1); // add error to the list m_progressItemSolve->addAdaptivityError(error, Space::get_num_dofs(space)); if (error < adaptivityTolerance || Space::get_num_dofs(space) >= adaptivityMaxDOFs) { break; } if (i != maxAdaptivitySteps-1) adaptivity.adapt(selector, Util::config()->threshold, Util::config()->strategy, Util::config()->meshRegularity); actualAdaptivitySteps = i+1; } if (m_progressItemSolve->isCanceled()) { isError = true; break; } // delete reference space for (int i = 0; i < spaceReference.size(); i++) { delete spaceReference.at(i)->get_mesh(); delete spaceReference.at(i); } spaceReference.clear(); } // clean up. delete solver; delete matrix; delete rhs; } // delete reference solution for (int i = 0; i < solutionReference.size(); i++) delete solutionReference.at(i); solutionReference.clear(); // delete selector if (select) delete select; selector.clear(); // timesteps if (!isError) { SparseMatrix *matrix = NULL; Vector *rhs = NULL; Solver *solver = NULL; // allocate dp for transient solution DiscreteProblem *dpTran = NULL; if (analysisType == AnalysisType_Transient) { // set up the solver, matrix, and rhs according to the solver selection. matrix = create_matrix(matrixSolver); rhs = create_vector(matrixSolver); solver = create_linear_solver(matrixSolver, matrix, rhs); // solver->set_factorization_scheme(HERMES_REUSE_FACTORIZATION_COMPLETELY); dpTran = new DiscreteProblem(m_wf, space, true); } int timesteps = (analysisType == AnalysisType_Transient) ? floor(timeTotal/timeStep) : 1; for (int n = 0; n<timesteps; n++) { // set actual time actualTime = (n+1)*timeStep; // update essential bc values Space::update_essential_bc_values(space, actualTime); // update timedep values Util::scene()->problemInfo()->hermes()->updateTimeFunctions(actualTime); m_wf->set_current_time(actualTime); m_wf->delete_all(); m_wf->registerForms(); // transient if ((timesteps > 1) && (linearityType == LinearityType_Linear)) isError = !solveLinear(dpTran, space, solution, solver, matrix, rhs); if ((timesteps > 1) && (linearityType != LinearityType_Linear)) isError = !solve(space, solution, solver, matrix, rhs); // output for (int i = 0; i < numberOfSolution; i++) { solutionArrayList.append(solutionArray(solution.at(i), space.at(i), error, actualAdaptivitySteps, (n+1)*timeStep)); } if (analysisType == AnalysisType_Transient) m_progressItemSolve->emitMessage(QObject::tr("Transient time step (%1/%2): %3 s"). arg(n+1). arg(timesteps). arg(actualTime, 0, 'e', 2), false, n+2); if (m_progressItemSolve->isCanceled()) { isError = true; break; } } // clean up if (solver) delete solver; if (matrix) delete matrix; if (rhs) delete rhs; if (dpTran) delete dpTran; } } // delete mesh delete mesh; // delete space for (unsigned int i = 0; i < space.size(); i++) { // delete space.at(i)->get_mesh(); delete space.at(i); } space.clear(); // delete last solution for (unsigned int i = 0; i < solution.size(); i++) delete solution.at(i); solution.clear(); if (isError) { for (int i = 0; i < solutionArrayList.count(); i++) delete solutionArrayList.at(i); solutionArrayList.clear(); } return solutionArrayList; }
bool rk_time_step(double current_time, double time_step, ButcherTable* const bt, Solution* sln_time_prev, Solution* sln_time_new, Solution* error_fn, DiscreteProblem* dp, MatrixSolverType matrix_solver, bool verbose, bool is_linear, double newton_tol, int newton_max_iter, double newton_damping_coeff, double newton_max_allowed_residual_norm) { // Check for not implemented features. if (matrix_solver != SOLVER_UMFPACK) error("Sorry, rk_time_step() still only works with UMFpack."); if (dp->get_weak_formulation()->get_neq() > 1) error("Sorry, rk_time_step() does not work with systems yet."); // Get number of stages from the Butcher's table. int num_stages = bt->get_size(); // Check whether the user provided a nonzero B2-row if he wants temporal error estimation. if(error_fn != NULL) if (bt->is_embedded() == false) { error("rk_time_step(): R-K method must be embedded if temporal error estimate is requested."); } // Matrix for the time derivative part of the equation (left-hand side). UMFPackMatrix* matrix_left = new UMFPackMatrix(); // Matrix and vector for the rest (right-hand side). UMFPackMatrix* matrix_right = new UMFPackMatrix(); UMFPackVector* vector_right = new UMFPackVector(); // Create matrix solver. Solver* solver = create_linear_solver(matrix_solver, matrix_right, vector_right); // Get space, mesh, and ndof for the stage solutions in the R-K method (K_i vectors). Space* K_space = dp->get_space(0); Mesh* K_mesh = K_space->get_mesh(); int ndof = K_space->get_num_dofs(); // Create spaces for stage solutions K_i. This is necessary // to define a num_stages x num_stages block weak formulation. Hermes::vector<Space*> stage_spaces; stage_spaces.push_back(K_space); for (int i = 1; i < num_stages; i++) { stage_spaces.push_back(K_space->dup(K_mesh)); } Space::assign_dofs(stage_spaces); // Create a multistage weak formulation. WeakForm stage_wf_left; // For the matrix M (size ndof times ndof). WeakForm stage_wf_right(num_stages); // For the rest of equation (written on the right), // size num_stages*ndof times num_stages*ndof. Solution** stage_time_sol = new Solution*[num_stages]; // This array will be filled by artificially created // solutions to represent stage times. create_stage_wf(current_time, time_step, bt, dp, &stage_wf_left, &stage_wf_right, stage_time_sol); // Initialize discrete problems for the assembling of the // matrix M and the stage Jacobian matrix and residual. DiscreteProblem stage_dp_left(&stage_wf_left, K_space); DiscreteProblem stage_dp_right(&stage_wf_right, stage_spaces); // Vector K_vector of length num_stages * ndof. will represent // the 'K_i' vectors in the usual R-K notation. scalar* K_vector = new scalar[num_stages*ndof]; memset(K_vector, 0, num_stages * ndof * sizeof(scalar)); // Vector u_ext_vec will represent h \sum_{j=1}^s a_{ij} K_i. scalar* u_ext_vec = new scalar[num_stages*ndof]; // Vector for the left part of the residual. scalar* vector_left = new scalar[num_stages*ndof]; // Prepare residuals of stage solutions. Hermes::vector<Solution*> residuals; Hermes::vector<bool> add_dir_lift; for (int i = 0; i < num_stages; i++) { residuals.push_back(new Solution(K_mesh)); add_dir_lift.push_back(false); } // Assemble the block-diagonal mass matrix M of size ndof times ndof. // The corresponding part of the global residual vector is obtained // just by multiplication. stage_dp_left.assemble(matrix_left); // The Newton's loop. double residual_norm; int it = 1; while (true) { // Prepare vector h\sum_{j=1}^s a_{ij} K_j. for (int i = 0; i < num_stages; i++) { // block row for (int idx = 0; idx < ndof; idx++) { scalar increment = 0; for (int j = 0; j < num_stages; j++) { increment += bt->get_A(i, j) * K_vector[j*ndof + idx]; } u_ext_vec[i*ndof + idx] = time_step * increment; } } multiply_as_diagonal_block_matrix(matrix_left, num_stages, K_vector, vector_left); // Assemble the block Jacobian matrix of the stationary residual F // Diagonal blocks are created even if empty, so that matrix_left // can be added later. bool rhs_only = false; bool force_diagonal_blocks = true; stage_dp_right.assemble(u_ext_vec, matrix_right, vector_right, rhs_only, force_diagonal_blocks, false); // false = do not add Dirichlet lift while // converting u_ext_vec into Solutions. matrix_right->add_to_diagonal_blocks(num_stages, matrix_left); vector_right->add_vector(vector_left); // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). vector_right->change_sign(); // Measure the residual norm. if (HERMES_RESIDUAL_AS_VECTOR_RK) { // Calculate the l2-norm of residual vector. residual_norm = get_l2_norm(vector_right); } else { // Translate residual vector into residual functions. Solution::vector_to_solutions(vector_right, stage_dp_right.get_spaces(), residuals, add_dir_lift); residual_norm = calc_norms(residuals); } // Info for the user. if (verbose) info("---- Newton iter %d, ndof %d, residual norm %g", it, ndof, residual_norm); // If maximum allowed residual norm is exceeded, fail. if (residual_norm > newton_max_allowed_residual_norm) { if (verbose) { info("Current residual norm: %g", residual_norm); info("Maximum allowed residual norm: %g", newton_max_allowed_residual_norm); info("Newton solve not successful, returning false."); } return false; } // If residual norm is within tolerance, or the maximum number // of iteration has been reached, or the problem is linear, then quit. if ((residual_norm < newton_tol || it > newton_max_iter) && it > 1) break; // Solve the linear system. if(!solver->solve()) error ("Matrix solver failed.\n"); // Add \deltaK^{n+1} to K^n. for (int i = 0; i < num_stages*ndof; i++) { K_vector[i] += newton_damping_coeff * solver->get_solution()[i]; } // If the problem is linear, quit. if (is_linear) { if (verbose) { info("Terminating Newton's loop as problem is linear."); } break; } // Increase iteration counter. it++; } // If max number of iterations was exceeded, fail. if (it >= newton_max_iter) { if (verbose) info("Maximum allowed number of Newton iterations exceeded, returning false."); return false; } // Project previous time level solution on the stage space, // to be able to add them together. The result of the projection // will be stored in the vector coeff_vec. // FIXME - this projection is slow and it is not needed when the // spaces are the same (if spatial adaptivity does not take place). scalar* coeff_vec = new scalar[ndof]; OGProjection::project_global(K_space, sln_time_prev, coeff_vec, matrix_solver); // Calculate new time level solution in the stage space (u_{n+1} = u_n + h \sum_{j=1}^s b_j k_j). for (int i = 0; i < ndof; i++) { for (int j = 0; j < num_stages; j++) { coeff_vec[i] += time_step * bt->get_B(j) * K_vector[j*ndof + i]; } } Solution::vector_to_solution(coeff_vec, K_space, sln_time_new); // If error_fn is not NULL, use the B2-row in the Butcher's // table to calculate the temporal error estimate. if (error_fn != NULL) { for (int i = 0; i < ndof; i++) { coeff_vec[i] = 0; for (int j = 0; j < num_stages; j++) { coeff_vec[i] += (bt->get_B(j) - bt->get_B2(j)) * K_vector[j*ndof + i]; } coeff_vec[i] *= time_step; } Solution::vector_to_solution(coeff_vec, K_space, error_fn, false); } // Clean up. delete matrix_left; delete matrix_right; delete vector_right; delete solver; // Delete stage spaces, but not the first (original) one. for (int i = 1; i < num_stages; i++) delete stage_spaces[i]; // Delete all residuals. for (int i = 0; i < num_stages; i++) delete residuals[i]; // Delete artificial Solutions with stage times. for (int i = 0; i < num_stages; i++) delete stage_time_sol[i]; delete [] stage_time_sol; // Clean up. delete [] K_vector; delete [] u_ext_vec; delete [] coeff_vec; delete [] vector_left; return true; }
bool rk_time_step(double current_time, double time_step, ButcherTable* const bt, scalar* coeff_vec, scalar* err_vec, DiscreteProblem* dp, MatrixSolverType matrix_solver, bool verbose, bool is_linear, double newton_tol, int newton_max_iter, double newton_damping_coeff, double newton_max_allowed_residual_norm) { // Check for not implemented features. if (matrix_solver != SOLVER_UMFPACK) error("Sorry, rk_time_step() still only works with UMFpack."); if (dp->get_weak_formulation()->get_neq() > 1) error("Sorry, rk_time_step() does not work with systems yet."); // Get number of stages from the Butcher's table. int num_stages = bt->get_size(); // Check whether the user provided a second B-row if he wants // err_vec. if(err_vec != NULL) { double b2_coeff_sum = 0; for (int i=0; i < num_stages; i++) b2_coeff_sum += fabs(bt->get_B2(i)); if (b2_coeff_sum < 1e-10) error("err_vec != NULL but the B2 row in the Butcher's table is zero in rk_time_step()."); } // Matrix for the time derivative part of the equation (left-hand side). UMFPackMatrix* matrix_left = new UMFPackMatrix(); // Matrix and vector for the rest (right-hand side). UMFPackMatrix* matrix_right = new UMFPackMatrix(); UMFPackVector* vector_right = new UMFPackVector(); // Create matrix solver. Solver* solver = create_linear_solver(matrix_solver, matrix_right, vector_right); // Get original space, mesh, and ndof. dp->get_space(0); Mesh* mesh = dp->get_space(0)->get_mesh(); int ndof = dp->get_space(0)->get_num_dofs(); // Create spaces for stage solutions. This is necessary // to define a num_stages x num_stages block weak formulation. Hermes::vector<Space*> stage_spaces; stage_spaces.push_back(dp->get_space(0)); for (int i = 1; i < num_stages; i++) { stage_spaces.push_back(dp->get_space(0)->dup(mesh)); } Space::assign_dofs(stage_spaces); // Create a multistage weak formulation. WeakForm stage_wf_left; // For the matrix M (size ndof times ndof). WeakForm stage_wf_right(num_stages); // For the rest of equation (written on the right), // size num_stages*ndof times num_stages*ndof. create_stage_wf(current_time, time_step, bt, dp, &stage_wf_left, &stage_wf_right); // Initialize discrete problems for the assembling of the // matrix M and the stage Jacobian matrix and residual. DiscreteProblem stage_dp_left(&stage_wf_left, dp->get_space(0)); DiscreteProblem stage_dp_right(&stage_wf_right, stage_spaces); // Vector K_vector of length num_stages * ndof. will represent // the 'k_i' vectors in the usual R-K notation. scalar* K_vector = new scalar[num_stages*ndof]; memset(K_vector, 0, num_stages * ndof * sizeof(scalar)); // Vector u_prev_vec will represent y_n + h \sum_{j=1}^s a_{ij}k_i // in the usual R-K notation. scalar* u_prev_vec = new scalar[num_stages*ndof]; // Vector for the left part of the residual. scalar* vector_left = new scalar[num_stages*ndof]; // Prepare residuals of stage solutions. Hermes::vector<Solution*> residuals; Hermes::vector<bool> add_dir_lift; for (int i = 0; i < num_stages; i++) { residuals.push_back(new Solution(mesh)); add_dir_lift.push_back(false); } // Assemble the block-diagonal mass matrix M of size ndof times ndof. // The corresponding part of the global residual vector is obtained // just by multiplication. stage_dp_left.assemble(matrix_left); // The Newton's loop. double residual_norm; int it = 1; while (true) { // Prepare vector Y_n + h\sum_{j=1}^s a_{ij} K_j. for (int i = 0; i < num_stages; i++) { // block row for (int idx = 0; idx < ndof; idx++) { scalar increment = 0; for (int j = 0; j < num_stages; j++) { increment += bt->get_A(i, j) * K_vector[j*ndof + idx]; } u_prev_vec[i*ndof + idx] = coeff_vec[idx] + time_step * increment; } } multiply_as_diagonal_block_matrix(matrix_left, num_stages, K_vector, vector_left); // Assemble the block Jacobian matrix of the stationary residual F // Diagonal blocks are created even if empty, so that matrix_left // can be added later. bool rhs_only = false; bool force_diagonal_blocks = true; stage_dp_right.assemble(u_prev_vec, matrix_right, vector_right, rhs_only, force_diagonal_blocks); matrix_right->add_to_diagonal_blocks(num_stages, matrix_left); vector_right->add_vector(vector_left); // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). vector_right->change_sign(); // Measure the residual norm. if (HERMES_RESIDUAL_AS_VECTOR_RK) { // Calculate the l2-norm of residual vector. residual_norm = get_l2_norm(vector_right); } else { // Translate residual vector into residual functions. Solution::vector_to_solutions(vector_right, stage_dp_right.get_spaces(), residuals, add_dir_lift); residual_norm = calc_norms(residuals); } // Info for the user. if (verbose) info("---- Newton iter %d, ndof %d, residual norm %g", it, ndof, residual_norm); // If maximum allowed residual norm is exceeded, fail. if (residual_norm > newton_max_allowed_residual_norm) { if (verbose) { info("Current residual norm: %g", residual_norm); info("Maximum allowed residual norm: %g", newton_max_allowed_residual_norm); info("Newton solve not successful, returning false."); } return false; } // If residual norm is within tolerance, or the maximum number // of iteration has been reached, or the problem is linear, then quit. if ((residual_norm < newton_tol || it > newton_max_iter) && it > 1) break; // Solve the linear system. if(!solver->solve()) error ("Matrix solver failed.\n"); // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < num_stages*ndof; i++) { K_vector[i] += newton_damping_coeff * solver->get_solution()[i]; } // If the problem is linear, quit. if (is_linear) { if (verbose) { info("Terminating Newton's loop as problem is linear."); } break; } // Increase iteration counter. it++; } // If max number of iterations was exceeded, fail. if (it >= newton_max_iter) { if (verbose) info("Maximum allowed number of Newton iterations exceeded, returning false."); return false; } // Calculate the vector Y^{n+1} = Y^n + h \sum_{j=1}^s b_j k_j. for (int i = 0; i < ndof; i++) { for (int j = 0; j < num_stages; j++) { coeff_vec[i] += time_step * bt->get_B(j) * K_vector[j*ndof + i]; } } // If err_vec is not NULL, use the second B-row in the Butcher's // table to calculate the second approximation Y_{n+1}. Then // subtract the original one from it, and return this as an // error vector err_vec. if (err_vec != NULL) { for (int i = 0; i < ndof; i++) { err_vec[i] = 0; for (int j = 0; j < num_stages; j++) { err_vec[i] += (bt->get_B(j) - bt->get_B2(j)) * K_vector[j*ndof + i]; } err_vec[i] *= time_step; } } // Clean up. delete matrix_left; delete matrix_right; delete vector_right; delete solver; // Delete stage spaces, but not the first (original) one. for (int i = 1; i < num_stages; i++) delete stage_spaces[i]; // Delete all residuals. for (int i = 0; i < num_stages; i++) delete residuals[i]; // TODO: Delete stage_wf, in particular its external solutions // stage_time_sol[i], i = 0, 1, ..., num_stages-1. // Delete stage_vec and u_prev_vec. delete [] K_vector; delete [] u_prev_vec; // debug delete [] vector_left; return true; }
int main(int argc, char* argv[]) { #ifdef THREAD_TESTING HermesCommonApi.set_integral_param_value(numThreads, 8); #endif // Load the mesh. MeshSharedPtr mesh(new Mesh); Hermes::vector<MeshSharedPtr> meshes; meshes.push_back(mesh); MeshReaderH2DXML mloader; mloader.load("agrosMesh.msh", meshes); // Perform initial mesh refinements. for (int i = 0; i < INIT_REF_NUM; i++) mesh->refine_all_elements(); // Initialize boundary conditions. DefaultEssentialBCConst<complex> bc_essential("4", P_SOURCE); EssentialBCs<complex> bcs(&bc_essential); // Create an H1 space with default shapeset. SpaceSharedPtr<complex> space(new H1Space<complex> (mesh, &bcs, P_INIT)); adaptivity.set_space(space); // Initialize the weak formulation. CustomWeakFormAcoustics wf("0", RHO, SOUND_SPEED, OMEGA); // Initialize coarse and reference mesh solution. MeshFunctionSharedPtr<complex> sln(new Solution<complex>), ref_sln(new Solution<complex>); // Initialize refinement selector. H1ProjBasedSelector<complex> selector(CAND_LIST); Hermes::Hermes2D::NewtonSolver<complex> newton; newton.set_weak_formulation(&wf); // 2 Adaptivity steps: int as = 1; bool done = false; do { // Construct globally refined reference mesh and setup reference space. Mesh::ReferenceMeshCreator refMeshCreator(mesh); MeshSharedPtr ref_mesh = refMeshCreator.create_ref_mesh(); Space<complex>::ReferenceSpaceCreator refSpaceCreator(space, ref_mesh); SpaceSharedPtr<complex> ref_space = refSpaceCreator.create_ref_space(); // Perform Newton's iteration. try { newton.set_space(ref_space); 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<complex> sln-> Hermes::Hermes2D::Solution<complex>::vector_to_solution(newton.get_sln_vector(), ref_space, ref_sln); // Project the fine mesh solution onto the coarse mesh. OGProjection<complex> ogProjection; ogProjection.project_global(space, ref_sln, sln); // Calculate element errors and total error estimate. errorCalculator.calculate_errors(sln, ref_sln); adaptivity.adapt(&selector); } while (as++ < 2); return 0; }
int main() { // Time measurement. TimePeriod cpu_time; cpu_time.tick(); // Create space, set Dirichlet BC, enumerate basis functions. Space* space = new Space(A, B, NELEM, DIR_BC_LEFT, DIR_BC_RIGHT, P_INIT, NEQ, NEQ); // Enumerate basis functions, info for user. int ndof = Space::get_num_dofs(space); info("ndof: %d", ndof); // Initialize the weak formulation. WeakForm wf(2); wf.add_matrix_form(0, 0, jacobian_0_0); wf.add_matrix_form(0, 1, jacobian_0_1); wf.add_matrix_form(1, 0, jacobian_1_0); wf.add_matrix_form(1, 1, jacobian_1_1); wf.add_vector_form(0, residual_0); wf.add_vector_form(1, residual_1); // Initialize the FE problem. bool is_linear = false; DiscreteProblem *dp = new DiscreteProblem(&wf, space, is_linear); // Newton's loop. // Fill vector coeff_vec using dof and coeffs arrays in elements. double *coeff_vec = new double[Space::get_num_dofs(space)]; get_coeff_vector(space, coeff_vec); // 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); int it = 1; bool success = false; while (1) { // Obtain the number of degrees of freedom. int ndof = Space::get_num_dofs(space); // Assemble the Jacobian matrix and residual vector. dp->assemble(coeff_vec, 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), 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 && 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(!(success = 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); it++; } info("Total running time: %g s", cpu_time.accumulated()); // Test variable. info("ndof = %d.", Space::get_num_dofs(space)); // Cleanup. for(unsigned i = 0; i < DIR_BC_LEFT.size(); i++) delete DIR_BC_LEFT[i]; DIR_BC_LEFT.clear(); for(unsigned i = 0; i < DIR_BC_RIGHT.size(); i++) delete DIR_BC_RIGHT[i]; DIR_BC_RIGHT.clear(); delete matrix; delete rhs; delete solver; delete[] coeff_vec; delete dp; delete space; if (success) { info("Success!"); return ERROR_SUCCESS; } else { info("Failure!"); return ERROR_FAILURE; } }
bool NewtonSolver<Scalar>::solve_keep_jacobian(Scalar* coeff_vec, double newton_tol, int newton_max_iter, bool residual_as_function) { // Obtain the number of degrees of freedom. int ndof = this->dp->get_num_dofs(); // The Newton's loop. double residual_norm; int it = 1; while (1) { // Assemble the residual vector. this->dp->assemble(coeff_vec, residual); // Measure the residual norm. if (residual_as_function) { // Prepare solutions for measuring residual norm. Hermes::vector<Solution<Scalar>*> solutions; Hermes::vector<bool> dir_lift_false; for (unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++) { solutions.push_back(new Solution<Scalar>()); dir_lift_false.push_back(false); } Solution<Scalar>::vector_to_solutions(residual, static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces(), solutions, dir_lift_false); // Calculate the norm. residual_norm = Global<Scalar>::calc_norms(solutions); // Clean up. for (unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++) delete solutions[i]; } else { // Calculate the l2-norm of residual vector, this is the traditional way. residual_norm = Global<Scalar>::get_l2_norm(residual); } // Info for the user. if(it == 1) { if(this->verbose_output) info("---- Newton initial residual norm: %g", residual_norm); } else if(this->verbose_output) info("---- Newton iter %d, residual norm: %g", it - 1, residual_norm); // If maximum allowed residual norm is exceeded, fail. if (residual_norm > max_allowed_residual_norm) { if (this->verbose_output) { info("Current residual norm: %g", residual_norm); info("Maximum allowed residual norm: %g", max_allowed_residual_norm); info("Newton solve not successful, returning false."); } break; } // If residual norm is within tolerance, return 'true'. // This is the only correct way of ending. if (residual_norm < newton_tol && it > 1) { // We want to return the solution in a different structure. this->sln_vector = new Scalar[ndof]; for (int i = 0; i < ndof; i++) this->sln_vector[i] = coeff_vec[i]; return true; } // Assemble and keep the jacobian if this has not been done before. // Also declare that LU-factorization in case of a direct solver will be done only once and reused afterwards. if(kept_jacobian == NULL) { kept_jacobian = create_matrix<Scalar>(this->matrix_solver_type); // Give the matrix solver the correct Jacobian. NOTE: It would be cleaner if the whole decision whether to keep // Jacobian or not was made in the constructor. // // Delete the matrix solver created in the constructor. delete linear_solver; // Create new matrix solver with correct matrix. linear_solver = create_linear_solver<Scalar>(this->matrix_solver_type, kept_jacobian, residual); this->dp->assemble(coeff_vec, kept_jacobian); linear_solver->set_factorization_scheme(HERMES_REUSE_FACTORIZATION_COMPLETELY); } // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). residual->change_sign(); // Solve the linear system. if(!linear_solver->solve()) { if (this->verbose_output) info ("Matrix<Scalar> solver failed. Returning false.\n"); break; } // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof; i++) coeff_vec[i] += linear_solver->get_sln_vector()[i]; // Increase the number of iterations and test if we are still under the limit. if (it++ >= newton_max_iter) { if (this->verbose_output) info("Maximum allowed number of Newton iterations exceeded, returning false."); break; } } // Return false. // All 'bad' situations end here. return false; }
void NeighborSearch<Scalar>::Transformations::copy_from(const Hermes::vector<unsigned int>& t) { num_levels = std::min<unsigned int>(t.size(), max_level); std::copy( t.begin(), t.begin() + num_levels, transf); }
bool NewtonSolver<Scalar>::solve(Scalar* coeff_vec, double newton_tol, int newton_max_iter, bool residual_as_function) { // Delete the old solution vector, if there is any. if(this->sln_vector != NULL) { delete [] this->sln_vector; this->sln_vector = NULL; } // Obtain the number of degrees of freedom. int ndof = this->dp->get_num_dofs(); // The Newton's loop. double residual_norm; int it = 1; bool delete_timer = false; if (this->timer == NULL) { this->timer = new TimePeriod; delete_timer = true; } this->timer->tick(); setup_time += this->timer->last(); while (1) { // Assemble just the residual vector. if(it > 1) static_cast<DiscreteProblem<Scalar>*>(this->dp)->temp_disable_adaptivity_cache(); this->dp->assemble(coeff_vec, residual); this->timer->tick(); assemble_time += this->timer->last(); // Measure the residual norm. if (residual_as_function) { // Prepare solutions for measuring residual norm. Hermes::vector<Solution<Scalar>*> solutions; Hermes::vector<bool> dir_lift_false; for (unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++) { solutions.push_back(new Solution<Scalar>()); dir_lift_false.push_back(false); } Solution<Scalar>::vector_to_solutions(residual, static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces(), solutions, dir_lift_false); // Calculate the norm. residual_norm = Global<Scalar>::calc_norms(solutions); // Clean up. for (unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++) delete solutions[i]; } else { // Calculate the l2-norm of residual vector, this is the traditional way. residual_norm = Global<Scalar>::get_l2_norm(residual); } // Info for the user. if(it == 1) { if(this->verbose_output) info("---- Newton initial residual norm: %g", residual_norm); } else if(this->verbose_output) info("---- Newton iter %d, residual norm: %g", it - 1, residual_norm); // If maximum allowed residual norm is exceeded, fail. if (residual_norm > max_allowed_residual_norm) { if (this->verbose_output) { info("Current residual norm: %g", residual_norm); info("Maximum allowed residual norm: %g", max_allowed_residual_norm); info("Newton solve not successful, returning false."); } break; } // If residual norm is within tolerance, return 'true'. // This is the only correct way of ending. if (residual_norm < newton_tol && it > 1) { // We want to return the solution in a different structure. this->sln_vector = new Scalar[ndof]; for (int i = 0; i < ndof; i++) this->sln_vector[i] = coeff_vec[i]; this->timer->tick(); solve_time += this->timer->last(); if (delete_timer) { delete this->timer; this->timer = NULL; } static_cast<DiscreteProblem<Scalar>*>(this->dp)->temp_enable_adaptivity_cache(); return true; } this->timer->tick(); solve_time += this->timer->last(); // Assemble just the jacobian. this->dp->assemble(coeff_vec, jacobian); this->timer->tick(); assemble_time += this->timer->last(); // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). residual->change_sign(); // Solve the linear system. if(!linear_solver->solve()) { if (this->verbose_output) info ("Matrix<Scalar> solver failed. Returning false.\n"); break; } // Add \deltaY^{n+1} to Y^n. for (int i = 0; i < ndof; i++) coeff_vec[i] += linear_solver->get_sln_vector()[i]; // Increase the number of iterations and test if we are still under the limit. if (it++ >= newton_max_iter) { if (this->verbose_output) info("Maximum allowed number of Newton iterations exceeded, returning false."); break; } this->timer->tick(); solve_time += this->timer->last(); } // Return false. // All 'bad' situations end here. if (delete_timer) { delete this->timer; this->timer = NULL; } return false; }
void NeighborSearch<Scalar>::Transformations::apply_on(const Hermes::vector<Transformable*>& tr) const { for(Hermes::vector<Transformable*>::const_iterator it = tr.begin(); it != tr.end(); ++it) for(unsigned int i = 0; i < num_levels; i++) (*it)->push_transform(transf[i]); }
int main(int argc, char* argv[]) { // Load the mesh. Mesh mesh_whole_domain, mesh_without_hole; Hermes::vector<Mesh*> meshes (&mesh_whole_domain, &mesh_without_hole); MeshReaderH2DXML mloader; mloader.load("subdomains.xml", meshes); // Perform initial mesh refinements (optional). for(int i = 0; i < INIT_REF_NUM; i++) for(unsigned int meshes_i = 0; meshes_i < meshes.size(); meshes_i++) meshes[meshes_i]->refine_all_elements(); // Perform refinement towards the hole. for(unsigned int meshes_i = 0; meshes_i < meshes.size(); meshes_i++) meshes[meshes_i]->refine_towards_boundary("Inner", INIT_REF_NUM_HOLE); // Initialize boundary conditions. // Flow. EssentialBCNonConst bc_inlet_vel_x("Inlet", VEL_INLET, H, STARTUP_TIME); DefaultEssentialBCConst<double> bc_other_vel_x(Hermes::vector<std::string>("Outer", "Inner"), 0.0); EssentialBCs<double> bcs_vel_x(Hermes::vector<EssentialBoundaryCondition<double> *>(&bc_inlet_vel_x, &bc_other_vel_x)); DefaultEssentialBCConst<double> bc_vel_y(Hermes::vector<std::string>("Inlet", "Outer", "Inner"), 0.0); EssentialBCs<double> bcs_vel_y(&bc_vel_y); EssentialBCs<double> bcs_pressure; // Temperature. DefaultEssentialBCConst<double> bc_temperature(Hermes::vector<std::string>("Inlet", "Outer"), 20.0); EssentialBCs<double> bcs_temperature(&bc_temperature); // Spaces for velocity components and pressure. H1Space<double> xvel_space(&mesh_without_hole, &bcs_vel_x, P_INIT_VEL); H1Space<double> yvel_space(&mesh_without_hole, &bcs_vel_y, P_INIT_VEL); #ifdef PRESSURE_IN_L2 L2Space<double> p_space(&mesh_without_hole, P_INIT_PRESSURE); #else H1Space<double> p_space(&mesh_without_hole, &bcs_pressure, P_INIT_PRESSURE); #endif // Space<double> for temperature. H1Space<double> temperature_space(&mesh_whole_domain, &bcs_temperature, P_INIT_TEMP); // Calculate and report the number of degrees of freedom. int ndof = Space<double>::get_num_dofs(Hermes::vector<Space<double> *>(&xvel_space, &yvel_space, &p_space, &temperature_space)); info("ndof = %d.", ndof); // Define projection norms. ProjNormType vel_proj_norm = HERMES_H1_NORM; #ifdef PRESSURE_IN_L2 ProjNormType p_proj_norm = HERMES_L2_NORM; #else ProjNormType p_proj_norm = HERMES_H1_NORM; #endif ProjNormType temperature_proj_norm = HERMES_H1_NORM; // Solutions for the Newton's iteration and time stepping. info("Setting initial conditions."); ZeroSolution xvel_prev_time(&mesh_without_hole), yvel_prev_time(&mesh_without_hole), p_prev_time(&mesh_without_hole); ConstantSolution<double> temperature_prev_time(&mesh_whole_domain, TEMP_INIT); // Calculate Reynolds number. double reynolds_number = VEL_INLET * OBSTACLE_DIAMETER / KINEMATIC_VISCOSITY_WATER; info("RE = %g", reynolds_number); // Initialize weak formulation. CustomWeakFormHeatAndFlow wf(STOKES, reynolds_number, time_step, &xvel_prev_time, &yvel_prev_time, &temperature_prev_time, HEAT_SOURCE_GRAPHITE, SPECIFIC_HEAT_GRAPHITE, SPECIFIC_HEAT_WATER, RHO_GRAPHITE, RHO_WATER, THERMAL_CONDUCTIVITY_GRAPHITE, THERMAL_CONDUCTIVITY_WATER); // Initialize the FE problem. DiscreteProblem<double> dp(&wf, Hermes::vector<Space<double> *>(&xvel_space, &yvel_space, &p_space, &temperature_space)); // Initialize the Newton solver. NewtonSolver<double> newton(&dp, matrix_solver_type); // Initialize views. Views::VectorView vview("velocity [m/s]", new Views::WinGeom(0, 0, 500, 300)); Views::ScalarView pview("pressure [Pa]", new Views::WinGeom(0, 310, 500, 300)); Views::ScalarView tempview("temperature [C]", new Views::WinGeom(510, 0, 500, 300)); vview.set_min_max_range(0, 1.6); vview.fix_scale_width(80); //pview.set_min_max_range(-0.9, 1.0); pview.fix_scale_width(80); pview.show_mesh(true); // Project the initial condition on the FE space to obtain initial // coefficient vector for the Newton's method. double* coeff_vec = new double[ndof]; info("Projecting initial condition to obtain initial vector for the Newton's method."); OGProjection<double>::project_global(Hermes::vector<Space<double> *>(&xvel_space, &yvel_space, &p_space, &temperature_space), Hermes::vector<MeshFunction<double> *>(&xvel_prev_time, &yvel_prev_time, &p_prev_time, &temperature_prev_time), coeff_vec, matrix_solver_type, Hermes::vector<ProjNormType>(vel_proj_norm, vel_proj_norm, p_proj_norm, temperature_proj_norm)); // Time-stepping loop: char title[100]; int num_time_steps = T_FINAL / time_step; double current_time = 0.0; for (int ts = 1; ts <= num_time_steps; ts++) { current_time += time_step; info("---- Time step %d, time = %g:", ts, current_time); // Update time-dependent essential BCs. if (current_time <= STARTUP_TIME) { info("Updating time-dependent essential BC."); Space<double>::update_essential_bc_values(Hermes::vector<Space<double> *>(&xvel_space, &yvel_space, &p_space, &temperature_space), current_time); } // Perform Newton's iteration. info("Solving nonlinear problem:"); bool verbose = true; // Perform Newton's iteration and translate the resulting coefficient vector into previous time level solutions. newton.set_verbose_output(verbose); try { newton.solve(coeff_vec, NEWTON_TOL, NEWTON_MAX_ITER); } catch(Hermes::Exceptions::Exception e) { e.printMsg(); error("Newton's iteration failed."); }; { Hermes::vector<Solution<double> *> tmp(&xvel_prev_time, &yvel_prev_time, &p_prev_time, &temperature_prev_time); Solution<double>::vector_to_solutions(newton.get_sln_vector(), Hermes::vector<Space<double> *>(&xvel_space, &yvel_space, &p_space, &temperature_space), tmp); } // Show the solution at the end of time step. sprintf(title, "Velocity [m/s], time %g s", current_time); vview.set_title(title); vview.show(&xvel_prev_time, &yvel_prev_time, Views::HERMES_EPS_LOW); sprintf(title, "Pressure [Pa], time %g s", current_time); pview.set_title(title); pview.show(&p_prev_time); sprintf(title, "Temperature [C], time %g s", current_time); tempview.set_title(title); tempview.show(&temperature_prev_time); } delete [] coeff_vec; // Wait for all views to be closed. Views::View::wait(); return 0; }
void NeighborSearch<Scalar>::handle_sub_idx_way_down(const Hermes::vector<unsigned int>& transformations) { Hermes::vector<unsigned int> neighbors_to_be_deleted; Hermes::vector<unsigned int> neighbors_not_to_be_deleted; Hermes::vector<unsigned int> updated_transformations; for(int i = 0; i < transformations.size(); i++) { if(! ((active_edge == 0 && transformations[i] == 4) || (active_edge == 1 && transformations[i] == 7) || (active_edge == 2 && transformations[i] == 5) || (active_edge == 3 && transformations[i] == 6)) ) { if(active_edge == 0 && transformations[i] == 6) updated_transformations.push_back(0); else if(active_edge == 0 && transformations[i] == 7) updated_transformations.push_back(1); else if(active_edge == 1 && transformations[i] == 4) updated_transformations.push_back(1); else if(active_edge == 1 && transformations[i] == 5) updated_transformations.push_back(2); else if(active_edge == 2 && transformations[i] == 6) updated_transformations.push_back(3); else if(active_edge == 2 && transformations[i] == 7) updated_transformations.push_back(2); else if(active_edge == 3 && transformations[i] == 4) updated_transformations.push_back(0); else if(active_edge == 3 && transformations[i] == 5) updated_transformations.push_back(3); else updated_transformations.push_back(transformations[i]); } } // We basically identify the neighbors that are not compliant with the current sub-element mapping on the central element. for(unsigned int neighbor_i = 0; neighbor_i < n_neighbors; neighbor_i++) { bool deleted = false; Transformations* current_transforms = central_transformations.get(neighbor_i); for(unsigned int level = 0; level < std::min((unsigned int)updated_transformations.size(), current_transforms->num_levels); level++) { // If the found neighbor is not a neighbor of this subelement. if(!compatible_transformations(current_transforms->transf[level], updated_transformations[level], active_edge)) { deleted = true; break; } } /* // If there were more sub-element transformation from the assembling than from the neighbor search. if(!deleted) { if((unsigned int)updated_transformations.size() > current_transforms->num_levels) { for(unsigned int level = current_transforms->num_levels; level < (unsigned int)updated_transformations.size(); level++) { // If the found neighbor is not a neighbor of this subelement. if(!compatible_transformations(current_transforms->transf[current_transforms->num_levels - 1], updated_transformations[level], active_edge)) { deleted = true; break; } } } } */ if(deleted) neighbors_to_be_deleted.push_back(neighbor_i); else neighbors_not_to_be_deleted.push_back(neighbor_i); } // Now we truly delete (in the reverse order) the neighbors. if(neighbors_to_be_deleted.size() > 0) for(unsigned int neighbors_to_be_deleted_i = neighbors_to_be_deleted.size(); neighbors_to_be_deleted_i >= 1; neighbors_to_be_deleted_i--) delete_neighbor(neighbors_to_be_deleted[neighbors_to_be_deleted_i - 1]); }
double KellyTypeAdapt::calc_err_internal(Hermes::vector<Solution *> slns, Hermes::vector<double>* component_errors, unsigned int error_flags) { int n = slns.size(); error_if (n != this->num, "Wrong number of solutions."); TimePeriod tmr; for (int i = 0; i < n; i++) { this->sln[i] = slns[i]; sln[i]->set_quad_2d(&g_quad_2d_std); } have_coarse_solutions = true; WeakForm::Stage stage; num_act_elems = 0; for (int i = 0; i < num; i++) { stage.meshes.push_back(sln[i]->get_mesh()); stage.fns.push_back(sln[i]); num_act_elems += stage.meshes[i]->get_num_active_elements(); int max = stage.meshes[i]->get_max_element_id(); if (errors[i] != NULL) delete [] errors[i]; errors[i] = new double[max]; memset(errors[i], 0.0, sizeof(double) * max); } /* for (unsigned int i = 0; i < error_estimators_vol.size(); i++) trset.insert(error_estimators_vol[i].ext.begin(), error_estimators_vol[i].ext.end()); for (unsigned int i = 0; i < error_estimators_surf.size(); i++) trset.insert(error_estimators_surf[i].ext.begin(), error_estimators_surf[i].ext.end()); */ double total_norm = 0.0; bool calc_norm = false; if ((error_flags & HERMES_ELEMENT_ERROR_MASK) == HERMES_ELEMENT_ERROR_REL || (error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_REL) calc_norm = true; double *norms = NULL; if (calc_norm) { norms = new double[num]; memset(norms, 0.0, num * sizeof(double)); } double *errors_components = new double[num]; memset(errors_components, 0.0, num * sizeof(double)); this->errors_squared_sum = 0.0; double total_error = 0.0; bool bnd[4]; // FIXME: magic number - maximal possible number of element surfaces SurfPos surf_pos[4]; Element **ee; Traverse trav; // Reset the e->visited status of each element of each mesh (most likely it will be set to true from // the latest assembling procedure). if (ignore_visited_segments) { for (int i = 0; i < num; i++) { Element* e; for_all_active_elements(e, stage.meshes[i]) e->visited = false; } } //WARNING: AD HOC debugging parameter. bool multimesh = false; // Begin the multimesh traversal. trav.begin(num, &(stage.meshes.front()), &(stage.fns.front())); while ((ee = trav.get_next_state(bnd, surf_pos)) != NULL) { // Go through all solution components. for (int i = 0; i < num; i++) { if (ee[i] == NULL) continue; // Set maximum integration order for use in integrals, see limit_order() update_limit_table(ee[i]->get_mode()); RefMap *rm = sln[i]->get_refmap(); double err = 0.0; // Go through all volumetric error estimators. for (unsigned int iest = 0; iest < error_estimators_vol.size(); iest++) { // Skip current error estimator if it is assigned to a different component or geometric area // different from that of the current active element. if (error_estimators_vol[iest]->i != i) continue; /* if (error_estimators_vol[iest].area != ee[i]->marker) continue; */ else if (error_estimators_vol[iest]->area != HERMES_ANY) continue; err += eval_volumetric_estimator(error_estimators_vol[iest], rm); } // Go through all surface error estimators (includes both interface and boundary est's). for (unsigned int iest = 0; iest < error_estimators_surf.size(); iest++) { if (error_estimators_surf[iest]->i != i) continue; for (int isurf = 0; isurf < ee[i]->get_num_surf(); isurf++) { /* if (error_estimators_surf[iest].area > 0 && error_estimators_surf[iest].area != surf_pos[isurf].marker) continue; */ if (bnd[isurf]) // Boundary { if (error_estimators_surf[iest]->area == H2D_DG_INNER_EDGE) continue; /* if (boundary_markers_conversion.get_internal_marker(error_estimators_surf[iest].area) < 0 && error_estimators_surf[iest].area != HERMES_ANY) continue; */ err += eval_boundary_estimator(error_estimators_surf[iest], rm, surf_pos); } else // Interface { if (error_estimators_surf[iest]->area != H2D_DG_INNER_EDGE) continue; /* BEGIN COPY FROM DISCRETE_PROBLEM.CPP */ // 5 is for bits per page in the array. LightArray<NeighborSearch*> neighbor_searches(5); unsigned int num_neighbors = 0; DiscreteProblem::NeighborNode* root; int ns_index; dp.min_dg_mesh_seq = 0; for(int j = 0; j < num; j++) if(stage.meshes[j]->get_seq() < dp.min_dg_mesh_seq || j == 0) dp.min_dg_mesh_seq = stage.meshes[j]->get_seq(); ns_index = stage.meshes[i]->get_seq() - dp.min_dg_mesh_seq; // = 0 for single mesh // Determine the minimum mesh seq in this stage. if (multimesh) { // Initialize the NeighborSearches. dp.init_neighbors(neighbor_searches, stage, isurf); // Create a multimesh tree; root = new DiscreteProblem::NeighborNode(NULL, 0); dp.build_multimesh_tree(root, neighbor_searches); // Update all NeighborSearches according to the multimesh tree. // After this, all NeighborSearches in neighbor_searches should have the same count // of neighbors and proper set of transformations // for the central and the neighbor element(s) alike. // Also check that every NeighborSearch has the same number of neighbor elements. for(unsigned int j = 0; j < neighbor_searches.get_size(); j++) if(neighbor_searches.present(j)) { NeighborSearch* ns = neighbor_searches.get(j); dp.update_neighbor_search(ns, root); if(num_neighbors == 0) num_neighbors = ns->n_neighbors; if(ns->n_neighbors != num_neighbors) error("Num_neighbors of different NeighborSearches not matching in KellyTypeAdapt::calc_err_internal."); } } else { NeighborSearch *ns = new NeighborSearch(ee[i], stage.meshes[i]); ns->original_central_el_transform = stage.fns[i]->get_transform(); ns->set_active_edge(isurf); ns->clear_initial_sub_idx(); num_neighbors = ns->n_neighbors; neighbor_searches.add(ns, ns_index); } // Go through all segments of the currently processed interface (segmentation is caused // by hanging nodes on the other side of the interface). for (unsigned int neighbor = 0; neighbor < num_neighbors; neighbor++) { if (ignore_visited_segments) { bool processed = true; for(unsigned int j = 0; j < neighbor_searches.get_size(); j++) if(neighbor_searches.present(j)) if(!neighbor_searches.get(j)->neighbors.at(neighbor)->visited) { processed = false; break; } if (processed) continue; } // Set the active segment in all NeighborSearches for(unsigned int j = 0; j < neighbor_searches.get_size(); j++) if(neighbor_searches.present(j)) { neighbor_searches.get(j)->active_segment = neighbor; neighbor_searches.get(j)->neighb_el = neighbor_searches.get(j)->neighbors[neighbor]; neighbor_searches.get(j)->neighbor_edge = neighbor_searches.get(j)->neighbor_edges[neighbor]; } // Push all the necessary transformations to all functions of this stage. // The important thing is that the transformations to the current subelement are already there. // Also store the current neighbor element and neighbor edge in neighb_el, neighbor_edge. if (multimesh) { for(unsigned int fns_i = 0; fns_i < stage.fns.size(); fns_i++) for(unsigned int trf_i = 0; trf_i < neighbor_searches.get(stage.meshes[fns_i]->get_seq() - dp.min_dg_mesh_seq)->central_n_trans[neighbor]; trf_i++) stage.fns[fns_i]->push_transform(neighbor_searches.get(stage.meshes[fns_i]->get_seq() - dp.min_dg_mesh_seq)->central_transformations[neighbor][trf_i]); } else { // Push the transformations only to the solution on the current mesh for(unsigned int trf_i = 0; trf_i < neighbor_searches.get(ns_index)->central_n_trans[neighbor]; trf_i++) stage.fns[i]->push_transform(neighbor_searches.get(ns_index)->central_transformations[neighbor][trf_i]); } /* END COPY FROM DISCRETE_PROBLEM.CPP */ rm->force_transform(this->sln[i]->get_transform(), this->sln[i]->get_ctm()); // The estimate is multiplied by 0.5 in order to distribute the error equally onto // the two neighboring elements. double central_err = 0.5 * eval_interface_estimator(error_estimators_surf[iest], rm, surf_pos, neighbor_searches, ns_index); double neighb_err = central_err; // Scale the error estimate by the scaling function dependent on the element diameter // (use the central element's diameter). if (use_aposteriori_interface_scaling && interface_scaling_fns[i]) central_err *= interface_scaling_fns[i](ee[i]->get_diameter()); // In the case this edge will be ignored when calculating the error for the element on // the other side, add the now computed error to that element as well. if (ignore_visited_segments) { Element *neighb = neighbor_searches.get(i)->neighb_el; // Scale the error estimate by the scaling function dependent on the element diameter // (use the diameter of the element on the other side). if (use_aposteriori_interface_scaling && interface_scaling_fns[i]) neighb_err *= interface_scaling_fns[i](neighb->get_diameter()); errors_components[i] += central_err + neighb_err; total_error += central_err + neighb_err; errors[i][ee[i]->id] += central_err; errors[i][neighb->id] += neighb_err; } else err += central_err; /* BEGIN COPY FROM DISCRETE_PROBLEM.CPP */ // Clear the transformations from the RefMaps and all functions. if (multimesh) for(unsigned int fns_i = 0; fns_i < stage.fns.size(); fns_i++) stage.fns[fns_i]->set_transform(neighbor_searches.get(stage.meshes[fns_i]->get_seq() - dp.min_dg_mesh_seq)->original_central_el_transform); else stage.fns[i]->set_transform(neighbor_searches.get(ns_index)->original_central_el_transform); rm->set_transform(neighbor_searches.get(ns_index)->original_central_el_transform); /* END COPY FROM DISCRETE_PROBLEM.CPP */ } /* BEGIN COPY FROM DISCRETE_PROBLEM.CPP */ if (multimesh) // Delete the multimesh tree; delete root; // Delete the neighbor_searches array. for(unsigned int j = 0; j < neighbor_searches.get_size(); j++) if(neighbor_searches.present(j)) delete neighbor_searches.get(j); /* END COPY FROM DISCRETE_PROBLEM.CPP */ } } } if (calc_norm) { double nrm = eval_solution_norm(error_form[i][i], rm, sln[i]); norms[i] += nrm; total_norm += nrm; } errors_components[i] += err; total_error += err; errors[i][ee[i]->id] += err; ee[i]->visited = true; } } trav.finish(); // Store the calculation for each solution component separately. if(component_errors != NULL) { component_errors->clear(); for (int i = 0; i < num; i++) { if((error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_ABS) component_errors->push_back(sqrt(errors_components[i])); else if ((error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_REL) component_errors->push_back(sqrt(errors_components[i]/norms[i])); else { error("Unknown total error type (0x%x).", error_flags & HERMES_TOTAL_ERROR_MASK); return -1.0; } } } tmr.tick(); error_time = tmr.accumulated(); // Make the error relative if needed. if ((error_flags & HERMES_ELEMENT_ERROR_MASK) == HERMES_ELEMENT_ERROR_REL) { for (int i = 0; i < num; i++) { Element* e; for_all_active_elements(e, stage.meshes[i]) errors[i][e->id] /= norms[i]; } } this->errors_squared_sum = total_error; // Element error mask is used here, because this variable is used in the adapt() // function, where the processed error (sum of errors of processed element errors) // is matched to this variable. if ((error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_ELEMENT_ERROR_REL) errors_squared_sum /= total_norm; // Prepare an ordered list of elements according to an error. fill_regular_queue(&(stage.meshes.front())); have_errors = true; if (calc_norm) delete [] norms; delete [] errors_components; // Return error value. if ((error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_ABS) return sqrt(total_error); else if ((error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_REL) return sqrt(total_error / total_norm); else { error("Unknown total error type (0x%x).", error_flags & HERMES_TOTAL_ERROR_MASK); return -1.0; } }
void WeakForm<Scalar>::get_stages(Hermes::vector<const Space<Scalar> *> spaces, Hermes::vector<Solution<Scalar> *>& u_ext, Hermes::vector<Stage<Scalar> >& stages, bool want_matrix, bool want_vector, bool one_stage) const { _F_; if (!want_matrix && !want_vector) return; unsigned int i; stages.clear(); if (want_matrix || want_vector) { // This is because of linear problems where // matrix terms with the Dirichlet lift go to rhs. // Process volume matrix forms. for (i = 0; i < mfvol.size(); i++) { unsigned int ii = mfvol[i]->i, jj = mfvol[i]->j; Mesh* m1 = spaces[ii]->get_mesh(); Mesh* m2 = spaces[jj]->get_mesh(); Stage<Scalar>* s = find_stage(stages, ii, jj, m1, m2, mfvol[i]->ext, u_ext, one_stage); s->mfvol.push_back(mfvol[i]); } // Process surface matrix forms. for (i = 0; i < mfsurf.size(); i++) { unsigned int ii = mfsurf[i]->i, jj = mfsurf[i]->j; Mesh* m1 = spaces[ii]->get_mesh(); Mesh* m2 = spaces[jj]->get_mesh(); Stage<Scalar>* s = find_stage(stages, ii, jj, m1, m2, mfsurf[i]->ext, u_ext, one_stage); s->mfsurf.push_back(mfsurf[i]); } // Multi component forms. for (unsigned i = 0; i < mfvol_mc.size(); i++) { Mesh* the_one_mesh = spaces[mfvol_mc.at(i)->coordinates.at(0).first]->get_mesh(); for(unsigned int form_i = 0; form_i < mfvol_mc.at(i)->coordinates.size(); form_i++) { if(spaces[mfvol_mc.at(i)->coordinates.at(form_i).first]->get_mesh()->get_seq() != the_one_mesh->get_seq()) error("When using multi-component forms, the Meshes have to be identical."); if(spaces[mfvol_mc.at(i)->coordinates.at(form_i).second]->get_mesh()->get_seq() != the_one_mesh->get_seq()) error("When using multi-component forms, the Meshes have to be identical."); } Stage<Scalar>* s = find_stage(stages, mfvol_mc.at(i)->coordinates, the_one_mesh, the_one_mesh, mfvol_mc[i]->ext, u_ext, one_stage); s->mfvol_mc.push_back(mfvol_mc[i]); } for (unsigned i = 0; i < mfsurf_mc.size(); i++) { Mesh* the_one_mesh = spaces[mfsurf_mc.at(i)->coordinates.at(0).first]->get_mesh(); for(unsigned int form_i = 0; form_i < mfsurf_mc.at(i)->coordinates.size(); form_i++) { if(spaces[mfsurf_mc.at(i)->coordinates.at(form_i).first]->get_mesh()->get_seq() != the_one_mesh->get_seq()) error("When using multi-component forms, the Meshes have to be identical."); if(spaces[mfsurf_mc.at(i)->coordinates.at(form_i).second]->get_mesh()->get_seq() != the_one_mesh->get_seq()) error("When using multi-component forms, the Meshes have to be identical."); } Stage<Scalar>* s = find_stage(stages, mfsurf_mc.at(i)->coordinates, the_one_mesh, the_one_mesh, mfsurf_mc[i]->ext, u_ext, one_stage); s->mfsurf_mc.push_back(mfsurf_mc[i]); } } if (want_vector) { // Process volume vector forms. for (unsigned i = 0; i < vfvol.size(); i++) { unsigned int ii = vfvol[i]->i; Mesh *m = spaces[ii]->get_mesh(); Stage<Scalar>*s = find_stage(stages, ii, ii, m, m, vfvol[i]->ext, u_ext, one_stage); s->vfvol.push_back(vfvol[i]); } // Process surface vector forms. for (unsigned i = 0; i < vfsurf.size(); i++) { unsigned int ii = vfsurf[i]->i; Mesh *m = spaces[ii]->get_mesh(); Stage<Scalar>*s = find_stage(stages, ii, ii, m, m, vfsurf[i]->ext, u_ext, one_stage); s->vfsurf.push_back(vfsurf[i]); } // Multi component forms. for (unsigned i = 0; i < vfvol_mc.size(); i++) { Mesh* the_one_mesh = spaces[vfvol_mc.at(i)->coordinates.at(0)]->get_mesh(); for(unsigned int form_i = 0; form_i < vfvol_mc.at(i)->coordinates.size(); form_i++) if(spaces[vfvol_mc.at(i)->coordinates.at(form_i)]->get_mesh()->get_seq() != the_one_mesh->get_seq()) error("When using multi-component forms, the Meshes have to be identical."); Stage<Scalar>*s = find_stage(stages, vfvol_mc.at(i)->coordinates, the_one_mesh, the_one_mesh, vfvol_mc[i]->ext, u_ext, one_stage); s->vfvol_mc.push_back(vfvol_mc[i]); } for (unsigned i = 0; i < vfsurf_mc.size(); i++) { Mesh* the_one_mesh = spaces[vfsurf_mc.at(i)->coordinates.at(0)]->get_mesh(); for(unsigned int form_i = 0; form_i < vfsurf_mc.at(i)->coordinates.size(); form_i++) if(spaces[vfsurf_mc.at(i)->coordinates.at(form_i)]->get_mesh()->get_seq() != the_one_mesh->get_seq()) error("When using multi-component forms, the Meshes have to be identical."); Stage<Scalar>*s = find_stage(stages, vfsurf_mc.at(i)->coordinates, the_one_mesh, the_one_mesh, vfsurf_mc[i]->ext, u_ext, one_stage); s->vfsurf_mc.push_back(vfsurf_mc[i]); } } // Helper macro for iterating in a set, #define set_for_each(myset, type) \ for (typename std::set<type>::iterator it = (myset).begin(); it != (myset).end(); it++) // Initialize the arrays meshes and fns needed by Traverse for each stage. for (i = 0; i < stages.size(); i++) { Stage<Scalar>* s = &stages[i]; // First, initialize arrays for the test functions. A pointer to the PrecalcShapeset // corresponding to each space will be assigned to s->fns later during assembling. set_for_each(s->idx_set, int) { s->idx.push_back(*it); s->meshes.push_back(spaces[*it]->get_mesh()); s->fns.push_back(NULL); } // Next, append to the existing arrays the external functions (including the solutions // from previous Newton iteration) and their meshes. Also fill in a special array with // these external functions only. set_for_each(s->ext_set, MeshFunction<Scalar>*) { s->ext.push_back(*it); s->meshes.push_back((*it)->get_mesh()); s->fns.push_back(*it); } s->idx_set.clear(); s->seq_set.clear(); s->ext_set.clear(); } }