// ------------------------------------------------------------ // MetisPartitioner implementation void MetisPartitioner::_do_partition (MeshBase& mesh, const unsigned int n_pieces) { libmesh_assert_greater (n_pieces, 0); libmesh_assert (mesh.is_serial()); // Check for an easy return if (n_pieces == 1) { this->single_partition (mesh); return; } // What to do if the Metis library IS NOT present #ifndef LIBMESH_HAVE_METIS libmesh_here(); libMesh::err << "ERROR: The library has been built without" << std::endl << "Metis support. Using a space-filling curve" << std::endl << "partitioner instead!" << std::endl; SFCPartitioner sfcp; sfcp.partition (mesh, n_pieces); // What to do if the Metis library IS present #else START_LOG("partition()", "MetisPartitioner"); const unsigned int n_active_elem = mesh.n_active_elem(); // build the graph // std::vector<int> options(5); std::vector<int> vwgt(n_active_elem); std::vector<int> part(n_active_elem); int n = static_cast<int>(n_active_elem), // number of "nodes" (elements) // in the graph // wgtflag = 2, // weights on vertices only, // // none on edges // numflag = 0, // C-style 0-based numbering nparts = static_cast<int>(n_pieces), // number of subdomains to create edgecut = 0; // the numbers of edges cut by the // resulting partition // Set the options // options[0] = 0; // use default options // Metis will only consider the active elements. // We need to map the active element ids into a // contiguous range. Further, we want the unique range indexing to be // independednt of the element ordering, otherwise a circular dependency // can result in which the partitioning depends on the ordering which // depends on the partitioning... std::map<const Elem*, unsigned int> global_index_map; { std::vector<unsigned int> global_index; MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); MeshCommunication().find_global_indices (MeshTools::bounding_box(mesh), it, end, global_index); libmesh_assert_equal_to (global_index.size(), n_active_elem); for (unsigned int cnt=0; it != end; ++it) { const Elem *elem = *it; libmesh_assert (!global_index_map.count(elem)); global_index_map[elem] = global_index[cnt++]; } libmesh_assert_equal_to (global_index_map.size(), n_active_elem); } // build the graph in CSR format. Note that // the edges in the graph will correspond to // face neighbors std::vector<int> xadj, adjncy; { std::vector<const Elem*> neighbors_offspring; MeshBase::element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = mesh.active_elements_end(); // This will be exact when there is no refinement and all the // elements are of the same type. unsigned int graph_size=0; std::vector<std::vector<unsigned int> > graph(n_active_elem); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; libmesh_assert (global_index_map.count(elem)); const unsigned int elem_global_index = global_index_map[elem]; libmesh_assert_less (elem_global_index, vwgt.size()); libmesh_assert_less (elem_global_index, graph.size()); // maybe there is a better weight? // The weight is used to define what a balanced graph is if(!_weights) vwgt[elem_global_index] = elem->n_nodes(); else vwgt[elem_global_index] = static_cast<int>((*_weights)[elem->id()]); // Loop over the element's neighbors. An element // adjacency corresponds to a face neighbor for (unsigned int ms=0; ms<elem->n_neighbors(); ms++) { const Elem* neighbor = elem->neighbor(ms); if (neighbor != NULL) { // If the neighbor is active treat it // as a connection if (neighbor->active()) { libmesh_assert (global_index_map.count(neighbor)); const unsigned int neighbor_global_index = global_index_map[neighbor]; graph[elem_global_index].push_back(neighbor_global_index); graph_size++; } #ifdef LIBMESH_ENABLE_AMR // Otherwise we need to find all of the // neighbor's children that are connected to // us and add them else { // The side of the neighbor to which // we are connected const unsigned int ns = neighbor->which_neighbor_am_i (elem); libmesh_assert_less (ns, neighbor->n_neighbors()); // Get all the active children (& grandchildren, etc...) // of the neighbor. neighbor->active_family_tree (neighbors_offspring); // Get all the neighbor's children that // live on that side and are thus connected // to us for (unsigned int nc=0; nc<neighbors_offspring.size(); nc++) { const Elem* child = neighbors_offspring[nc]; // This does not assume a level-1 mesh. // Note that since children have sides numbered // coincident with the parent then this is a sufficient test. if (child->neighbor(ns) == elem) { libmesh_assert (child->active()); libmesh_assert (global_index_map.count(child)); const unsigned int child_global_index = global_index_map[child]; graph[elem_global_index].push_back(child_global_index); graph_size++; } } } #endif /* ifdef LIBMESH_ENABLE_AMR */ } } } // Convert the graph into the format Metis wants xadj.reserve(n_active_elem+1); adjncy.reserve(graph_size); for (unsigned int r=0; r<graph.size(); r++) { xadj.push_back(adjncy.size()); std::vector<unsigned int> graph_row; // build this emtpy graph_row.swap(graph[r]); // this will deallocate at the end of scope adjncy.insert(adjncy.end(), graph_row.begin(), graph_row.end()); } // The end of the adjacency array for the last elem xadj.push_back(adjncy.size()); libmesh_assert_equal_to (adjncy.size(), graph_size); libmesh_assert_equal_to (xadj.size(), n_active_elem+1); } // done building the graph if (adjncy.empty()) adjncy.push_back(0); int ncon = 1; // Select which type of partitioning to create // Use recursive if the number of partitions is less than or equal to 8 if (n_pieces <= 8) Metis::METIS_PartGraphRecursive(&n, &ncon, &xadj[0], &adjncy[0], &vwgt[0], NULL, NULL, &nparts, NULL, NULL, NULL, &edgecut, &part[0]); // Otherwise use kway else Metis::METIS_PartGraphKway(&n, &ncon, &xadj[0], &adjncy[0], &vwgt[0], NULL, NULL, &nparts, NULL, NULL, NULL, &edgecut, &part[0]); // Assign the returned processor ids. The part array contains // the processor id for each active element, but in terms of // the contiguous indexing we defined above { MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); for (; it!=end; ++it) { Elem* elem = *it; libmesh_assert (global_index_map.count(elem)); const unsigned int elem_global_index = global_index_map[elem]; libmesh_assert_less (elem_global_index, part.size()); const unsigned int elem_procid = static_cast<short int>(part[elem_global_index]); elem->processor_id() = elem_procid; } } STOP_LOG("partition()", "MetisPartitioner"); #endif }
void OFFIO::read_stream(std::istream& in) { // This is a serial-only process for now; // the Mesh should be read on processor 0 and // broadcast later libmesh_assert_equal_to (this->mesh().processor_id(), 0); // Get a reference to the mesh MeshBase& the_mesh = MeshInput<MeshBase>::mesh(); // Clear any existing mesh data the_mesh.clear(); // Check the input buffer libmesh_assert (in.good()); unsigned int nn, ne, nf; std::string label; // Read the first string. It should say "OFF" in >> label; libmesh_assert_equal_to (label, "OFF"); // read the number of nodes, faces, and edges in >> nn >> nf >> ne; Real x=0., y=0., z=0.; // Read the nodes for (unsigned int n=0; n<nn; n++) { libmesh_assert (in.good()); in >> x >> y >> z; the_mesh.add_point ( Point(x,y,z), n ); } unsigned int nv, nid; // Read the elements for (unsigned int e=0; e<nf; e++) { libmesh_assert (in.good()); // The number of vertices in the element in >> nv; libmesh_assert(nv == 2 || nv == 3); if (e == 0) { the_mesh.set_mesh_dimension(nv-1); if (nv == 3) { #if LIBMESH_DIM < 2 libmesh_error_msg("Cannot open dimension 2 mesh file when configured without 2D support."); #endif } } Elem* elem; switch (nv) { case 2: elem = new Edge2; break; case 3: elem = new Tri3; break; default: libmesh_error_msg("Unsupported nv = " << nv); } elem->set_id(e); the_mesh.add_elem (elem); for (unsigned int i=0; i<nv; i++) { in >> nid; elem->set_node(i) = the_mesh.node_ptr(nid); } } }
void Partitioner::partition_unpartitioned_elements (MeshBase & mesh, const unsigned int n_subdomains) { MeshBase::element_iterator it = mesh.unpartitioned_elements_begin(); const MeshBase::element_iterator end = mesh.unpartitioned_elements_end(); const dof_id_type n_unpartitioned_elements = MeshTools::n_elem (it, end); // the unpartitioned elements must exist on all processors. If the range is empty on one // it is empty on all, and we can quit right here. if (!n_unpartitioned_elements) return; // find the target subdomain sizes std::vector<dof_id_type> subdomain_bounds(mesh.n_processors()); for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { dof_id_type tgt_subdomain_size = 0; // watch out for the case that n_subdomains < n_processors if (pid < n_subdomains) { tgt_subdomain_size = n_unpartitioned_elements/n_subdomains; if (pid < n_unpartitioned_elements%n_subdomains) tgt_subdomain_size++; } //libMesh::out << "pid, #= " << pid << ", " << tgt_subdomain_size << std::endl; if (pid == 0) subdomain_bounds[0] = tgt_subdomain_size; else subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size; } libmesh_assert_equal_to (subdomain_bounds.back(), n_unpartitioned_elements); // create the unique mapping for all unpartitioned elements independent of partitioning // determine the global indexing for all the unpartitoned elements std::vector<dof_id_type> global_indices; // Calling this on all processors a unique range in [0,n_unpartitioned_elements) is constructed. // Only the indices for the elements we pass in are returned in the array. MeshCommunication().find_global_indices (mesh.comm(), MeshTools::bounding_box(mesh), it, end, global_indices); for (dof_id_type cnt=0; it != end; ++it) { Elem * elem = *it; libmesh_assert_less (cnt, global_indices.size()); const dof_id_type global_index = global_indices[cnt++]; libmesh_assert_less (global_index, subdomain_bounds.back()); libmesh_assert_less (global_index, n_unpartitioned_elements); const processor_id_type subdomain_id = cast_int<processor_id_type> (std::distance(subdomain_bounds.begin(), std::upper_bound(subdomain_bounds.begin(), subdomain_bounds.end(), global_index))); libmesh_assert_less (subdomain_id, n_subdomains); elem->processor_id() = subdomain_id; //libMesh::out << "assigning " << global_index << " to " << subdomain_id << std::endl; } }
// The main program int main(int argc, char** argv) { //for record-keeping std::cout << "Running: " << argv[0]; for (int i=1; i<argc; i++) std::cout << " " << argv[i]; std::cout << std::endl << std::endl; clock_t begin = std::clock(); // Initialize libMesh LibMeshInit init(argc, argv); // Parameters GetPot solverInfile("fem_system_params.in"); const bool transient = solverInfile("transient", false); unsigned int n_timesteps = solverInfile("n_timesteps", 1); const int nx = solverInfile("nx",100); const int ny = solverInfile("ny",100); const int nz = solverInfile("nz",100); GetPot infile("contamTrans.in"); //std::string find_mesh_here = infile("initial_mesh","mesh.exo"); bool doContinuation = infile("do_continuation",false); bool splitSuperAdj = infile("split_super_adjoint",true); //solve as single adjoint or two forwards int maxIter = infile("max_model_refinements",0); //maximum number of model refinements double refStep = infile("refinement_step",0.1); //additional proportion of domain refined per step //this refers to additional basis functions...number of elements will be more... double qoiErrorTol = infile("relative_error_tolerance",0.01); //stopping criterion //bool doDivvyMatlab = infile("do_divvy_in_Matlab",false); //output files to determine next refinement in Matlab bool avoid_sides = infile("avoid_sides",false); //DEBUG, whether to avoid sides while refining if(refStep*maxIter > 1) maxIter = round(ceil(1./refStep)); Mesh mesh(init.comm()); Mesh mesh2(init.comm()); //create mesh unsigned int dim; if(nz == 0){ //to check if oscillations happen in 2D as well... dim = 2; MeshTools::Generation::build_square(mesh, nx, ny, 0., 2300., 0., 1650., QUAD9); MeshTools::Generation::build_square(mesh2, nx, ny, 0., 2300., 0., 1650., QUAD9); }else{ dim = 3; MeshTools::Generation::build_cube(mesh, nx, ny, nz, 0., 2300., 0., 1650., 0., 100., HEX27); MeshTools::Generation::build_cube(mesh2, nx, ny, nz, 0., 2300., 0., 1650., 0., 100., HEX27); } mesh.print_info(); //DEBUG // Create an equation systems object. EquationSystems equation_systems (mesh); EquationSystems equation_systems_mix(mesh2); //name system ConvDiff_PrimarySys & system_primary = equation_systems.add_system<ConvDiff_PrimarySys>("ConvDiff_PrimarySys"); //for primary variables ConvDiff_AuxSys & system_aux = equation_systems.add_system<ConvDiff_AuxSys>("ConvDiff_AuxSys"); //for auxiliary variables ConvDiff_MprimeSys & system_mix = equation_systems_mix.add_system<ConvDiff_MprimeSys>("Diff_ConvDiff_MprimeSys"); //for superadj ConvDiff_PrimarySadjSys & system_sadj_primary = equation_systems.add_system<ConvDiff_PrimarySadjSys>("ConvDiff_PrimarySadjSys"); //for split superadj ConvDiff_AuxSadjSys & system_sadj_aux = equation_systems.add_system<ConvDiff_AuxSadjSys>("ConvDiff_AuxSadjSys"); //for split superadj //steady-state problem system_primary.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system_primary)); system_aux.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system_aux)); system_mix.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system_mix)); system_sadj_primary.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system_sadj_primary)); system_sadj_aux.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system_sadj_aux)); libmesh_assert_equal_to (n_timesteps, 1); // Initialize the system equation_systems.init (); equation_systems_mix.init(); //initial guess for primary state read_initial_parameters(); system_primary.project_solution(initial_value, initial_grad, equation_systems.parameters); finish_initialization(); //nonlinear solver options NewtonSolver *solver_sadj_primary = new NewtonSolver(system_sadj_primary); system_sadj_primary.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_sadj_primary); solver_sadj_primary->quiet = solverInfile("solver_quiet", true); solver_sadj_primary->verbose = !solver_sadj_primary->quiet; solver_sadj_primary->max_nonlinear_iterations = solverInfile("max_nonlinear_iterations", 15); solver_sadj_primary->relative_step_tolerance = solverInfile("relative_step_tolerance", 1.e-3); solver_sadj_primary->relative_residual_tolerance = solverInfile("relative_residual_tolerance", 0.0); solver_sadj_primary->absolute_residual_tolerance = solverInfile("absolute_residual_tolerance", 0.0); NewtonSolver *solver_sadj_aux = new NewtonSolver(system_sadj_aux); system_sadj_aux.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_sadj_aux); solver_sadj_aux->quiet = solverInfile("solver_quiet", true); solver_sadj_aux->verbose = !solver_sadj_aux->quiet; solver_sadj_aux->max_nonlinear_iterations = solverInfile("max_nonlinear_iterations", 15); solver_sadj_aux->relative_step_tolerance = solverInfile("relative_step_tolerance", 1.e-3); solver_sadj_aux->relative_residual_tolerance = solverInfile("relative_residual_tolerance", 0.0); solver_sadj_aux->absolute_residual_tolerance = solverInfile("absolute_residual_tolerance", 0.0); NewtonSolver *solver_primary = new NewtonSolver(system_primary); system_primary.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_primary); solver_primary->quiet = solverInfile("solver_quiet", true); solver_primary->verbose = !solver_primary->quiet; solver_primary->max_nonlinear_iterations = solverInfile("max_nonlinear_iterations", 15); solver_primary->relative_step_tolerance = solverInfile("relative_step_tolerance", 1.e-3); solver_primary->relative_residual_tolerance = solverInfile("relative_residual_tolerance", 0.0); solver_primary->absolute_residual_tolerance = solverInfile("absolute_residual_tolerance", 0.0); NewtonSolver *solver_aux = new NewtonSolver(system_aux); system_aux.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_aux); solver_aux->quiet = solverInfile("solver_quiet", true); solver_aux->verbose = !solver_aux->quiet; solver_aux->max_nonlinear_iterations = solverInfile("max_nonlinear_iterations", 15); solver_aux->relative_step_tolerance = solverInfile("relative_step_tolerance", 1.e-3); solver_aux->relative_residual_tolerance = solverInfile("relative_residual_tolerance", 0.0); solver_aux->absolute_residual_tolerance = solverInfile("absolute_residual_tolerance", 0.0); solver_primary->require_residual_reduction = solverInfile("require_residual_reduction",true); solver_sadj_primary->require_residual_reduction = solverInfile("require_residual_reduction",true); solver_aux->require_residual_reduction = solverInfile("require_residual_reduction",true); solver_sadj_aux->require_residual_reduction = solverInfile("require_residual_reduction",true); //linear solver options solver_primary->max_linear_iterations = solverInfile("max_linear_iterations",10000); solver_primary->initial_linear_tolerance = solverInfile("initial_linear_tolerance",1.e-13); solver_primary->minimum_linear_tolerance = solverInfile("minimum_linear_tolerance",1.e-13); solver_primary->linear_tolerance_multiplier = solverInfile("linear_tolerance_multiplier",1.e-3); solver_aux->max_linear_iterations = solverInfile("max_linear_iterations",10000); solver_aux->initial_linear_tolerance = solverInfile("initial_linear_tolerance",1.e-13); solver_aux->minimum_linear_tolerance = solverInfile("minimum_linear_tolerance",1.e-13); solver_aux->linear_tolerance_multiplier = solverInfile("linear_tolerance_multiplier",1.e-3); solver_sadj_primary->max_linear_iterations = solverInfile("max_linear_iterations",10000); solver_sadj_primary->initial_linear_tolerance = solverInfile("initial_linear_tolerance",1.e-13); solver_sadj_primary->minimum_linear_tolerance = solverInfile("minimum_linear_tolerance",1.e-13); solver_sadj_primary->linear_tolerance_multiplier = solverInfile("linear_tolerance_multiplier",1.e-3); solver_sadj_aux->max_linear_iterations = solverInfile("max_linear_iterations",10000); solver_sadj_aux->initial_linear_tolerance = solverInfile("initial_linear_tolerance",1.e-13); solver_sadj_aux->minimum_linear_tolerance = solverInfile("minimum_linear_tolerance",1.e-13); solver_sadj_aux->linear_tolerance_multiplier = solverInfile("linear_tolerance_multiplier",1.e-3); /*if(doDivvyMatlab){ //DOF maps and such to help visualize std::ofstream output_global_dof("global_dof_map.dat"); for(unsigned int i = 0 ; i < system_mix.get_mesh().n_elem(); i++){ std::vector< dof_id_type > di; system_mix.get_dof_map().dof_indices(system_mix.get_mesh().elem(i), di); if(output_global_dof.is_open()){ output_global_dof << i << " "; for(unsigned int j = 0; j < di.size(); j++) output_global_dof << di[j] << " "; output_global_dof << "\n"; } } output_global_dof.close(); std::ofstream output_elem_cent("elem_centroids.dat"); for(unsigned int i = 0 ; i < system_mix.get_mesh().n_elem(); i++){ Point elem_cent = system_mix.get_mesh().elem(i)->centroid(); if(output_elem_cent.is_open()){ output_elem_cent << elem_cent(0) << " " << elem_cent(1) << "\n"; } } output_elem_cent.close(); }*/ //inverse dof map (elements in support of each node, assuming every 6 dofs belong to same node) std::vector<std::set<dof_id_type> > node_to_elem; node_to_elem.resize(round(system_mix.n_dofs()/6.)); for(unsigned int i = 0 ; i < system_mix.get_mesh().n_elem(); i++){ std::vector< dof_id_type > di; system_mix.get_dof_map().dof_indices(system_mix.get_mesh().elem(i), di); for(unsigned int j = 0; j < di.size(); j++) node_to_elem[round(floor(di[j]/6.))].insert(i); } int refIter = 0; double relError = 2.*qoiErrorTol; while(refIter <= maxIter && relError > qoiErrorTol){ if(!doContinuation){ //clear out previous solutions system_primary.solution->zero(); system_aux.solution->zero(); system_sadj_primary.solution->zero(); system_sadj_aux.solution->zero(); } system_mix.solution->zero(); clock_t begin_inv = std::clock(); system_primary.solve(); system_primary.clearQoI(); clock_t end_inv = std::clock(); clock_t begin_err_est = std::clock(); std::cout << "\n End primary solve, begin auxiliary solve..." << std::endl; system_aux.solve(); std::cout << "\n End auxiliary solve..." << std::endl; clock_t end_aux = std::clock(); system_primary.postprocess(); system_aux.postprocess(); system_sadj_primary.set_c_vals(system_primary.get_c_vals()); system_sadj_aux.set_auxc_vals(system_aux.get_auxc_vals()); equation_systems_mix.reinit(); //combine primary and auxiliary variables into psi DirectSolutionTransfer sol_transfer(init.comm()); sol_transfer.transfer(system_aux.variable(system_aux.variable_number("aux_c")), system_mix.variable(system_mix.variable_number("aux_c"))); sol_transfer.transfer(system_aux.variable(system_aux.variable_number("aux_zc")), system_mix.variable(system_mix.variable_number("aux_zc"))); sol_transfer.transfer(system_aux.variable(system_aux.variable_number("aux_fc")), system_mix.variable(system_mix.variable_number("aux_fc"))); AutoPtr<NumericVector<Number> > just_aux = system_mix.solution->clone(); sol_transfer.transfer(system_primary.variable(system_primary.variable_number("c")), system_mix.variable(system_mix.variable_number("c"))); sol_transfer.transfer(system_primary.variable(system_primary.variable_number("zc")), system_mix.variable(system_mix.variable_number("zc"))); sol_transfer.transfer(system_primary.variable(system_primary.variable_number("fc")), system_mix.variable(system_mix.variable_number("fc"))); if(!splitSuperAdj){ //solve super-adjoint as single adjoint system_mix.assemble_qoi_sides = true; //QoI doesn't involve sides std::cout << "\n~*~*~*~*~*~*~*~*~ adjoint solve start ~*~*~*~*~*~*~*~*~\n" << std::endl; std::pair<unsigned int, Real> adjsolve = system_mix.adjoint_solve(); std::cout << "number of iterations to solve adjoint: " << adjsolve.first << std::endl; std::cout << "final residual of adjoint solve: " << adjsolve.second << std::endl; std::cout << "\n~*~*~*~*~*~*~*~*~ adjoint solve end ~*~*~*~*~*~*~*~*~" << std::endl; NumericVector<Number> &dual_sol = system_mix.get_adjoint_solution(0); //DEBUG system_mix.assemble(); //calculate residual to correspond to solution //std::cout << "\n sadj norm: " << system_mix.calculate_norm(dual_sol, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 0, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 1, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 2, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 3, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 4, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 5, L2) << std::endl; //DEBUG }else{ //solve super-adjoint as system_mix.assemble(); //calculate residual to correspond to solution std::cout << "\n Begin primary super-adjoint solve...\n" << std::endl; system_sadj_primary.solve(); std::cout << "\n End primary super-adjoint solve, begin auxiliary super-adjoint solve...\n" << std::endl; system_sadj_aux.solve(); std::cout << "\n End auxiliary super-adjoint solve...\n" << std::endl; const std::string & adjoint_solution0_name = "adjoint_solution0"; system_mix.add_vector(adjoint_solution0_name, false, GHOSTED); system_mix.set_vector_as_adjoint(adjoint_solution0_name,0); NumericVector<Number> &eep = system_mix.add_adjoint_rhs(0); system_mix.set_adjoint_already_solved(true); NumericVector<Number> &dual_sol = system_mix.get_adjoint_solution(0); NumericVector<Number> &primal_sol = *system_mix.solution; dual_sol.swap(primal_sol); sol_transfer.transfer(system_sadj_aux.variable(system_sadj_aux.variable_number("sadj_aux_c")), system_mix.variable(system_mix.variable_number("aux_c"))); sol_transfer.transfer(system_sadj_aux.variable(system_sadj_aux.variable_number("sadj_aux_zc")), system_mix.variable(system_mix.variable_number("aux_zc"))); sol_transfer.transfer(system_sadj_aux.variable(system_sadj_aux.variable_number("sadj_aux_fc")), system_mix.variable(system_mix.variable_number("aux_fc"))); sol_transfer.transfer(system_sadj_primary.variable(system_sadj_primary.variable_number("sadj_c")), system_mix.variable(system_mix.variable_number("c"))); sol_transfer.transfer(system_sadj_primary.variable(system_sadj_primary.variable_number("sadj_zc")), system_mix.variable(system_mix.variable_number("zc"))); sol_transfer.transfer(system_sadj_primary.variable(system_sadj_primary.variable_number("sadj_fc")), system_mix.variable(system_mix.variable_number("fc"))); //std::cout << "\n sadj norm: " << system_mix.calculate_norm(primal_sol, L2) << std::endl; //DEBUG dual_sol.swap(primal_sol); //std::cout << "\n sadj norm: " << system_mix.calculate_norm(primal_sol, L2) << std::endl; //DEBUG //std::cout << system_sadj_primary.calculate_norm(*system_sadj_primary.solution, 0, L2) << std::endl; //DEBUG //std::cout << system_sadj_primary.calculate_norm(*system_sadj_primary.solution, 1, L2) << std::endl; //DEBUG //std::cout << system_sadj_primary.calculate_norm(*system_sadj_primary.solution, 2, L2) << std::endl; //DEBUG //std::cout << system_sadj_aux.calculate_norm(*system_sadj_aux.solution, 0, L2) << std::endl; //DEBUG //std::cout << system_sadj_aux.calculate_norm(*system_sadj_aux.solution, 1, L2) << std::endl; //DEBUG //std::cout << system_sadj_aux.calculate_norm(*system_sadj_aux.solution, 2, L2) << std::endl; //DEBUG } NumericVector<Number> &dual_solution = system_mix.get_adjoint_solution(0); /* NumericVector<Number> &primal_solution = *system_mix.solution; //DEBUG primal_solution.swap(dual_solution); //DEBUG ExodusII_IO(mesh).write_timestep("super_adjoint.exo", equation_systems, 1, / his number indicates how many time steps are being written to the file system_mix.time); //DEBUG primal_solution.swap(dual_solution); //DEBUG */ //adjoint-weighted residual AutoPtr<NumericVector<Number> > adjresid = system_mix.solution->zero_clone(); adjresid->pointwise_mult(*system_mix.rhs,dual_solution); adjresid->scale(-0.5); std::cout << "\n -0.5*M'_HF(psiLF)(superadj): " << adjresid->sum() << std::endl; //DEBUG //LprimeHF(psiLF) AutoPtr<NumericVector<Number> > LprimeHF_psiLF = system_mix.solution->zero_clone(); LprimeHF_psiLF->pointwise_mult(*system_mix.rhs,*just_aux); std::cout << " L'_HF(psiLF): " << LprimeHF_psiLF->sum() << std::endl; //DEBUG //QoI and error estimate std::cout << "QoI: " << std::setprecision(17) << system_primary.getQoI() << std::endl; std::cout << "QoI Error estimate: " << std::setprecision(17) << adjresid->sum()+LprimeHF_psiLF->sum() << std::endl; relError = fabs((adjresid->sum()+LprimeHF_psiLF->sum())/system_primary.getQoI()); //print out information std::cout << "Estimated absolute relative qoi error: " << relError << std::endl << std::endl; std::cout << "Estimated HF QoI: " << std::setprecision(17) << system_primary.getQoI()+adjresid->sum()+LprimeHF_psiLF->sum() << std::endl; clock_t end = clock(); std::cout << "Time so far: " << double(end-begin)/CLOCKS_PER_SEC << " seconds..." << std::endl; std::cout << "Time for inverse problem: " << double(end_inv-begin_inv)/CLOCKS_PER_SEC << " seconds..." << std::endl; std::cout << "Time for extra error estimate bits: " << double(end-begin_err_est)/CLOCKS_PER_SEC << " seconds..." << std::endl; std::cout << " Time to get auxiliary problems: " << double(end_aux-begin_err_est)/CLOCKS_PER_SEC << " seconds..." << std::endl; std::cout << " Time to get superadjoint: " << double(end-end_aux)/CLOCKS_PER_SEC << " seconds...\n" << std::endl; //proportion of domain refined at this iteration MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); double numMarked = 0.; for (; elem_it != elem_end; ++elem_it){ Elem* elem = *elem_it; numMarked += elem->subdomain_id(); } std::cout << "Refinement fraction: " << numMarked/system_mix.get_mesh().n_elem() << std::endl << std::endl; //output at each iteration std::stringstream ss; ss << refIter; std::string str = ss.str(); std::string write_error_basis_blame = (infile("error_est_output_file_basis_blame", "error_est_breakdown_basis_blame")) + str + ".dat"; std::ofstream output2(write_error_basis_blame); for(unsigned int i = 0 ; i < adjresid->size(); i++){ if(output2.is_open()) output2 << (*adjresid)(i) + (*LprimeHF_psiLF)(i) << "\n"; } output2.close(); if(refIter < maxIter && relError > qoiErrorTol){ //if further refinement needed //collapse error contributions into nodes std::vector<std::pair<Number,dof_id_type> > node_errs(round(system_mix.n_dofs()/6.)); for(unsigned int node_num = 0; node_num < node_errs.size(); node_num++){ node_errs[node_num] = std::pair<Number,dof_id_type> (fabs((*adjresid)(6*node_num) + (*LprimeHF_psiLF)(6*node_num) + (*adjresid)(6*node_num+1) + (*LprimeHF_psiLF)(6*node_num+1) + (*adjresid)(6*node_num+2) + (*LprimeHF_psiLF)(6*node_num+2) + (*adjresid)(6*node_num+3) + (*LprimeHF_psiLF)(6*node_num+3) + (*adjresid)(6*node_num+4) + (*LprimeHF_psiLF)(6*node_num+4) + (*adjresid)(6*node_num+5) + (*LprimeHF_psiLF)(6*node_num+5)), node_num); } //find nodes contributing the most //double refPcnt = std::min((refIter+1)*refStep,1.); double refPcnt = std::min(refStep,1.); //additional refinement (compared to previous iteration) int cutoffLoc = round(node_errs.size()*refPcnt); std::sort(node_errs.begin(), node_errs.end()); std::reverse(node_errs.begin(), node_errs.end()); //find elements in support of worst offenders std::vector<dof_id_type> markMe; markMe.reserve(cutoffLoc*8); for(int i = 0; i < cutoffLoc; i++){ markMe.insert(markMe.end(), node_to_elem[node_errs[i].second].begin(), node_to_elem[node_errs[i].second].end()); } //mark those elements for refinement. for(int i = 0; i < markMe.size(); i++){ if(!avoid_sides || (avoid_sides && !mesh.elem(markMe[i])->on_boundary())) mesh.elem(markMe[i])->subdomain_id() = 1; //assuming HF regions marked with 1 } //to test whether assignment matches matlab's /*std::string stash_assign = "divvy_c_poke.txt"; std::ofstream output_dbg(stash_assign.c_str()); MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); for (; elem_it != elem_end; ++elem_it){ Elem* elem = *elem_it; if(output_dbg.is_open()){ output_dbg << elem->id() << " " << elem->subdomain_id() << "\n"; } } output_dbg.close();*/ #ifdef LIBMESH_HAVE_EXODUS_API std::stringstream ss2; ss2 << refIter + 1; std::string str = ss2.str(); std::string write_divvy = "divvy" + str + ".exo"; ExodusII_IO (mesh).write_equation_systems(write_divvy,equation_systems); //DEBUG #endif // #ifdef LIBMESH_HAVE_EXODUS_API } refIter += 1; } std::string stash_assign = "divvy_final.txt"; std::ofstream output_dbg(stash_assign.c_str()); MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); double numMarked = 0.; for (; elem_it != elem_end; ++elem_it){ Elem* elem = *elem_it; numMarked += elem->subdomain_id(); if(output_dbg.is_open()){ output_dbg << elem->id() << " " << elem->subdomain_id() << "\n"; } } output_dbg.close(); std::cout << "\nRefinement concluded..." << std::endl; std::cout << "Final refinement fraction: " << numMarked/system_mix.get_mesh().n_elem() << std::endl; std::cout << "Final estimated relative error: " << relError << std::endl; return 0; //done } //end main
Real FE<1,LAGRANGE>::shape_second_deriv(const ElemType, const Order order, const unsigned int i, const unsigned int libmesh_dbg_var(j), const Point & p) { // Don't need to switch on j. 1D shape functions // depend on xi only! const Real xi = p(0); libmesh_assert_equal_to (j, 0); switch (order) { // linear Lagrange shape functions case FIRST: { // All second derivatives of linears are zero.... return 0.; } // quadratic Lagrange shape functions case SECOND: { switch (i) { case 0: return 1.; case 1: return 1.; case 2: return -2.; default: libmesh_error_msg("Invalid shape function index i = " << i); } } // end case SECOND case THIRD: { switch (i) { case 0: return -9./16.*(6.*xi-2); case 1: return -9./16.*(-6*xi-2.); case 2: return 27./16.*(6*xi-2./3.); case 3: return 27./16.*(-6*xi-2./3.); default: libmesh_error_msg("Invalid shape function index i = " << i); } } // end case THIRD default: libmesh_error_msg("ERROR: Unsupported polynomial order = " << order); } // end switch (order) libmesh_error_msg("We'll never get here!"); return 0.; }
int main(int argc, char** argv){ //initialize libMesh LibMeshInit init(argc, argv); //parameters GetPot infile("fem_system_params.in"); const bool transient = infile("transient", true); const Real deltat = infile("deltat", 0.005); unsigned int n_timesteps = infile("n_timesteps", 20); const int nx = infile("nx",100); const int ny = infile("ny",100); const int nz = infile("nz",100); //const unsigned int dim = 3; const unsigned int max_r_steps = infile("max_r_steps", 3); const unsigned int max_r_level = infile("max_r_level", 3); const Real refine_percentage = infile("refine_percentage", 0.1); const Real coarsen_percentage = infile("coarsen_percentage", 0.0); const std::string indicator_type = infile("indicator_type", "kelly"); const bool write_error = infile("write_error",false); const bool flag_by_elem_frac = infile("flag_by_elem_frac",true); const bool printJ = infile("print_jac",false); //DEBUG #ifdef LIBMESH_HAVE_EXODUS_API const unsigned int write_interval = infile("write_interval", 5); #endif // Create a mesh, with dimension to be overridden later, distributed // across the default MPI communicator. Mesh mesh(init.comm()); //create mesh unsigned int dim; if(nz == 0){ //to check if oscillations happen in 2D as well... dim = 2; MeshTools::Generation::build_square(mesh, nx, ny, 497150.0, 501750.0, 537350.0, 540650.0, QUAD9); }else{ dim = 3; MeshTools::Generation::build_cube(mesh, nx, ny, nz, 497150.0, 501750.0, 537350.0, 540650.0, 0.0, 100.0, HEX27); //MeshTools::Generation::build_cube (mesh, // 15, 3, 3, // -0.0, 5.0, // -0.0, 1.0, // -0.0, 1.0, // HEX27); //DEBUG } // Print information about the mesh to the screen. mesh.print_info(); // Create an equation systems object. EquationSystems equation_systems (mesh); //name system ContamTransSysInv & system = equation_systems.add_system<ContamTransSysInv>("ContamTransInv"); //solve as steady or transient if(transient){ //system.time_solver = AutoPtr<TimeSolver>(new EulerSolver(system)); //backward Euler system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system)); std::cout << "\n\nAaahhh transience not yet available!\n" << std::endl; n_timesteps = 1; } else{ system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system)); libmesh_assert_equal_to (n_timesteps, 1); //this doesn't seem to work? } // Initialize the system equation_systems.init (); //initial conditions read_initial_parameters(); system.project_solution(initial_value, initial_grad, equation_systems.parameters); finish_initialization(); // Set the time stepping options... system.deltat = deltat; //...and the nonlinear solver options... NewtonSolver *solver = new NewtonSolver(system); system.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver); solver->quiet = infile("solver_quiet", true); solver->verbose = !solver->quiet; solver->max_nonlinear_iterations = infile("max_nonlinear_iterations", 15); solver->relative_step_tolerance = infile("relative_step_tolerance", 1.e-3); solver->relative_residual_tolerance = infile("relative_residual_tolerance", 0.0); solver->absolute_residual_tolerance = infile("absolute_residual_tolerance", 0.0); // And the linear solver options solver->max_linear_iterations = infile("max_linear_iterations", 10000); solver->initial_linear_tolerance = infile("initial_linear_tolerance",1.e-13); solver->minimum_linear_tolerance = infile("minimum_linear_tolerance",1.e-13); solver->linear_tolerance_multiplier = infile("linear_tolerance_multiplier",1.e-3); // Mesh Refinement object - to test effect of constant refined mesh (not refined at every timestep) MeshRefinement mesh_refinement(mesh); mesh_refinement.refine_fraction() = refine_percentage; mesh_refinement.coarsen_fraction() = coarsen_percentage; mesh_refinement.max_h_level() = max_r_level; #ifdef LIBMESH_HAVE_GMV GMVIO(equation_systems.get_mesh()).write_equation_systems(std::string("invLF.gmv"), equation_systems); //DEBUG #endif // Print information about the system to the screen. equation_systems.print_info(); ExodusII_IO exodusIO = ExodusII_IO(mesh); //for writing multiple timesteps to one file for (unsigned int r_step=0; r_step<max_r_steps; r_step++) { std::cout << "\nBeginning Solve " << r_step+1 << std::endl; for (unsigned int t_step=0; t_step != n_timesteps; ++t_step) { std::cout << "\n\nSolving time step " << t_step << ", time = " << system.time << std::endl; system.solve(); system.postprocess(); // Advance to the next timestep in a transient problem system.time_solver->advance_timestep(); } //end stepping through time loop std::cout << "\n Refining the mesh..." << std::endl; // The \p ErrorVector is a particular \p StatisticsVector // for computing error information on a finite element mesh. ErrorVector error; if (indicator_type == "patch") { // The patch recovery estimator should give a // good estimate of the solution interpolation // error. PatchRecoveryErrorEstimator error_estimator; error_estimator.set_patch_reuse(false); //anisotropy trips up reuse error_estimator.estimate_error (system, error); } else if (indicator_type == "kelly") { // The Kelly error estimator is based on // an error bound for the Poisson problem // on linear elements, but is useful for // driving adaptive refinement in many problems KellyErrorEstimator error_estimator; error_estimator.estimate_error (system, error); } // Write out the error distribution if(write_error){ std::ostringstream ss; ss << r_step; #ifdef LIBMESH_HAVE_EXODUS_API std::string error_output = "error_"+ss.str()+".e"; #else std::string error_output = "error_"+ss.str()+".gmv"; #endif error.plot_error( error_output, mesh ); } // This takes the error in \p error and decides which elements // will be coarsened or refined. if(flag_by_elem_frac) mesh_refinement.flag_elements_by_elem_fraction(error); else mesh_refinement.flag_elements_by_error_fraction (error); // This call actually refines and coarsens the flagged // elements. mesh_refinement.refine_and_coarsen_elements(); // This call reinitializes the \p EquationSystems object for // the newly refined mesh. One of the steps in the // reinitialization is projecting the \p solution, // \p old_solution, etc... vectors from the old mesh to // the current one. equation_systems.reinit (); std::cout << "System has: " << equation_systems.n_active_dofs() << " degrees of freedom." << std::endl; } //end refinement loop //use that final refinement for (unsigned int t_step=0; t_step != n_timesteps; ++t_step) { std::cout << "\n\nSolving time step " << t_step << ", time = " << system.time << std::endl; system.solve(); system.postprocess(); //DEBUG if(printJ){ //aahhh this doesn't print if solve not successful... std::ostringstream Jfile_name; Jfile_name << "J.dat"; std::ofstream outputJ(Jfile_name.str()); system.matrix->print(outputJ); outputJ.close(); } Number QoI_computed = system.get_QoI_value("computed", 0); std::cout<< "Computed QoI is " << std::setprecision(17) << QoI_computed << std::endl; // Advance to the next timestep in a transient problem system.time_solver->advance_timestep(); } //end stepping through time loop #ifdef LIBMESH_HAVE_EXODUS_API for (unsigned int t_step=0; t_step != n_timesteps; ++t_step) { // Write out this timestep if we're requested to if ((t_step+1)%write_interval == 0) { std::ostringstream ex_file_name; std::ostringstream tplot_file_name; // We write the file in the ExodusII format. //ex_file_name << "out_" // << std::setw(3) // << std::setfill('0') // << std::right // << t_step+1 // << ".e"; tplot_file_name << "out_" << std::setw(3) << std::setfill('0') << std::right << t_step+1 << ".plt"; //ExodusII_IO(mesh).write_timestep(ex_file_name.str(), // equation_systems, // 1, /* This number indicates how many time steps // are being written to the file */ // system.time); exodusIO.write_timestep("output.exo", equation_systems, t_step+1, system.time); //outputs all timesteps in one file TecplotIO(mesh).write_equation_systems(tplot_file_name.str(), equation_systems); } } #endif // #ifdef LIBMESH_HAVE_EXODUS_API // All done. return 0; } //end main
void ParmetisPartitioner::build_graph (const MeshBase& mesh) { // build the graph in distributed CSR format. Note that // the edges in the graph will correspond to // face neighbors const dof_id_type n_active_local_elem = mesh.n_active_local_elem(); // If we have boundary elements in this mesh, we want to account for // the connectivity between them and interior elements. We can find // interior elements from boundary elements, but we need to build up // a lookup map to do the reverse. typedef LIBMESH_BEST_UNORDERED_MAP<const Elem *, const Elem *> map_type; map_type interior_to_boundary_map; { MeshBase::const_element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; // If we don't have an interior_parent then there's nothing to look us // up. if ((elem->dim() >= LIBMESH_DIM) || !elem->interior_parent()) continue; // get all relevant interior elements std::set<const Elem*> neighbor_set; elem->find_interior_neighbors(neighbor_set); std::set<const Elem*>::iterator n_it = neighbor_set.begin(); for (; n_it != neighbor_set.end(); ++n_it) { // FIXME - non-const versions of the Elem set methods // would be nice Elem* neighbor = const_cast<Elem*>(*n_it); #if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP) interior_to_boundary_map.insert (std::make_pair(neighbor, elem)); #else interior_to_boundary_map.insert (interior_to_boundary_map.begin(), std::make_pair(neighbor, elem)); #endif } } } #ifdef LIBMESH_ENABLE_AMR std::vector<const Elem*> neighbors_offspring; #endif std::vector<std::vector<dof_id_type> > graph(n_active_local_elem); dof_id_type graph_size=0; const dof_id_type first_local_elem = _pmetis->vtxdist[mesh.processor_id()]; MeshBase::const_element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; libmesh_assert (_global_index_by_pid_map.count(elem->id())); const dof_id_type global_index_by_pid = _global_index_by_pid_map[elem->id()]; const dof_id_type local_index = global_index_by_pid - first_local_elem; libmesh_assert_less (local_index, n_active_local_elem); std::vector<dof_id_type> &graph_row = graph[local_index]; // Loop over the element's neighbors. An element // adjacency corresponds to a face neighbor for (unsigned int ms=0; ms<elem->n_neighbors(); ms++) { const Elem* neighbor = elem->neighbor(ms); if (neighbor != NULL) { // If the neighbor is active treat it // as a connection if (neighbor->active()) { libmesh_assert(_global_index_by_pid_map.count(neighbor->id())); const dof_id_type neighbor_global_index_by_pid = _global_index_by_pid_map[neighbor->id()]; graph_row.push_back(neighbor_global_index_by_pid); graph_size++; } #ifdef LIBMESH_ENABLE_AMR // Otherwise we need to find all of the // neighbor's children that are connected to // us and add them else { // The side of the neighbor to which // we are connected const unsigned int ns = neighbor->which_neighbor_am_i (elem); libmesh_assert_less (ns, neighbor->n_neighbors()); // Get all the active children (& grandchildren, etc...) // of the neighbor // FIXME - this is the wrong thing, since we // should be getting the active family tree on // our side only. But adding too many graph // links may cause hanging nodes to tend to be // on partition interiors, which would reduce // communication overhead for constraint // equations, so we'll leave it. neighbor->active_family_tree (neighbors_offspring); // Get all the neighbor's children that // live on that side and are thus connected // to us for (unsigned int nc=0; nc<neighbors_offspring.size(); nc++) { const Elem* child = neighbors_offspring[nc]; // This does not assume a level-1 mesh. // Note that since children have sides numbered // coincident with the parent then this is a sufficient test. if (child->neighbor(ns) == elem) { libmesh_assert (child->active()); libmesh_assert (_global_index_by_pid_map.count(child->id())); const dof_id_type child_global_index_by_pid = _global_index_by_pid_map[child->id()]; graph_row.push_back(child_global_index_by_pid); graph_size++; } } } #endif /* ifdef LIBMESH_ENABLE_AMR */ } } if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent()) { // get all relevant interior elements std::set<const Elem*> neighbor_set; elem->find_interior_neighbors(neighbor_set); std::set<const Elem*>::iterator n_it = neighbor_set.begin(); for (; n_it != neighbor_set.end(); ++n_it) { // FIXME - non-const versions of the Elem set methods // would be nice Elem* neighbor = const_cast<Elem*>(*n_it); const dof_id_type neighbor_global_index_by_pid = _global_index_by_pid_map[neighbor->id()]; graph_row.push_back(neighbor_global_index_by_pid); graph_size++; } } // Check for any boundary neighbors typedef map_type::iterator map_it_type; std::pair<map_it_type, map_it_type> bounds = interior_to_boundary_map.equal_range(elem); for (map_it_type it = bounds.first; it != bounds.second; ++it) { const Elem* neighbor = it->second; const dof_id_type neighbor_global_index_by_pid = _global_index_by_pid_map[neighbor->id()]; graph_row.push_back(neighbor_global_index_by_pid); graph_size++; } } // Reserve space in the adjacency array _pmetis->xadj.clear(); _pmetis->xadj.reserve (n_active_local_elem + 1); _pmetis->adjncy.clear(); _pmetis->adjncy.reserve (graph_size); for (std::size_t r=0; r<graph.size(); r++) { _pmetis->xadj.push_back(_pmetis->adjncy.size()); std::vector<dof_id_type> graph_row; // build this emtpy graph_row.swap(graph[r]); // this will deallocate at the end of scope _pmetis->adjncy.insert(_pmetis->adjncy.end(), graph_row.begin(), graph_row.end()); } // The end of the adjacency array for the last elem _pmetis->xadj.push_back(_pmetis->adjncy.size()); libmesh_assert_equal_to (_pmetis->xadj.size(), n_active_local_elem+1); libmesh_assert_equal_to (_pmetis->adjncy.size(), graph_size); }
void LaspackMatrix<T>::update_sparsity_pattern (const SparsityPattern::Graph & sparsity_pattern) { // clear data, start over this->clear (); // big trouble if this fails! libmesh_assert(this->_dof_map); const numeric_index_type n_rows = sparsity_pattern.size(); // Initialize the _row_start data structure, // allocate storage for the _csr array { std::size_t size = 0; for (numeric_index_type row=0; row<n_rows; row++) size += sparsity_pattern[row].size(); _csr.resize (size); _row_start.reserve(n_rows + 1); } // Initize the _csr data structure. { std::vector<numeric_index_type>::iterator position = _csr.begin(); _row_start.push_back (position); for (numeric_index_type row=0; row<n_rows; row++) { // insert the row indices for (SparsityPattern::Row::const_iterator col = sparsity_pattern[row].begin(); col != sparsity_pattern[row].end(); ++col) { libmesh_assert (position != _csr.end()); *position = *col; ++position; } _row_start.push_back (position); } } // Initialize the matrix libmesh_assert (!this->initialized()); this->init (); libmesh_assert (this->initialized()); //libMesh::out << "n_rows=" << n_rows << std::endl; //libMesh::out << "m()=" << m() << std::endl; libmesh_assert_equal_to (n_rows, this->m()); // Tell the matrix about its structure. Initialize it // to zero. for (numeric_index_type i=0; i<n_rows; i++) { const std::vector<numeric_index_type>::const_iterator rs = _row_start[i]; const numeric_index_type length = _row_start[i+1] - rs; Q_SetLen (&_QMat, i+1, length); for (numeric_index_type l=0; l<length; l++) { const numeric_index_type j = *(rs+l); // sanity check //libMesh::out << "m()=" << m() << std::endl; //libMesh::out << "(i,j,l) = (" << i // << "," << j // << "," << l // << ")" << std::endl; //libMesh::out << "pos(i,j)=" << pos(i,j) // << std::endl; libmesh_assert_equal_to (this->pos(i,j), l); Q_SetEntry (&_QMat, i+1, l, j+1, 0.); } } // That's it! //libmesh_here(); }
void Tet::select_diagonal (const Diagonal diag) const { libmesh_assert_equal_to (_diagonal_selection, INVALID_DIAG); _diagonal_selection = diag; }
void TimeSolver::solve () { libmesh_assert(this->diff_solver().get()); libmesh_assert_equal_to (&(this->diff_solver()->system()), &(this->system())); this->diff_solver()->solve(); }
// The main program int main(int argc, char** argv) { // Initialize libMesh LibMeshInit init(argc, argv); // Parameters GetPot infile("fem_system_params.in"); const Real global_tolerance = infile("global_tolerance", 0.); const unsigned int nelem_target = infile("n_elements", 400); const bool transient = infile("transient", true); const Real deltat = infile("deltat", 0.005); unsigned int n_timesteps = infile("n_timesteps", 1); //const unsigned int coarsegridsize = infile("coarsegridsize", 1); const unsigned int coarserefinements = infile("coarserefinements", 0); const unsigned int max_adaptivesteps = infile("max_adaptivesteps", 10); //const unsigned int dim = 2; #ifdef LIBMESH_HAVE_EXODUS_API const unsigned int write_interval = infile("write_interval", 5); #endif // Create a mesh, with dimension to be overridden later, distributed // across the default MPI communicator. Mesh mesh(init.comm()); Mesh mesh_dummy(init.comm()); GetPot infileForMesh("convdiff_mprime.in"); std::string find_mesh_here = infileForMesh("mesh","psiLF_mesh.xda"); mesh.read(find_mesh_here); mesh_dummy.read(find_mesh_here); std::cout << "Read in mesh from: " << find_mesh_here << "\n\n"; // And an object to refine it MeshRefinement mesh_refinement(mesh); //mesh_refinement.coarsen_by_parents() = true; //mesh_refinement.absolute_global_tolerance() = global_tolerance; //mesh_refinement.nelem_target() = nelem_target; //mesh_refinement.refine_fraction() = 0.3; //mesh_refinement.coarsen_fraction() = 0.3; //mesh_refinement.coarsen_threshold() = 0.1; //mesh_refinement.uniformly_refine(coarserefinements); // Print information about the mesh to the screen. mesh.print_info(); // Create an equation systems object. EquationSystems equation_systems (mesh); EquationSystems eqSysDummy(mesh_dummy); // Name system ConvDiff_MprimeSys & system = equation_systems.add_system<ConvDiff_MprimeSys>("ConvDiff_MprimeSys"); ConvDiff_MprimeSys & system_dummy = eqSysDummy.add_system<ConvDiff_MprimeSys>("ConvDiff_MprimeSys"); // Steady-state problem system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system)); system_dummy.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system)); // Sanity check that we are indeed solving a steady problem libmesh_assert_equal_to (n_timesteps, 1); // Read in all the equation systems data from the LF solve (system, solutions, rhs, etc) std::string find_psiLF_here = infileForMesh("psiLF_file","psiLF.xda"); std::cout << "Looking for psiLF at: " << find_psiLF_here << "\n" << std::endl; eqSysDummy.read(find_psiLF_here, READ, EquationSystems::READ_HEADER | EquationSystems::READ_DATA | EquationSystems::READ_ADDITIONAL_DATA); // Check that the norm of the solution read in is what we expect it to be //Real readin_L2 = system.calculate_norm(*system.solution, L2); //std::cout << "Read in solution norm: "<< readin_L2 << std::endl << std::endl; //DEBUG //equation_systems.write("right_back_out.xda", WRITE, EquationSystems::WRITE_DATA | // EquationSystems::WRITE_ADDITIONAL_DATA); #ifdef LIBMESH_HAVE_GMV //GMVIO(equation_systems.get_mesh()).write_equation_systems(std::string("right_back_out.gmv"), equation_systems); #endif // Initialize the system equation_systems.init (); DirectSolutionTransfer sol_transfer(init.comm()); sol_transfer.transfer(system_dummy.variable(system_dummy.variable_number("c")), system.variable(system.variable_number("c"))); sol_transfer.transfer(system_dummy.variable(system_dummy.variable_number("zc")), system.variable(system.variable_number("zc"))); sol_transfer.transfer(system_dummy.variable(system_dummy.variable_number("fc")), system.variable(system.variable_number("fc"))); sol_transfer.transfer(system_dummy.variable(system_dummy.variable_number("aux_c")), system.variable(system.variable_number("aux_c"))); sol_transfer.transfer(system_dummy.variable(system_dummy.variable_number("aux_zc")), system.variable(system.variable_number("aux_zc"))); sol_transfer.transfer(system_dummy.variable(system_dummy.variable_number("aux_fc")), system.variable(system.variable_number("aux_fc"))); std::cout << "c: " << system.calculate_norm(*system.solution, 0, L2) << std::endl; std::cout << "zc: " << system.calculate_norm(*system.solution, 1, L2) << std::endl; std::cout << "fc: " << system.calculate_norm(*system.solution, 2, L2) << std::endl; std::cout << "aux_c: " << system.calculate_norm(*system.solution, 3, L2) << std::endl; std::cout << "aux_zc: " << system.calculate_norm(*system.solution, 4, L2) << std::endl; std::cout << "aux_fc: " << system.calculate_norm(*system.solution, 5, L2) << std::endl; //save values of scalar variables; FEMSystem::point_value doesn't work for scalars...?! //Point p(0.0333333, 0.0333333); //system.stash_constants( // system_dummy.point_value(system_dummy.variable_number("fconst"),p), // system_dummy.point_value(system_dummy.variable_number("aux_fconst"),p)); int endind = (*system_dummy.solution).size(); system.stash_constants((*system_dummy.solution)(endind-2),(*system_dummy.solution)(endind-1)); // And the nonlinear solver options NewtonSolver *solver = new NewtonSolver(system); system.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver); solver->quiet = infile("solver_quiet", true); solver->verbose = !solver->quiet; solver->max_nonlinear_iterations = infile("max_nonlinear_iterations", 15); solver->relative_step_tolerance = infile("relative_step_tolerance", 1.e-3); solver->relative_residual_tolerance = infile("relative_residual_tolerance", 0.0); solver->absolute_residual_tolerance = infile("absolute_residual_tolerance", 0.0); // And the linear solver options solver->max_linear_iterations = infile("max_linear_iterations", 50000); solver->initial_linear_tolerance = infile("initial_linear_tolerance", 1.e-3); // Print information about the system to the screen. equation_systems.print_info(); // Now we begin the timestep loop to compute the time-accurate // solution of the equations...not that this is transient, but eh, why not... for (unsigned int t_step=0; t_step != n_timesteps; ++t_step) { // A pretty update message std::cout << "\n\nSolving time step " << t_step << ", time = " << system.time << std::endl; // Adaptively solve the timestep unsigned int a_step = 0; for (; a_step != max_adaptivesteps; ++a_step) { // VESTIGIAL for now ('vestigial' eh ? ;) ) std::cout << "\n\n I should be skipped what are you doing here lalalalalalala *!**!*!*!*!*!* \n\n"; system.solve(); system.postprocess(); ErrorVector error; AutoPtr<ErrorEstimator> error_estimator; // To solve to a tolerance in this problem we // need a better estimator than Kelly if (global_tolerance != 0.) { // We can't adapt to both a tolerance and a mesh // size at once libmesh_assert_equal_to (nelem_target, 0); UniformRefinementEstimator *u = new UniformRefinementEstimator; // The lid-driven cavity problem isn't in H1, so // lets estimate L2 error u->error_norm = L2; error_estimator.reset(u); } else { // If we aren't adapting to a tolerance we need a // target mesh size libmesh_assert_greater (nelem_target, 0); // Kelly is a lousy estimator to use for a problem // not in H1 - if we were doing more than a few // timesteps we'd need to turn off or limit the // maximum level of our adaptivity eventually error_estimator.reset(new KellyErrorEstimator); } // Calculate error std::vector<Real> weights(9,1.0); // based on u, v, p, c, their adjoints, and source parameter // Keep the same default norm type. std::vector<FEMNormType> norms(1, error_estimator->error_norm.type(0)); error_estimator->error_norm = SystemNorm(norms, weights); error_estimator->estimate_error(system, error); // Print out status at each adaptive step. Real global_error = error.l2_norm(); std::cout << "Adaptive step " << a_step << ": " << std::endl; if (global_tolerance != 0.) std::cout << "Global_error = " << global_error << std::endl; if (global_tolerance != 0.) std::cout << "Worst element error = " << error.maximum() << ", mean = " << error.mean() << std::endl; if (global_tolerance != 0.) { // If we've reached our desired tolerance, we // don't need any more adaptive steps if (global_error < global_tolerance) break; mesh_refinement.flag_elements_by_error_tolerance(error); } else { // If flag_elements_by_nelem_target returns true, this // should be our last adaptive step. if (mesh_refinement.flag_elements_by_nelem_target(error)) { mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); a_step = max_adaptivesteps; break; } } // Carry out the adaptive mesh refinement/coarsening mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); std::cout << "Refined mesh to " << mesh.n_active_elem() << " active elements and " << equation_systems.n_active_dofs() << " active dofs." << std::endl; } // End loop over adaptive steps // Do one last solve if necessary if (a_step == max_adaptivesteps) { QoISet qois; std::vector<unsigned int> qoi_indices; qoi_indices.push_back(0); qois.add_indices(qoi_indices); qois.set_weight(0, 1.0); system.assemble_qoi_sides = true; //QoI doesn't involve sides std::cout << "\n~*~*~*~*~*~*~*~*~ adjoint solve start ~*~*~*~*~*~*~*~*~\n" << std::endl; std::pair<unsigned int, Real> adjsolve = system.adjoint_solve(); std::cout << "number of iterations to solve adjoint: " << adjsolve.first << std::endl; std::cout << "final residual of adjoint solve: " << adjsolve.second << std::endl; std::cout << "\n~*~*~*~*~*~*~*~*~ adjoint solve end ~*~*~*~*~*~*~*~*~" << std::endl; NumericVector<Number> &dual_solution = system.get_adjoint_solution(0); NumericVector<Number> &primal_solution = *system.solution; primal_solution.swap(dual_solution); ExodusII_IO(mesh).write_timestep("super_adjoint.exo", equation_systems, 1, /* This number indicates how many time steps are being written to the file */ system.time); primal_solution.swap(dual_solution); system.assemble(); //overwrite residual read in from psiLF solve // The total error estimate system.postprocess(); //to compute M_HF(psiLF) and M_LF(psiLF) terms Real QoI_error_estimate = (-0.5*(system.rhs)->dot(dual_solution)) + system.get_MHF_psiLF() - system.get_MLF_psiLF(); std::cout << "\n\n 0.5*M'_HF(psiLF)(superadj): " << std::setprecision(17) << 0.5*(system.rhs)->dot(dual_solution) << "\n"; std::cout << " M_HF(psiLF): " << std::setprecision(17) << system.get_MHF_psiLF() << "\n"; std::cout << " M_LF(psiLF): " << std::setprecision(17) << system.get_MLF_psiLF() << "\n"; std::cout << "\n\n Residual L2 norm: " << system.calculate_norm(*system.rhs, L2) << "\n"; std::cout << " Residual discrete L2 norm: " << system.calculate_norm(*system.rhs, DISCRETE_L2) << "\n"; std::cout << " Super-adjoint L2 norm: " << system.calculate_norm(dual_solution, L2) << "\n"; std::cout << " Super-adjoint discrete L2 norm: " << system.calculate_norm(dual_solution, DISCRETE_L2) << "\n"; std::cout << "\n\n QoI error estimate: " << std::setprecision(17) << QoI_error_estimate << "\n\n"; //DEBUG std::cout << "\n------------ herp derp ------------" << std::endl; //libMesh::out.precision(16); //dual_solution.print(); //system.get_adjoint_rhs().print(); AutoPtr<NumericVector<Number> > adjresid = system.solution->clone(); (system.matrix)->vector_mult(*adjresid,system.get_adjoint_solution(0)); SparseMatrix<Number>& adjmat = *system.matrix; (system.matrix)->get_transpose(adjmat); adjmat.vector_mult(*adjresid,system.get_adjoint_solution(0)); //std::cout << "******************** matrix-superadj product (libmesh) ************************" << std::endl; //adjresid->print(); adjresid->add(-1.0, system.get_adjoint_rhs(0)); //std::cout << "******************** superadjoint system residual (libmesh) ***********************" << std::endl; //adjresid->print(); std::cout << "\n\nadjoint system residual (discrete L2): " << system.calculate_norm(*adjresid,DISCRETE_L2) << std::endl; std::cout << "adjoint system residual (L2, all): " << system.calculate_norm(*adjresid,L2) << std::endl; std::cout << "adjoint system residual (L2, 0): " << system.calculate_norm(*adjresid,0,L2) << std::endl; std::cout << "adjoint system residual (L2, 1): " << system.calculate_norm(*adjresid,1,L2) << std::endl; std::cout << "adjoint system residual (L2, 2): " << system.calculate_norm(*adjresid,2,L2) << std::endl; std::cout << "adjoint system residual (L2, 3): " << system.calculate_norm(*adjresid,3,L2) << std::endl; std::cout << "adjoint system residual (L2, 4): " << system.calculate_norm(*adjresid,4,L2) << std::endl; std::cout << "adjoint system residual (L2, 5): " << system.calculate_norm(*adjresid,5,L2) << std::endl; /* AutoPtr<NumericVector<Number> > sadj_matlab = system.solution->clone(); AutoPtr<NumericVector<Number> > adjresid_matlab = system.solution->clone(); if(FILE *fp=fopen("superadj_matlab.txt","r")){ Real value; int counter = 0; int flag = 1; while(flag != -1){ flag = fscanf(fp,"%lf",&value); if(flag != -1){ sadj_matlab->set(counter, value); counter += 1; } } fclose(fp); } (system.matrix)->vector_mult(*adjresid_matlab,*sadj_matlab); //std::cout << "******************** matrix-superadj product (matlab) ***********************" << std::endl; //adjresid_matlab->print(); adjresid_matlab->add(-1.0, system.get_adjoint_rhs(0)); //std::cout << "******************** superadjoint system residual (matlab) ***********************" << std::endl; //adjresid_matlab->print(); std::cout << "\n\nmatlab import adjoint system residual (discrete L2): " << system.calculate_norm(*adjresid_matlab,DISCRETE_L2) << "\n" << std::endl; */ /* AutoPtr<NumericVector<Number> > sadj_fwd_hack = system.solution->clone(); AutoPtr<NumericVector<Number> > adjresid_fwd_hack = system.solution->clone(); if(FILE *fp=fopen("superadj_forward_hack.txt","r")){ Real value; int counter = 0; int flag = 1; while(flag != -1){ flag = fscanf(fp,"%lf",&value); if(flag != -1){ sadj_fwd_hack->set(counter, value); counter += 1; } } fclose(fp); } (system.matrix)->vector_mult(*adjresid_fwd_hack,*sadj_fwd_hack); //std::cout << "******************** matrix-superadj product (fwd_hack) ***********************" << std::endl; //adjresid_fwd_hack->print(); adjresid_fwd_hack->add(-1.0, system.get_adjoint_rhs(0)); //std::cout << "******************** superadjoint system residual (fwd_hack) ***********************" << std::endl; //adjresid_fwd_hack->print(); std::cout << "\n\nfwd_hack import adjoint system residual (discrete L2): " << system.calculate_norm(*adjresid_fwd_hack,DISCRETE_L2) << "\n" << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 0): " << system.calculate_norm(*adjresid_fwd_hack,0,L2) << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 1): " << system.calculate_norm(*adjresid_fwd_hack,1,L2) << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 2): " << system.calculate_norm(*adjresid_fwd_hack,2,L2) << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 3): " << system.calculate_norm(*adjresid_fwd_hack,3,L2) << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 4): " << system.calculate_norm(*adjresid_fwd_hack,4,L2) << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 5): " << system.calculate_norm(*adjresid_fwd_hack,5,L2) << std::endl; */ //std::cout << "************************ system.matrix ***********************" << std::endl; //system.matrix->print(); std::cout << "\n------------ herp derp ------------" << std::endl; // The cell wise breakdown ErrorVector cell_wise_error; cell_wise_error.resize((system.rhs)->size()); for(unsigned int i = 0; i < (system.rhs)->size() ; i++) { if(i < system.get_mesh().n_elem()) cell_wise_error[i] = fabs(-0.5*((system.rhs)->el(i) * dual_solution(i)) + system.get_MHF_psiLF(i) - system.get_MLF_psiLF(i)); else cell_wise_error[i] = fabs(-0.5*((system.rhs)->el(i) * dual_solution(i))); /*csv from 'save data' from gmv output gives a few values at each node point (value for every element that shares that node), yet paraview display only seems to show one of them -> the value in an element is given at each of the nodes that it has, hence the repetition; what is displayed in paraview is each element's value; even though MHF_psiLF and MLF_psiLF are stored by element this seems to give elemental contributions that agree with if we had taken the superadj-residual dot product by integrating over elements*/ /*at higher mesh resolutions and lower k, weird-looking artifacts start to appear and it no longer agrees with output from manual integration of superadj-residual...*/ } // Plot it std::ostringstream error_gmv; error_gmv << "error.gmv"; cell_wise_error.plot_error(error_gmv.str(), equation_systems.get_mesh()); //alternate element-wise breakdown, outputed as values matched to element centroids; for matlab plotz primal_solution.swap(dual_solution); system.postprocess(1); primal_solution.swap(dual_solution); system.postprocess(2); std::cout << "\n\n -0.5*M'_HF(psiLF)(superadj): " << std::setprecision(17) << system.get_half_adj_weighted_resid() << "\n"; primal_solution.swap(dual_solution); std::string write_error_here = infileForMesh("error_est_output_file", "error_est_breakdown.dat"); std::ofstream output(write_error_here); for(unsigned int i = 0 ; i < system.get_mesh().n_elem(); i++){ Point elem_cent = system.get_mesh().elem(i)->centroid(); if(output.is_open()){ output << elem_cent(0) << " " << elem_cent(1) << " " << fabs(system.get_half_adj_weighted_resid(i) + system.get_MHF_psiLF(i) - system.get_MLF_psiLF(i)) << "\n"; } } output.close(); } // End if at max adaptive steps #ifdef LIBMESH_HAVE_EXODUS_API // Write out this timestep if we're requested to if ((t_step+1)%write_interval == 0) { std::ostringstream file_name; /* // We write the file in the ExodusII format. file_name << "out_" << std::setw(3) << std::setfill('0') << std::right << t_step+1 << ".e"; //this should write out the primal which should be the same as what's read in... ExodusII_IO(mesh).write_timestep(file_name.str(), equation_systems, 1, //number of time steps written to file system.time); */ } #endif // #ifdef LIBMESH_HAVE_EXODUS_API } // All done. return 0; } //end main
void InverseDistanceInterpolation<KDDim>::interpolate (const Point & /* pt */, const std::vector<size_t> &src_indices, const std::vector<Real> &src_dist_sqr, std::vector<Number>::iterator &out_it) const { // We explicitly assume that the input source points are sorted from closest to // farthests. assert that assumption in DEBUG mode. #ifdef DEBUG if (!src_dist_sqr.empty()) { Real min_dist = src_dist_sqr.front(); std::vector<Real>::const_iterator it = src_dist_sqr.begin(); for (++it; it!= src_dist_sqr.end(); ++it) { if (*it < min_dist) libmesh_error(); min_dist = *it; } } #endif libmesh_assert_equal_to (src_dist_sqr.size(), src_indices.size()); // Compute the interpolation weights & interpolated value const unsigned int n_fv = this->n_field_variables(); _vals.resize(n_fv); /**/ std::fill (_vals.begin(), _vals.end(), Number(0.)); Real tot_weight = 0.; std::vector<Real>::const_iterator src_dist_sqr_it=src_dist_sqr.begin(); std::vector<size_t>::const_iterator src_idx_it=src_indices.begin(); // Loop over source points while ((src_dist_sqr_it != src_dist_sqr.end()) && (src_idx_it != src_indices.end())) { libmesh_assert_greater_equal (*src_dist_sqr_it, 0.); const Real dist_sq = std::max(*src_dist_sqr_it, std::numeric_limits<Real>::epsilon()), weight = 1./std::pow(dist_sq, _half_power); tot_weight += weight; const unsigned int src_idx = *src_idx_it; // loop over field variables for (unsigned int v=0; v<n_fv; v++) { libmesh_assert_less (src_idx*n_fv+v, _src_vals.size()); _vals[v] += _src_vals[src_idx*n_fv+v]*weight; } ++src_dist_sqr_it; ++src_idx_it; } // don't forget normalizing term & set the output buffer! for (unsigned int v=0; v<n_fv; v++, ++out_it) { _vals[v] /= tot_weight; *out_it = _vals[v]; } }
void InverseDistanceInterpolation<KDDim>::interpolate_field_data (const std::vector<std::string> &field_names, const std::vector<Point> &tgt_pts, std::vector<Number> &tgt_vals) const { libmesh_experimental(); // forcibly initialize, if needed #ifdef LIBMESH_HAVE_NANOFLANN if (_kd_tree.get() == NULL) const_cast<InverseDistanceInterpolation<KDDim>*>(this)->construct_kd_tree(); #endif START_LOG ("interpolate_field_data()", "InverseDistanceInterpolation<>"); libmesh_assert_equal_to (field_names.size(), this->n_field_variables()); // If we already have field variables, we assume we are appending. // that means the names and ordering better be identical! if (_names.size() != field_names.size()) { libMesh::err << "ERROR: when adding field data to an existing list the\n" << "varaible list must be the same!\n"; libmesh_error(); } for (unsigned int v=0; v<_names.size(); v++) if (_names[v] != field_names[v]) { libMesh::err << "ERROR: when adding field data to an existing list the\n" << "varaible list must be the same!\n"; libmesh_error(); } tgt_vals.resize (tgt_pts.size()*this->n_field_variables()); #ifdef LIBMESH_HAVE_NANOFLANN { std::vector<Number>::iterator out_it = tgt_vals.begin(); const size_t num_results = std::min((size_t) _n_interp_pts, _src_pts.size()); std::vector<size_t> ret_index(num_results); std::vector<Real> ret_dist_sqr(num_results); for (std::vector<Point>::const_iterator tgt_it=tgt_pts.begin(); tgt_it != tgt_pts.end(); ++tgt_it) { const Point &tgt(*tgt_it); const Real query_pt[] = { tgt(0), tgt(1), tgt(2) }; _kd_tree->knnSearch(&query_pt[0], num_results, &ret_index[0], &ret_dist_sqr[0]); this->interpolate (tgt, ret_index, ret_dist_sqr, out_it); // libMesh::out << "knnSearch(): num_results=" << num_results << "\n"; // for (size_t i=0;i<num_results;i++) // libMesh::out << "idx[" << i << "]=" // << std::setw(6) << ret_index[i] // << "\t dist["<< i << "]=" << ret_dist_sqr[i] // << "\t val[" << std::setw(6) << ret_index[i] << "]=" << _src_vals[ret_index[i]] // << std::endl; // libMesh::out << "\n"; // libMesh::out << "ival=" << _vals[0] << '\n'; } } #else libMesh::err << "ERROR: This functionality requires the library to be configured\n" << "with nanoflann KD-Tree approximate nearest neighbor support!\n" << std::endl; libmesh_error(); #endif STOP_LOG ("interpolate_field_data()", "InverseDistanceInterpolation<>"); }
void MeshfreeInterpolation::gather_remote_data () { #ifndef LIBMESH_HAVE_MPI // no MPI -- no-op return; #else // This function must be run on all processors at once parallel_object_only(); START_LOG ("gather_remote_data()", "MeshfreeInterpolation"); // block to avoid incorrect completion if called in quick succession on // two different MeshfreeInterpolation objects this->comm().barrier(); std::vector<Real> send_buf, recv_buf; libmesh_assert_equal_to (_src_vals.size(), _src_pts.size()*this->n_field_variables()); send_buf.reserve (_src_pts.size()*(3 + this->n_field_variables())); // Everyone packs their data at the same time for (unsigned int p_idx=0, v_idx=0; p_idx<_src_pts.size(); p_idx++) { const Point &pt(_src_pts[p_idx]); send_buf.push_back(pt(0)); send_buf.push_back(pt(1)); send_buf.push_back(pt(2)); for (unsigned int var=0; var<this->n_field_variables(); var++) { libmesh_assert_less (v_idx, _src_vals.size()); #ifdef LIBMESH_USE_COMPLEX_NUMBERS send_buf.push_back (_src_vals[v_idx].real()); send_buf.push_back (_src_vals[v_idx].imag()); v_idx++; #else send_buf.push_back (_src_vals[v_idx++]); #endif } } // Send our data to everyone else. Note that MPI-1 said you could not // use the same buffer in nonblocking sends, but that restriction has // recently been removed. std::vector<Parallel::Request> send_request(this->n_processors()-1); // Use a tag for best practices. In debug mode parallel_only() blocks above // so we can be sure there is no other shenanigarry going on, but in optimized // mode there is no such guarantee - other prcoessors could be somewhere else // completing some other communication, and we don't want to intercept that. Parallel::MessageTag tag = this->comm().get_unique_tag ( 6000 ); for (unsigned int proc=0, cnt=0; proc<this->n_processors(); proc++) if (proc != this->processor_id()) this->comm().send (proc, send_buf, send_request[cnt++], tag); // All data has been sent. Receive remote data in any order for (processor_id_type comm_step=0; comm_step<(this->n_processors()-1); comm_step++) { // blocking receive this->comm().receive (Parallel::any_source, recv_buf, tag); // Add their data to our list Point pt; Number val; std::vector<Real>::const_iterator it=recv_buf.begin(); while (it != recv_buf.end()) { pt(0) = *it, ++it; pt(1) = *it, ++it; pt(2) = *it, ++it; _src_pts.push_back(pt); for (unsigned int var=0; var<this->n_field_variables(); var++) { #ifdef LIBMESH_USE_COMPLEX_NUMBERS Real re = *it; ++it; Real im = *it; ++it; val = Number(re,im); #else val = *it, ++it; #endif _src_vals.push_back(val); } } } Parallel::wait (send_request); STOP_LOG ("gather_remote_data()", "MeshfreeInterpolation"); #endif // LIBMESH_HAVE_MPI }
void EnsightIO::write_vector_ascii(const std::string &sys, const std::vector<std::string> &vec, const std::string &var_name) { std::ostringstream vec_file; vec_file<<_ensight_file_name<<"_"<<var_name<<".vec"; vec_file << std::setw(3) << std::setprecision(0) << std::setfill('0') << std::right << _time_steps.size()-1; FILE * fout = fopen(vec_file.str().c_str(),"w"); fprintf(fout,"Per vector per value\n"); fprintf(fout,"part\n"); fprintf(fout,"%10d\n",1); fprintf(fout,"coordinates\n"); // Get a constant reference to the mesh object. const MeshBase& the_mesh = MeshOutput<MeshBase>::mesh(); // The dimension that we are running const unsigned int dim = the_mesh.mesh_dimension(); const System &system = _equation_systems.get_system(sys); const DofMap& dof_map = system.get_dof_map(); const unsigned int u_var = system.variable_number(vec[0]); const unsigned int v_var = system.variable_number(vec[1]); const unsigned int w_var = (dim==3) ? system.variable_number(vec[2]) : 0; std::vector<dof_id_type> dof_indices; std::vector<dof_id_type> dof_indices_u; std::vector<dof_id_type> dof_indices_v; std::vector<dof_id_type> dof_indices_w; // Now we will loop over all the elements in the mesh. MeshBase::const_element_iterator el = the_mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = the_mesh.active_local_elements_end(); typedef std::map<int,std::vector<Real> > map_local_soln; typedef map_local_soln::iterator local_soln_iterator; map_local_soln local_soln; for ( ; el != end_el ; ++el){ const Elem* elem = *el; const FEType& fe_type = system.variable_type(u_var); dof_map.dof_indices (elem, dof_indices); dof_map.dof_indices (elem, dof_indices_u,u_var); dof_map.dof_indices (elem, dof_indices_v,v_var); if(dim==3) dof_map.dof_indices (elem, dof_indices,w_var); std::vector<Number> elem_soln_u; std::vector<Number> elem_soln_v; std::vector<Number> elem_soln_w; std::vector<Number> nodal_soln_u; std::vector<Number> nodal_soln_v; std::vector<Number> nodal_soln_w; elem_soln_u.resize(dof_indices_u.size()); elem_soln_v.resize(dof_indices_v.size()); if(dim == 3) elem_soln_w.resize(dof_indices_w.size()); for (unsigned int i = 0; i < dof_indices_u.size(); i++) { elem_soln_u[i] = system.current_solution(dof_indices_u[i]); elem_soln_v[i] = system.current_solution(dof_indices_v[i]); if(dim==3) elem_soln_w[i] = system.current_solution(dof_indices_w[i]); } FEInterface::nodal_soln (dim,fe_type,elem,elem_soln_u,nodal_soln_u); FEInterface::nodal_soln (dim,fe_type,elem,elem_soln_v,nodal_soln_v); if(dim == 3) FEInterface::nodal_soln (dim,fe_type,elem,elem_soln_w,nodal_soln_w); libmesh_assert_equal_to (nodal_soln_u.size(), elem->n_nodes()); libmesh_assert_equal_to (nodal_soln_v.size(), elem->n_nodes()); #ifdef LIBMESH_ENABLE_COMPLEX libMesh::err << "Complex-valued Ensight output not yet supported" << std::endl; libmesh_not_implemented() #endif for (unsigned int n=0; n<elem->n_nodes(); n++) { std::vector<Real> node_vec(3); node_vec[0]= libmesh_real(nodal_soln_u[n]); node_vec[1]= libmesh_real(nodal_soln_v[n]); node_vec[2]=0.0; if(dim==3) node_vec[2]= libmesh_real(nodal_soln_w[n]); local_soln[elem->node(n)] = node_vec; } } local_soln_iterator sol = local_soln.begin(); const local_soln_iterator sol_end = local_soln.end(); for(; sol != sol_end; ++sol) fprintf(fout,"%12.5e\n",static_cast<double>((*sol).second[0])); sol = local_soln.begin(); for(; sol != sol_end; ++sol) fprintf(fout,"%12.5e\n",static_cast<double>((*sol).second[1])); sol = local_soln.begin(); for(; sol != sol_end; ++sol) fprintf(fout,"%12.5e\n",static_cast<double>((*sol).second[2])); fclose(fout); }
bool FEMPhysics::eulerian_residual (bool request_jacobian, DiffContext & /*c*/) { // Only calculate a mesh movement residual if it's necessary if (!_mesh_sys) return request_jacobian; libmesh_not_implemented(); #if 0 FEMContext & context = cast_ref<FEMContext &>(c); // This function only supports fully coupled mesh motion for now libmesh_assert_equal_to (_mesh_sys, this); unsigned int n_qpoints = (context.get_element_qrule())->n_points(); const unsigned int n_x_dofs = (_mesh_x_var == libMesh::invalid_uint) ? 0 : context.dof_indices_var[_mesh_x_var].size(); const unsigned int n_y_dofs = (_mesh_y_var == libMesh::invalid_uint) ? 0 : context.dof_indices_var[_mesh_y_var].size(); const unsigned int n_z_dofs = (_mesh_z_var == libMesh::invalid_uint) ? 0 : context.dof_indices_var[_mesh_z_var].size(); const unsigned int mesh_xyz_var = n_x_dofs ? _mesh_x_var : (n_y_dofs ? _mesh_y_var : (n_z_dofs ? _mesh_z_var : libMesh::invalid_uint)); // If we're our own _mesh_sys, we'd better be in charge of // at least one coordinate, and we'd better have the same // FE type for all coordinates we are in charge of libmesh_assert_not_equal_to (mesh_xyz_var, libMesh::invalid_uint); libmesh_assert(!n_x_dofs || context.element_fe_var[_mesh_x_var] == context.element_fe_var[mesh_xyz_var]); libmesh_assert(!n_y_dofs || context.element_fe_var[_mesh_y_var] == context.element_fe_var[mesh_xyz_var]); libmesh_assert(!n_z_dofs || context.element_fe_var[_mesh_z_var] == context.element_fe_var[mesh_xyz_var]); const std::vector<std::vector<Real>> & psi = context.element_fe_var[mesh_xyz_var]->get_phi(); for (unsigned int var = 0; var != context.n_vars(); ++var) { // Mesh motion only affects time-evolving variables if (this->is_time_evolving(var)) continue; // The mesh coordinate variables themselves are Lagrangian, // not Eulerian, and no convective term is desired. if (/*_mesh_sys == this && */ (var == _mesh_x_var || var == _mesh_y_var || var == _mesh_z_var)) continue; // Some of this code currently relies on the assumption that // we can pull mesh coordinate data from our own system if (_mesh_sys != this) libmesh_not_implemented(); // This residual should only be called by unsteady solvers: // if the mesh is steady, there's no mesh convection term! UnsteadySolver * unsteady; if (this->time_solver->is_steady()) return request_jacobian; else unsteady = cast_ptr<UnsteadySolver*>(this->time_solver.get()); const std::vector<Real> & JxW = context.element_fe_var[var]->get_JxW(); const std::vector<std::vector<Real>> & phi = context.element_fe_var[var]->get_phi(); const std::vector<std::vector<RealGradient>> & dphi = context.element_fe_var[var]->get_dphi(); const unsigned int n_u_dofs = context.dof_indices_var[var].size(); DenseSubVector<Number> & Fu = *context.elem_subresiduals[var]; DenseSubMatrix<Number> & Kuu = *context.elem_subjacobians[var][var]; DenseSubMatrix<Number> * Kux = n_x_dofs ? context.elem_subjacobians[var][_mesh_x_var] : nullptr; DenseSubMatrix<Number> * Kuy = n_y_dofs ? context.elem_subjacobians[var][_mesh_y_var] : nullptr; DenseSubMatrix<Number> * Kuz = n_z_dofs ? context.elem_subjacobians[var][_mesh_z_var] : nullptr; std::vector<Real> delta_x(n_x_dofs, 0.); std::vector<Real> delta_y(n_y_dofs, 0.); std::vector<Real> delta_z(n_z_dofs, 0.); for (unsigned int i = 0; i != n_x_dofs; ++i) { unsigned int j = context.dof_indices_var[_mesh_x_var][i]; delta_x[i] = libmesh_real(this->current_solution(j)) - libmesh_real(unsteady->old_nonlinear_solution(j)); } for (unsigned int i = 0; i != n_y_dofs; ++i) { unsigned int j = context.dof_indices_var[_mesh_y_var][i]; delta_y[i] = libmesh_real(this->current_solution(j)) - libmesh_real(unsteady->old_nonlinear_solution(j)); } for (unsigned int i = 0; i != n_z_dofs; ++i) { unsigned int j = context.dof_indices_var[_mesh_z_var][i]; delta_z[i] = libmesh_real(this->current_solution(j)) - libmesh_real(unsteady->old_nonlinear_solution(j)); } for (unsigned int qp = 0; qp != n_qpoints; ++qp) { Gradient grad_u = context.interior_gradient(var, qp); RealGradient convection(0.); for (unsigned int i = 0; i != n_x_dofs; ++i) convection(0) += delta_x[i] * psi[i][qp]; for (unsigned int i = 0; i != n_y_dofs; ++i) convection(1) += delta_y[i] * psi[i][qp]; for (unsigned int i = 0; i != n_z_dofs; ++i) convection(2) += delta_z[i] * psi[i][qp]; for (unsigned int i = 0; i != n_u_dofs; ++i) { Number JxWxPhiI = JxW[qp] * phi[i][qp]; Fu(i) += (convection * grad_u) * JxWxPhiI; if (request_jacobian) { Number JxWxPhiI = JxW[qp] * phi[i][qp]; for (unsigned int j = 0; j != n_u_dofs; ++j) Kuu(i,j) += JxWxPhiI * (convection * dphi[j][qp]); Number JxWxPhiIoverDT = JxWxPhiI/this->deltat; Number JxWxPhiIxDUDXoverDT = JxWxPhiIoverDT * grad_u(0); for (unsigned int j = 0; j != n_x_dofs; ++j) (*Kux)(i,j) += JxWxPhiIxDUDXoverDT * psi[j][qp]; Number JxWxPhiIxDUDYoverDT = JxWxPhiIoverDT * grad_u(1); for (unsigned int j = 0; j != n_y_dofs; ++j) (*Kuy)(i,j) += JxWxPhiIxDUDYoverDT * psi[j][qp]; Number JxWxPhiIxDUDZoverDT = JxWxPhiIoverDT * grad_u(2); for (unsigned int j = 0; j != n_z_dofs; ++j) (*Kuz)(i,j) += JxWxPhiIxDUDZoverDT * psi[j][qp]; } } } } #endif // 0 return request_jacobian; }
bool Edge2::is_node_on_edge(const unsigned int, const unsigned int libmesh_dbg_var(e)) const { libmesh_assert_equal_to (e, 0); return true; }
void MEDITIO::write_ascii (const std::string & fname, const std::vector<Number> * vec, const std::vector<std::string> * solution_names) { // Current lacks in implementation: // (i) only 3D meshes. // (ii) only QUAD4, TRI3, TET4 elements, others are omitted ! // (iii) no distinction between materials. // (iv) no vector output, just first scalar as output // libmesh_assert three dimensions (should be extended later) libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().mesh_dimension(), 3); // Open the output file stream std::ofstream out_stream (fname.c_str()); // Make sure it opened correctly if (!out_stream.good()) libmesh_file_error(fname.c_str()); // Get a reference to the mesh const MeshBase & the_mesh = MeshOutput<MeshBase>::mesh(); // Begin interfacing with the MEdit data file { // header: out_stream << "MeshVersionFormatted 1\n"; out_stream << "Dimension 3\n"; out_stream << "# Mesh generated by libmesh\n\n"; // write the nodes: out_stream << "# Set of mesh vertices\n"; out_stream << "Vertices\n"; out_stream << the_mesh.n_nodes() << "\n"; for (unsigned int v=0; v<the_mesh.n_nodes(); v++) out_stream << the_mesh.point(v)(0) << " " << the_mesh.point(v)(1) << " " << the_mesh.point(v)(2) << " 0\n"; } { // write the connectivity: out_stream << "\n# Set of Polys\n\n"; // count occurrences of output elements: int n_tri3 = 0; int n_quad4 = 0; int n_tet4 = 0; for (const auto & elem : the_mesh.active_element_ptr_range()) { if (elem->type() == TRI3) n_tri3++; if (elem->type() == QUAD4) n_quad4++; if (elem->type() == QUAD9) n_quad4+=4; // (QUAD9 is written as 4 QUAD4.) if (elem->type() == TET4) n_tet4++; } // First: write out TRI3 elements: out_stream << "Triangles\n"; out_stream << n_tri3 << "\n"; for (const auto & elem : the_mesh.active_element_ptr_range()) if (elem->type() == TRI3) out_stream << elem->node_id(0)+1 << " " << elem->node_id(1)+1 << " " << elem->node_id(2)+1 << " 0\n"; // Second: write out QUAD4 elements: out_stream << "Quadrilaterals\n"; out_stream << n_quad4 << "\n"; for (const auto & elem : the_mesh.active_element_ptr_range()) { if (elem->type() == QUAD4) { out_stream << elem->node_id(0)+1 << " " << elem->node_id(1)+1 << " " << elem->node_id(2)+1 << " " << elem->node_id(3)+1 <<" 0\n"; } // if else if (elem->type() == QUAD9) { out_stream << elem->node_id(0)+1 << " " << elem->node_id(4)+1 << " " << elem->node_id(8)+1 << " " << elem->node_id(7)+1 <<" 0\n"; out_stream << elem->node_id(7)+1 << " " << elem->node_id(8)+1 << " " << elem->node_id(6)+1 << " " << elem->node_id(3)+1 <<" 0\n"; out_stream << elem->node_id(4)+1 << " " << elem->node_id(1)+1 << " " << elem->node_id(5)+1 << " " << elem->node_id(8)+1 <<" 0\n"; out_stream << elem->node_id(8)+1 << " " << elem->node_id(5)+1 << " " << elem->node_id(2)+1 << " " << elem->node_id(6)+1 <<" 0\n"; } } // Third: write out TET4 elements: out_stream << "Tetrahedra\n"; out_stream << n_tet4 << "\n"; for (const auto & elem : the_mesh.active_element_ptr_range()) if (elem->type() == TET4) { out_stream << elem->node_id(0)+1 << " " << elem->node_id(1)+1 << " " << elem->node_id(2)+1 << " " << elem->node_id(3)+1 <<" 0\n"; } } // end of the out file out_stream << '\n' << "# end of file\n"; // optionally write the data if ((solution_names != libmesh_nullptr) && (vec != libmesh_nullptr)) { // Open the ".bb" file stream std::size_t idx = fname.find_last_of("."); std::string bbname = fname.substr(0,idx) + ".bb"; std::ofstream bbout (bbname.c_str()); // Make sure it opened correctly if (!bbout.good()) libmesh_file_error(bbname.c_str()); // Header: 3: 3D mesh, 1: scalar output, 2: node-indexed const std::size_t n_vars = solution_names->size(); bbout << "3 1 " << the_mesh.n_nodes() << " 2\n"; for (dof_id_type n=0; n<the_mesh.n_nodes(); n++) bbout << std::setprecision(10) << (*vec)[n*n_vars + scalar_idx] << " "; bbout << "\n"; } // endif }
void ParmetisPartitioner::initialize (const MeshBase& mesh, const unsigned int n_sbdmns) { const dof_id_type n_active_local_elem = mesh.n_active_local_elem(); // Set parameters. _pmetis->wgtflag = 2; // weights on vertices only _pmetis->ncon = 1; // one weight per vertex _pmetis->numflag = 0; // C-style 0-based numbering _pmetis->nparts = static_cast<Parmetis::idx_t>(n_sbdmns); // number of subdomains to create _pmetis->edgecut = 0; // the numbers of edges cut by the // partition // Initialize data structures for ParMETIS _pmetis->vtxdist.resize (mesh.n_processors()+1); std::fill (_pmetis->vtxdist.begin(), _pmetis->vtxdist.end(), 0); _pmetis->tpwgts.resize (_pmetis->nparts); std::fill (_pmetis->tpwgts.begin(), _pmetis->tpwgts.end(), 1./_pmetis->nparts); _pmetis->ubvec.resize (_pmetis->ncon); std::fill (_pmetis->ubvec.begin(), _pmetis->ubvec.end(), 1.05); _pmetis->part.resize (n_active_local_elem); std::fill (_pmetis->part.begin(), _pmetis->part.end(), 0); _pmetis->options.resize (5); _pmetis->vwgt.resize (n_active_local_elem); // Set the options _pmetis->options[0] = 1; // don't use default options _pmetis->options[1] = 0; // default (level of timing) _pmetis->options[2] = 15; // random seed (default) _pmetis->options[3] = 2; // processor distribution and subdomain distribution are decoupled // Find the number of active elements on each processor. We cannot use // mesh.n_active_elem_on_proc(pid) since that only returns the number of // elements assigned to pid which are currently stored on the calling // processor. This will not in general be correct for parallel meshes // when (pid!=mesh.processor_id()). _n_active_elem_on_proc.resize(mesh.n_processors()); mesh.comm().allgather(n_active_local_elem, _n_active_elem_on_proc); // count the total number of active elements in the mesh. Note we cannot // use mesh.n_active_elem() in general since this only returns the number // of active elements which are stored on the calling processor. // We should not use n_active_elem for any allocation because that will // be inheritly unscalable, but it can be useful for libmesh_assertions. dof_id_type n_active_elem=0; // Set up the vtxdist array. This will be the same on each processor. // ***** Consult the Parmetis documentation. ***** libmesh_assert_equal_to (_pmetis->vtxdist.size(), cast_int<std::size_t>(mesh.n_processors()+1)); libmesh_assert_equal_to (_pmetis->vtxdist[0], 0); for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { _pmetis->vtxdist[pid+1] = _pmetis->vtxdist[pid] + _n_active_elem_on_proc[pid]; n_active_elem += _n_active_elem_on_proc[pid]; } libmesh_assert_equal_to (_pmetis->vtxdist.back(), static_cast<Parmetis::idx_t>(n_active_elem)); // ParMetis expects the elements to be numbered in contiguous blocks // by processor, i.e. [0, ne0), [ne0, ne0+ne1), ... // Since we only partition active elements we should have no expectation // that we currently have such a distribution. So we need to create it. // Also, at the same time we are going to map all the active elements into a globally // unique range [0,n_active_elem) which is *independent* of the current partitioning. // This can be fed to ParMetis as the initial partitioning of the subdomains (decoupled // from the partitioning of the objects themselves). This allows us to get the same // resultant partitioning independed of the input partitioning. MeshTools::BoundingBox bbox = MeshTools::bounding_box(mesh); _global_index_by_pid_map.clear(); // Maps active element ids into a contiguous range independent of partitioning. // (only needs local scope) vectormap<dof_id_type, dof_id_type> global_index_map; { std::vector<dof_id_type> global_index; // create the mapping which is contiguous by processor dof_id_type pid_offset=0; for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { MeshBase::const_element_iterator it = mesh.active_pid_elements_begin(pid); const MeshBase::const_element_iterator end = mesh.active_pid_elements_end(pid); // note that we may not have all (or any!) the active elements which belong on this processor, // but by calling this on all processors a unique range in [0,_n_active_elem_on_proc[pid]) // is constructed. Only the indices for the elements we pass in are returned in the array. MeshCommunication().find_global_indices (mesh.comm(), bbox, it, end, global_index); for (dof_id_type cnt=0; it != end; ++it) { const Elem *elem = *it; libmesh_assert (!_global_index_by_pid_map.count(elem->id())); libmesh_assert_less (cnt, global_index.size()); libmesh_assert_less (global_index[cnt], _n_active_elem_on_proc[pid]); _global_index_by_pid_map.insert(std::make_pair(elem->id(), global_index[cnt++] + pid_offset)); } pid_offset += _n_active_elem_on_proc[pid]; } // create the unique mapping for all active elements independent of partitioning { MeshBase::const_element_iterator it = mesh.active_elements_begin(); const MeshBase::const_element_iterator end = mesh.active_elements_end(); // Calling this on all processors a unique range in [0,n_active_elem) is constructed. // Only the indices for the elements we pass in are returned in the array. MeshCommunication().find_global_indices (mesh.comm(), bbox, it, end, global_index); for (dof_id_type cnt=0; it != end; ++it) { const Elem *elem = *it; libmesh_assert (!global_index_map.count(elem->id())); libmesh_assert_less (cnt, global_index.size()); libmesh_assert_less (global_index[cnt], n_active_elem); global_index_map.insert(std::make_pair(elem->id(), global_index[cnt++])); } } // really, shouldn't be close! libmesh_assert_less_equal (global_index_map.size(), n_active_elem); libmesh_assert_less_equal (_global_index_by_pid_map.size(), n_active_elem); // At this point the two maps should be the same size. If they are not // then the number of active elements is not the same as the sum over all // processors of the number of active elements per processor, which means // there must be some unpartitioned objects out there. if (global_index_map.size() != _global_index_by_pid_map.size()) libmesh_error_msg("ERROR: ParmetisPartitioner cannot handle unpartitioned objects!"); } // Finally, we need to initialize the vertex (partition) weights and the initial subdomain // mapping. The subdomain mapping will be independent of the processor mapping, and is // defined by a simple mapping of the global indices we just found. { std::vector<dof_id_type> subdomain_bounds(mesh.n_processors()); const dof_id_type first_local_elem = _pmetis->vtxdist[mesh.processor_id()]; for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { dof_id_type tgt_subdomain_size = 0; // watch out for the case that n_subdomains < n_processors if (pid < static_cast<unsigned int>(_pmetis->nparts)) { tgt_subdomain_size = n_active_elem/std::min (cast_int<Parmetis::idx_t>(mesh.n_processors()), _pmetis->nparts); if (pid < n_active_elem%_pmetis->nparts) tgt_subdomain_size++; } if (pid == 0) subdomain_bounds[0] = tgt_subdomain_size; else subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size; } libmesh_assert_equal_to (subdomain_bounds.back(), n_active_elem); MeshBase::const_element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem *elem = *elem_it; libmesh_assert (_global_index_by_pid_map.count(elem->id())); const dof_id_type global_index_by_pid = _global_index_by_pid_map[elem->id()]; libmesh_assert_less (global_index_by_pid, n_active_elem); const dof_id_type local_index = global_index_by_pid - first_local_elem; libmesh_assert_less (local_index, n_active_local_elem); libmesh_assert_less (local_index, _pmetis->vwgt.size()); // TODO:[BSK] maybe there is a better weight? _pmetis->vwgt[local_index] = elem->n_nodes(); // find the subdomain this element belongs in libmesh_assert (global_index_map.count(elem->id())); const dof_id_type global_index = global_index_map[elem->id()]; libmesh_assert_less (global_index, subdomain_bounds.back()); const unsigned int subdomain_id = std::distance(subdomain_bounds.begin(), std::lower_bound(subdomain_bounds.begin(), subdomain_bounds.end(), global_index)); libmesh_assert_less (subdomain_id, static_cast<unsigned int>(_pmetis->nparts)); libmesh_assert_less (local_index, _pmetis->part.size()); _pmetis->part[local_index] = subdomain_id; } } }
PetscVector<T>& PetscVector<T>::operator = (const PetscVector<T>& v) { this->_restore_array(); v._restore_array(); libmesh_assert_equal_to (this->size(), v.size()); libmesh_assert_equal_to (this->local_size(), v.local_size()); libmesh_assert (v.closed()); PetscErrorCode ierr = 0; if (((this->type()==PARALLEL) && (v.type()==GHOSTED)) || ((this->type()==GHOSTED) && (v.type()==PARALLEL)) || ((this->type()==GHOSTED) && (v.type()==SERIAL)) || ((this->type()==SERIAL) && (v.type()==GHOSTED))) { /* Allow assignment of a ghosted to a parallel vector since this causes no difficulty. See discussion in libmesh-devel of June 24, 2010. */ ierr = VecCopy (v._vec, this->_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); } else { /* In all other cases, we assert that both vectors are of equal type. */ libmesh_assert_equal_to (this->_type, v._type); libmesh_assert (this->_global_to_local_map == v._global_to_local_map); if (v.size() != 0) { if(this->type() != GHOSTED) { ierr = VecCopy (v._vec, this->_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); } else { Vec loc_vec; Vec v_loc_vec; ierr = VecGhostGetLocalForm (_vec,&loc_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecGhostGetLocalForm (v._vec,&v_loc_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecCopy (v_loc_vec, loc_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecGhostRestoreLocalForm (v._vec,&v_loc_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecGhostRestoreLocalForm (_vec,&loc_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); } } } close(); return *this; }
int main(int argc, char** argv){ //initialize libMesh LibMeshInit init(argc, argv); //parameters GetPot infile("fem_system_params.in"); const Real global_tolerance = infile("global_tolerance", 0.); const unsigned int nelem_target = infile("n_elements", 400); const bool transient = infile("transient", true); const Real deltat = infile("deltat", 0.005); unsigned int n_timesteps = infile("n_timesteps", 1); //const unsigned int coarsegridsize = infile("coarsegridsize", 1); const unsigned int coarserefinements = infile("coarserefinements", 0); const unsigned int max_adaptivesteps = infile("max_adaptivesteps", 10); //const unsigned int dim = 2; #ifdef LIBMESH_HAVE_EXODUS_API const unsigned int write_interval = infile("write_interval", 5); #endif // Create a mesh, with dimension to be overridden later, distributed // across the default MPI communicator. Mesh mesh(init.comm()); GetPot infileForMesh("diff_convdiff_mprime.in"); std::string find_mesh_here = infileForMesh("divided_mesh","meep.exo"); mesh.read(find_mesh_here); //mesh.read("psiHF_mesh_1Dfused.xda"); // And an object to refine it MeshRefinement mesh_refinement(mesh); mesh_refinement.coarsen_by_parents() = true; mesh_refinement.absolute_global_tolerance() = global_tolerance; mesh_refinement.nelem_target() = nelem_target; mesh_refinement.refine_fraction() = 0.3; mesh_refinement.coarsen_fraction() = 0.3; mesh_refinement.coarsen_threshold() = 0.1; mesh_refinement.uniformly_refine(coarserefinements); // Print information about the mesh to the screen. mesh.print_info(); // Create an equation systems object. EquationSystems equation_systems (mesh); //name system Diff_ConvDiff_MprimeSys & system = equation_systems.add_system<Diff_ConvDiff_MprimeSys>("Diff_ConvDiff_MprimeSys"); //steady-state problem system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system)); libmesh_assert_equal_to (n_timesteps, 1); //DEBUG //std::string find_psiLF_here = "psiLF.xda"; //equation_systems.read(find_psiLF_here, READ, // EquationSystems::READ_HEADER | // EquationSystems::READ_DATA | // EquationSystems::READ_ADDITIONAL_DATA); //std::cout << "\n\n" << "DEBUG reading in " << find_psiLF_here << "\n\n"; //Real readin_L2 = system.calculate_norm(*system.solution, 0, L2); //std::cout << "Read in solution norm: "<< readin_L2 << std::endl << std::endl; //GMVIO(equation_systems.get_mesh()).write_equation_systems(std::string("right_back_out.gmv"), equation_systems); //DEBUG // Initialize the system equation_systems.init (); // Set the time stepping options system.deltat = deltat; //this is ignored for SteadySolver...right? // And the nonlinear solver options NewtonSolver *solver = new NewtonSolver(system); system.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver); solver->quiet = infile("solver_quiet", true); solver->verbose = !solver->quiet; solver->max_nonlinear_iterations = infile("max_nonlinear_iterations", 15); solver->relative_step_tolerance = infile("relative_step_tolerance", 1.e-3); solver->relative_residual_tolerance = infile("relative_residual_tolerance", 0.0); solver->absolute_residual_tolerance = infile("absolute_residual_tolerance", 0.0); // And the linear solver options solver->max_linear_iterations = infile("max_linear_iterations", 50000); solver->initial_linear_tolerance = infile("initial_linear_tolerance", 1.e-3); //FOR 1D DEBUG //read_initial_parameters(); //system.project_solution(initial_value, initial_grad, equation_systems.parameters); //finish_initialization(); #ifdef LIBMESH_HAVE_GMV //GMVIO(equation_systems.get_mesh()).write_equation_systems(std::string("psiHF_readin_1d.gmv"), equation_systems); #endif //equation_systems.write("psiLF_1D_fused.xda", WRITE, EquationSystems::WRITE_DATA | // EquationSystems::WRITE_ADDITIONAL_DATA); //mesh.write("psiLF_mesh_1Dfused.xda"); // Print information about the system to the screen. equation_systems.print_info(); //std::cout << "\n~~~~~~~~~~~~~~~~\n"; //DEBUG //system.assemble(); //DEBUG //std::cout << "\n~~~~~~~~~~~~~~~~\n"; //DEBUG //equation_systems.write("rhs.xda", WRITE, EquationSystems::WRITE_DATA | //DEBUG // EquationSystems::WRITE_ADDITIONAL_DATA); // Now we begin the timestep loop to compute the time-accurate // solution of the equations...not that this is transient, but eh, why not... for (unsigned int t_step=0; t_step != n_timesteps; ++t_step){ // A pretty update message std::cout << "\n\nSolving time step " << t_step << ", time = " << system.time << std::endl; // Adaptively solve the timestep unsigned int a_step = 0; for (; a_step != max_adaptivesteps; ++a_step) { system.solve(); system.postprocess(); ErrorVector error; AutoPtr<ErrorEstimator> error_estimator; // To solve to a tolerance in this problem we // need a better estimator than Kelly if (global_tolerance != 0.) { // We can't adapt to both a tolerance and a mesh // size at once libmesh_assert_equal_to (nelem_target, 0); UniformRefinementEstimator *u = new UniformRefinementEstimator; // The lid-driven cavity problem isn't in H1, so // lets estimate L2 error u->error_norm = L2; error_estimator.reset(u); } else { // If we aren't adapting to a tolerance we need a // target mesh size libmesh_assert_greater (nelem_target, 0); // Kelly is a lousy estimator to use for a problem // not in H1 - if we were doing more than a few // timesteps we'd need to turn off or limit the // maximum level of our adaptivity eventually error_estimator.reset(new KellyErrorEstimator); } // Calculate error std::vector<Real> weights(9,1.0); // based on u, v, p, c, their adjoints, and source parameter // Keep the same default norm type. std::vector<FEMNormType> norms(1, error_estimator->error_norm.type(0)); error_estimator->error_norm = SystemNorm(norms, weights); error_estimator->estimate_error(system, error); // Print out status at each adaptive step. Real global_error = error.l2_norm(); std::cout << "Adaptive step " << a_step << ": " << std::endl; if (global_tolerance != 0.) std::cout << "Global_error = " << global_error << std::endl; if (global_tolerance != 0.) std::cout << "Worst element error = " << error.maximum() << ", mean = " << error.mean() << std::endl; if (global_tolerance != 0.) { // If we've reached our desired tolerance, we // don't need any more adaptive steps if (global_error < global_tolerance) break; mesh_refinement.flag_elements_by_error_tolerance(error); } else { // If flag_elements_by_nelem_target returns true, this // should be our last adaptive step. if (mesh_refinement.flag_elements_by_nelem_target(error)) { mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); a_step = max_adaptivesteps; break; } } // Carry out the adaptive mesh refinement/coarsening mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); std::cout << "Refined mesh to " << mesh.n_active_elem() << " active elements and " << equation_systems.n_active_dofs() << " active dofs." << std::endl; } // Do one last solve if necessary if (a_step == max_adaptivesteps) { system.solve(); std::cout << "\n\n Residual L2 norm: " << system.calculate_norm(*system.rhs, L2) << "\n"; system.postprocess(); //DEBUG std::cout << " M_HF(psiLF): " << std::setprecision(17) << system.get_MHF_psiLF() << "\n"; std::cout << " I(psiLF): " << std::setprecision(17) << system.get_MLF_psiLF() << "\n"; } // Advance to the next timestep in a transient problem system.time_solver->advance_timestep(); #ifdef LIBMESH_HAVE_EXODUS_API // Write out this timestep if we're requested to if ((t_step+1)%write_interval == 0) { //std::ostringstream file_name; // We write the file in the ExodusII format. //file_name << "out_" // << std::setw(3) // << std::setfill('0') // << std::right // << t_step+1 // << ".e"; //ExodusII_IO(mesh).write_timestep(file_name.str(), ExodusII_IO(mesh).write_timestep("psiLF.exo", equation_systems, 1, /* This number indicates how many time steps are being written to the file */ system.time); mesh.write("psiLF_mesh.xda"); equation_systems.write("psiLF.xda", WRITE, EquationSystems::WRITE_DATA | EquationSystems::WRITE_ADDITIONAL_DATA); } #endif // #ifdef LIBMESH_HAVE_EXODUS_API } // All done. return 0; } //end main
void PetscVector<T>::localize (NumericVector<T>& v_local_in, const std::vector<numeric_index_type>& send_list) const { // FIXME: Workaround for a strange bug at large-scale. // If we have ghosting, PETSc lets us just copy the solution, and // doing so avoids a segfault? if (v_local_in.type() == GHOSTED && this->type() == PARALLEL) { v_local_in = *this; return; } // Normal code path begins here this->_restore_array(); // Make sure the NumericVector passed in is really a PetscVector PetscVector<T>* v_local = libmesh_cast_ptr<PetscVector<T>*>(&v_local_in); libmesh_assert(v_local); libmesh_assert_equal_to (v_local->size(), this->size()); libmesh_assert_less_equal (send_list.size(), v_local->size()); PetscErrorCode ierr=0; const numeric_index_type n_sl = send_list.size(); IS is; VecScatter scatter; std::vector<PetscInt> idx(n_sl + this->local_size()); for (numeric_index_type i=0; i<n_sl; i++) idx[i] = static_cast<PetscInt>(send_list[i]); for (numeric_index_type i = 0; i != this->local_size(); ++i) idx[n_sl+i] = i + this->first_local_index(); // Create the index set & scatter object if (idx.empty()) ierr = ISCreateLibMesh(libMesh::COMM_WORLD, n_sl+this->local_size(), PETSC_NULL, PETSC_USE_POINTER, &is); else ierr = ISCreateLibMesh(libMesh::COMM_WORLD, n_sl+this->local_size(), &idx[0], PETSC_USE_POINTER, &is); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecScatterCreate(_vec, is, v_local->_vec, is, &scatter); CHKERRABORT(libMesh::COMM_WORLD,ierr); // Perform the scatter #if PETSC_VERSION_LESS_THAN(2,3,3) ierr = VecScatterBegin(_vec, v_local->_vec, INSERT_VALUES, SCATTER_FORWARD, scatter); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecScatterEnd (_vec, v_local->_vec, INSERT_VALUES, SCATTER_FORWARD, scatter); CHKERRABORT(libMesh::COMM_WORLD,ierr); #else // API argument order change in PETSc 2.3.3 ierr = VecScatterBegin(scatter, _vec, v_local->_vec, INSERT_VALUES, SCATTER_FORWARD); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecScatterEnd (scatter, _vec, v_local->_vec, INSERT_VALUES, SCATTER_FORWARD); CHKERRABORT(libMesh::COMM_WORLD,ierr); #endif // Clean up ierr = LibMeshISDestroy (&is); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = LibMeshVecScatterDestroy(&scatter); CHKERRABORT(libMesh::COMM_WORLD,ierr); // Make sure ghost dofs are up to date if (v_local->type() == GHOSTED) v_local->close(); }
Real FE<1,LAGRANGE>::shape_deriv(const ElemType, const Order order, const unsigned int i, const unsigned int libmesh_dbg_var(j), const Point & p) { // only d()/dxi in 1D! libmesh_assert_equal_to (j, 0); const Real xi = p(0); switch (order) { // Lagrange linear shape function derivatives case FIRST: { libmesh_assert_less (i, 2); switch (i) { case 0: return -.5; case 1: return .5; default: libmesh_error_msg("Invalid shape function index i = " << i); } } // Lagrange quadratic shape function derivatives case SECOND: { libmesh_assert_less (i, 3); switch (i) { case 0: return xi-.5; case 1: return xi+.5; case 2: return -2.*xi; default: libmesh_error_msg("Invalid shape function index i = " << i); } } // Lagrange cubic shape function derivatives case THIRD: { libmesh_assert_less (i, 4); switch (i) { case 0: return -9./16.*(3.*xi*xi-2.*xi-1./9.); case 1: return -9./16.*(-3.*xi*xi-2.*xi+1./9.); case 2: return 27./16.*(3.*xi*xi-2./3.*xi-1.); case 3: return 27./16.*(-3.*xi*xi-2./3.*xi+1.); default: libmesh_error_msg("Invalid shape function index i = " << i); } } default: libmesh_error_msg("ERROR: Unsupported polynomial order = " << order); } libmesh_error_msg("We'll never get here!"); return 0.; }
//--------------------------------------------------------- // CentroidPartitioner methods void CentroidPartitioner::_do_partition (MeshBase& mesh, const unsigned int n) { // Check for an easy return if (n == 1) { this->single_partition (mesh); return; } // Possibly reconstruct centroids if (mesh.n_elem() != _elem_centroids.size()) this->compute_centroids (mesh); switch (this->sort_method()) { case X: { std::sort(_elem_centroids.begin(), _elem_centroids.end(), CentroidPartitioner::sort_x); break; } case Y: { std::sort(_elem_centroids.begin(), _elem_centroids.end(), CentroidPartitioner::sort_y); break; } case Z: { std::sort(_elem_centroids.begin(), _elem_centroids.end(), CentroidPartitioner::sort_z); break; } case RADIAL: { std::sort(_elem_centroids.begin(), _elem_centroids.end(), CentroidPartitioner::sort_radial); break; } default: libmesh_error(); } // Make sure the user has not handed us an // invalid number of partitions. libmesh_assert_greater (n, 0); // the number of elements, e.g. 1000 const dof_id_type n_elem = mesh.n_elem(); // the number of elements per processor, e.g 400 const dof_id_type target_size = n_elem / n; // Make sure the mesh hasn't changed since the // last time we computed the centroids. libmesh_assert_equal_to (mesh.n_elem(), _elem_centroids.size()); for (dof_id_type i=0; i<n_elem; i++) { Elem* elem = _elem_centroids[i].second; elem->processor_id() = std::min (libmesh_cast_int<processor_id_type>(i / target_size), libmesh_cast_int<processor_id_type>(n-1)); } }
void UNVIO::read_implementation (std::istream& in_stream) { // clear everything, so that // we can start from scratch this->clear (); // Keep track of what kinds of elements this file contains elems_of_dimension.clear(); elems_of_dimension.resize(4, false); // Note that we read this file // @e twice. First time to // detect the number of nodes // and elements (and possible // conversion tasks like D_to_e) // and the order of datasets // (nodes first, then elements, // or the other way around), // and second to do the actual // read. std::vector<std::string> order_of_datasets; order_of_datasets.reserve(2); { // the first time we read the file, // merely to obtain overall info if ( !in_stream.good() ) { libMesh::err << "ERROR: Input file not good." << std::endl; libmesh_error(); } // Count nodes and elements, then let // other methods read the element and // node data. Also remember which // dataset comes first: nodes or elements if (this->verbose()) libMesh::out << " Counting nodes and elements" << std::endl; // bool reached_eof = false; bool found_node = false; bool found_elem = false; std::string olds, news; while (in_stream.good()) { in_stream >> olds >> news; // a "-1" followed by a number means the beginning of a dataset // stop combing at the end of the file while ( ((olds != "-1") || (news == "-1") ) && !in_stream.eof() ) { olds = news; in_stream >> news; } // if (in_stream.eof()) // { // reached_eof = true; // break; // } // if beginning of dataset, buffer it in // temp_buffer, if desired if (news == _label_dataset_nodes) { found_node = true; order_of_datasets.push_back (_label_dataset_nodes); this->count_nodes (in_stream); // we can save some time scanning the file // when we know we already have everything // we want if (found_elem) break; } else if (news == _label_dataset_elements) { found_elem = true; order_of_datasets.push_back (_label_dataset_elements); this->count_elements (in_stream); // we can save some time scanning the file // when we know we already have everything // we want if (found_node) break; } } // Here we should better have found // the datasets for nodes and elements, // otherwise the unv files is bad! if (!found_elem) { libMesh::err << "ERROR: Could not find elements!" << std::endl; libmesh_error(); } if (!found_node) { libMesh::err << "ERROR: Could not find nodes!" << std::endl; libmesh_error(); } // Don't close, just seek to the beginning in_stream.seekg(0, std::ios::beg); if (!in_stream.good() ) { libMesh::err << "ERROR: Cannot re-read input file." << std::endl; libmesh_error(); } } // We finished scanning the file, // and our member data // \p this->_n_nodes, // \p this->_n_elements, // \p this->_need_D_to_e // should be properly initialized. { // Read the datasets in the order that // we already know libmesh_assert_equal_to (order_of_datasets.size(), 2); for (unsigned int ds=0; ds < order_of_datasets.size(); ds++) { if (order_of_datasets[ds] == _label_dataset_nodes) this->node_in (in_stream); else if (order_of_datasets[ds] == _label_dataset_elements) this->element_in (in_stream); else libmesh_error(); } // Set the mesh dimension to the largest encountered for an element for (unsigned int i=0; i!=4; ++i) if (elems_of_dimension[i]) MeshInput<MeshBase>::mesh().set_mesh_dimension(i); #if LIBMESH_DIM < 3 if (MeshInput<MeshBase>::mesh().mesh_dimension() > LIBMESH_DIM) { libMesh::err << "Cannot open dimension " << MeshInput<MeshBase>::mesh().mesh_dimension() << " mesh file when configured without " << MeshInput<MeshBase>::mesh().mesh_dimension() << "D support." << std::endl; libmesh_error(); } #endif // tell the MeshData object that we are finished // reading data this->_mesh_data.close_foreign_id_maps (); if (this->verbose()) libMesh::out << " Finished." << std::endl << std::endl; } // save memory this->_assign_nodes.clear(); this->_ds_position.clear(); }
Real FE<3,XYZ>::shape_second_deriv(const Elem* elem, const Order libmesh_dbg_var(order), const unsigned int i, const unsigned int j, const Point& point_in) { #if LIBMESH_DIM == 3 libmesh_assert(elem); libmesh_assert_less (j, 6); // Only recompute the centroid if the element // has changed from the last one we computed. // This avoids repeated centroid calculations // when called in succession with the same element. if (elem->id() != old_elem_id) { centroid = elem->centroid(); old_elem_id = elem->id(); max_distance = Point(0.,0.,0.); for (unsigned int p = 0; p < elem->n_nodes(); p++) for (unsigned int d = 0; d < 3; d++) { const Real distance = std::abs(centroid(d) - elem->point(p)(d)); max_distance(d) = std::max(distance, max_distance(d)); } } // Using static globals for old_elem_id, etc. will fail // horribly with more than one thread. libmesh_assert_equal_to (libMesh::n_threads(), 1); const Real x = point_in(0); const Real y = point_in(1); const Real z = point_in(2); const Real xc = centroid(0); const Real yc = centroid(1); const Real zc = centroid(2); const Real distx = max_distance(0); const Real disty = max_distance(1); const Real distz = max_distance(2); const Real dx = (x - xc)/distx; const Real dy = (y - yc)/disty; const Real dz = (z - zc)/distz; const Real dist2x = pow(distx,2.); const Real dist2y = pow(disty,2.); const Real dist2z = pow(distz,2.); const Real distxy = distx * disty; const Real distxz = distx * distz; const Real distyz = disty * distz; #ifndef NDEBUG // totalorder is only used in the assertion below, so // we avoid declaring it when asserts are not active. const unsigned int totalorder = static_cast<Order>(order + elem->p_level()); #endif libmesh_assert_less (i, (static_cast<unsigned int>(totalorder)+1)* (static_cast<unsigned int>(totalorder)+2)* (static_cast<unsigned int>(totalorder)+3)/6); // monomials. since they are hierarchic we only need one case block. switch (j) { // d^2()/dx^2 case 0: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: return 2./dist2x; case 5: case 6: case 7: case 8: case 9: return 0.; // cubic case 10: return 6.*dx/dist2x; case 11: return 2.*dy/dist2x; case 12: case 13: return 0.; case 14: return 2.*dz/dist2x; case 15: case 16: case 17: case 18: case 19: return 0.; // quartics case 20: return 12.*dx*dx/dist2x; case 21: return 6.*dx*dy/dist2x; case 22: return 2.*dy*dy/dist2x; case 23: case 24: return 0.; case 25: return 6.*dx*dz/dist2x; case 26: return 2.*dy*dz/dist2x; case 27: case 28: return 0.; case 29: return 2.*dz*dz/dist2x; case 30: case 31: case 32: case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nx * (nx - 1); for (unsigned int index=2; index < nx; index++) val *= dx; for (unsigned int index=0; index != ny; index++) val *= dy; for (unsigned int index=0; index != nz; index++) val *= dz; return val/dist2x; } } // d^2()/dxdy case 1: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: return 0.; case 5: return 1./distxy; case 6: case 7: case 8: case 9: return 0.; // cubic case 10: return 0.; case 11: return 2.*dx/distxy; case 12: return 2.*dy/distxy; case 13: case 14: return 0.; case 15: return dz/distxy; case 16: case 17: case 18: case 19: return 0.; // quartics case 20: return 0.; case 21: return 3.*dx*dx/distxy; case 22: return 4.*dx*dy/distxy; case 23: return 3.*dy*dy/distxy; case 24: case 25: return 0.; case 26: return 2.*dx*dz/distxy; case 27: return 2.*dy*dz/distxy; case 28: case 29: return 0.; case 30: return dz*dz/distxy; case 31: case 32: case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nx * ny; for (unsigned int index=1; index < nx; index++) val *= dx; for (unsigned int index=1; index < ny; index++) val *= dy; for (unsigned int index=0; index != nz; index++) val *= dz; return val/distxy; } } // d^2()/dy^2 case 2: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: return 0.; case 6: return 2./dist2y; case 7: case 8: case 9: return 0.; // cubic case 10: case 11: return 0.; case 12: return 2.*dx/dist2y; case 13: return 6.*dy/dist2y; case 14: case 15: return 0.; case 16: return 2.*dz/dist2y; case 17: case 18: case 19: return 0.; // quartics case 20: case 21: return 0.; case 22: return 2.*dx*dx/dist2y; case 23: return 6.*dx*dy/dist2y; case 24: return 12.*dy*dy/dist2y; case 25: case 26: return 0.; case 27: return 2.*dx*dz/dist2y; case 28: return 6.*dy*dz/dist2y; case 29: case 30: return 0.; case 31: return 2.*dz*dz/dist2y; case 32: case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = ny * (ny - 1); for (unsigned int index=0; index != nx; index++) val *= dx; for (unsigned int index=2; index < ny; index++) val *= dy; for (unsigned int index=0; index != nz; index++) val *= dz; return val/dist2y; } } // d^2()/dxdz case 3: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: case 6: return 0.; case 7: return 1./distxz; case 8: case 9: return 0.; // cubic case 10: case 11: case 12: case 13: return 0.; case 14: return 2.*dx/distxz; case 15: return dy/distxz; case 16: return 0.; case 17: return 2.*dz/distxz; case 18: case 19: return 0.; // quartics case 20: case 21: case 22: case 23: case 24: return 0.; case 25: return 3.*dx*dx/distxz; case 26: return 2.*dx*dy/distxz; case 27: return dy*dy/distxz; case 28: return 0.; case 29: return 4.*dx*dz/distxz; case 30: return 2.*dy*dz/distxz; case 31: return 0.; case 32: return 3.*dz*dz/distxz; case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nx * nz; for (unsigned int index=1; index < nx; index++) val *= dx; for (unsigned int index=0; index != ny; index++) val *= dy; for (unsigned int index=1; index < nz; index++) val *= dz; return val/distxz; } } // d^2()/dydz case 4: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: case 6: case 7: return 0.; case 8: return 1./distyz; case 9: return 0.; // cubic case 10: case 11: case 12: case 13: case 14: return 0.; case 15: return dx/distyz; case 16: return 2.*dy/distyz; case 17: return 0.; case 18: return 2.*dz/distyz; case 19: return 0.; // quartics case 20: case 21: case 22: case 23: case 24: case 25: return 0.; case 26: return dx*dx/distyz; case 27: return 2.*dx*dy/distyz; case 28: return 3.*dy*dy/distyz; case 29: return 0.; case 30: return 2.*dx*dz/distyz; case 31: return 4.*dy*dz/distyz; case 32: return 0.; case 33: return 3.*dz*dz/distyz; case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = ny * nz; for (unsigned int index=0; index != nx; index++) val *= dx; for (unsigned int index=1; index < ny; index++) val *= dy; for (unsigned int index=1; index < nz; index++) val *= dz; return val/distyz; } } // d^2()/dz^2 case 5: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: case 6: case 7: case 8: return 0.; case 9: return 2./dist2z; // cubic case 10: case 11: case 12: case 13: case 14: case 15: case 16: return 0.; case 17: return 2.*dx/dist2z; case 18: return 2.*dy/dist2z; case 19: return 6.*dz/dist2z; // quartics case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: return 0.; case 29: return 2.*dx*dx/dist2z; case 30: return 2.*dx*dy/dist2z; case 31: return 2.*dy*dy/dist2z; case 32: return 6.*dx*dz/dist2z; case 33: return 6.*dy*dz/dist2z; case 34: return 12.*dz*dz/dist2z; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nz * (nz - 1); for (unsigned int index=0; index != nx; index++) val *= dx; for (unsigned int index=0; index != ny; index++) val *= dy; for (unsigned int index=2; index < nz; index++) val *= dz; return val/dist2z; } } default: libmesh_error(); } #endif libmesh_error(); return 0.; }
void InfFE<Dim,T_radial,T_base>::init_face_shape_functions(const std::vector<Point>&, const Elem* inf_side) { libmesh_assert(inf_side); // Currently, this makes only sense in 3-D! libmesh_assert_equal_to (Dim, 3); // Initialiize the radial shape functions this->init_radial_shape_functions(inf_side); // Initialize the base shape functions this->update_base_elem(inf_side); // Initialize the base quadratur rule base_qrule->init(base_elem->type(), inf_side->p_level()); // base_fe still corresponds to the (dim-1)-dimensional base of the InfFE object, // so update the fe_base. { libmesh_assert_equal_to (Dim, 3); AutoPtr<FEBase> ap_fb(FEBase::build(Dim-2, this->fe_type)); delete base_fe; base_fe = ap_fb.release(); base_fe->attach_quadrature_rule(base_qrule); } // initialize the shape functions on the base base_fe->init_base_shape_functions(base_fe->qrule->get_points(), base_elem); // the number of quadrature points const unsigned int n_radial_qp = libmesh_cast_int<unsigned int>(som.size()); const unsigned int n_base_qp = base_qrule->n_points(); const unsigned int n_total_qp = n_radial_qp * n_base_qp; // the quadratur weigths _total_qrule_weights.resize(n_total_qp); // now inite the shapes for boundary work { // The element type and order to use in the base map const Order base_mapping_order ( base_elem->default_order() ); const ElemType base_mapping_elem_type ( base_elem->type() ); // the number of mapping shape functions // (Lagrange shape functions are used for mapping in the base) const unsigned int n_radial_mapping_sf = libmesh_cast_int<unsigned int>(radial_map.size()); const unsigned int n_base_mapping_shape_functions = Base::n_base_mapping_sf(base_mapping_elem_type, base_mapping_order); const unsigned int n_total_mapping_shape_functions = n_radial_mapping_sf * n_base_mapping_shape_functions; // initialize the node and shape numbering maps { _radial_node_index.resize (n_total_mapping_shape_functions); _base_node_index.resize (n_total_mapping_shape_functions); const ElemType inf_face_elem_type (inf_side->type()); // fill the node index map for (unsigned int n=0; n<n_total_mapping_shape_functions; n++) { compute_node_indices (inf_face_elem_type, n, _base_node_index[n], _radial_node_index[n]); libmesh_assert_less (_base_node_index[n], n_base_mapping_shape_functions); libmesh_assert_less (_radial_node_index[n], n_radial_mapping_sf); } } // rezise map data fields { std::vector<std::vector<Real> >& psi_map = this->_fe_map->get_psi(); std::vector<std::vector<Real> >& dpsidxi_map = this->_fe_map->get_dpsidxi(); std::vector<std::vector<Real> >& d2psidxi2_map = this->_fe_map->get_d2psidxi2(); psi_map.resize (n_total_mapping_shape_functions); dpsidxi_map.resize (n_total_mapping_shape_functions); d2psidxi2_map.resize (n_total_mapping_shape_functions); // if (Dim == 3) { std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta(); std::vector<std::vector<Real> >& d2psidxideta_map = this->_fe_map->get_d2psidxideta(); std::vector<std::vector<Real> >& d2psideta2_map = this->_fe_map->get_d2psideta2(); dpsideta_map.resize (n_total_mapping_shape_functions); d2psidxideta_map.resize (n_total_mapping_shape_functions); d2psideta2_map.resize (n_total_mapping_shape_functions); } for (unsigned int i=0; i<n_total_mapping_shape_functions; i++) { psi_map[i].resize (n_total_qp); dpsidxi_map[i].resize (n_total_qp); d2psidxi2_map[i].resize (n_total_qp); // if (Dim == 3) { std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta(); std::vector<std::vector<Real> >& d2psidxideta_map = this->_fe_map->get_d2psidxideta(); std::vector<std::vector<Real> >& d2psideta2_map = this->_fe_map->get_d2psideta2(); dpsideta_map[i].resize (n_total_qp); d2psidxideta_map[i].resize (n_total_qp); d2psideta2_map[i].resize (n_total_qp); } } } // compute shape maps { const std::vector<std::vector<Real> >& S_map = (base_fe->get_fe_map()).get_phi_map(); const std::vector<std::vector<Real> >& Ss_map = (base_fe->get_fe_map()).get_dphidxi_map(); std::vector<std::vector<Real> >& psi_map = this->_fe_map->get_psi(); std::vector<std::vector<Real> >& dpsidxi_map = this->_fe_map->get_dpsidxi(); std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta(); for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qp's for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qp's for (unsigned int ti=0; ti<n_total_mapping_shape_functions; ti++) // over all mapping shapes { // let the index vectors take care of selecting the appropriate base/radial mapping shape const unsigned int bi = _base_node_index [ti]; const unsigned int ri = _radial_node_index[ti]; psi_map [ti][bp+rp*n_base_qp] = S_map [bi][bp] * radial_map [ri][rp]; dpsidxi_map [ti][bp+rp*n_base_qp] = Ss_map[bi][bp] * radial_map [ri][rp]; dpsideta_map [ti][bp+rp*n_base_qp] = S_map [bi][bp] * dradialdv_map[ri][rp]; // second derivatives are not implemented for infinite elements // d2psidxi2_map [ti][bp+rp*n_base_qp] = 0.; // d2psidxideta_map [ti][bp+rp*n_base_qp] = 0.; // d2psideta2_map [ti][bp+rp*n_base_qp] = 0.; } } } // quadrature rule weights { const std::vector<Real>& radial_qw = radial_qrule->get_weights(); const std::vector<Real>& base_qw = base_qrule->get_weights(); libmesh_assert_equal_to (radial_qw.size(), n_radial_qp); libmesh_assert_equal_to (base_qw.size(), n_base_qp); for (unsigned int rp=0; rp<n_radial_qp; rp++) for (unsigned int bp=0; bp<n_base_qp; bp++) { _total_qrule_weights[ bp+rp*n_base_qp ] = radial_qw[rp] * base_qw[bp]; } } }
void EnsightIO::write_scalar_ascii(const std::string &sys, const std::string &var_name) { std::ostringstream scl_file; scl_file << _ensight_file_name << "_" << var_name << ".scl"; scl_file << std::setw(3) << std::setprecision(0) << std::setfill('0') << std::right << _time_steps.size()-1; FILE * fout = fopen(scl_file.str().c_str(),"w"); fprintf(fout,"Per node scalar value\n"); fprintf(fout,"part\n"); fprintf(fout,"%10d\n",1); fprintf(fout,"coordinates\n"); const MeshBase& the_mesh = MeshOutput<MeshBase>::mesh(); const unsigned int dim = the_mesh.mesh_dimension(); const System &system = _equation_systems.get_system(sys); const DofMap& dof_map = system.get_dof_map(); int var = system.variable_number(var_name); std::vector<dof_id_type> dof_indices; std::vector<dof_id_type> dof_indices_scl; // Now we will loop over all the elements in the mesh. MeshBase::const_element_iterator el = the_mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = the_mesh.active_local_elements_end(); typedef std::map<int,Real> map_local_soln; typedef map_local_soln::iterator local_soln_iterator; map_local_soln local_soln; std::vector<Number> elem_soln; std::vector<Number> nodal_soln; for ( ; el != end_el ; ++el){ const Elem* elem = *el; const FEType& fe_type = system.variable_type(var); dof_map.dof_indices (elem, dof_indices); dof_map.dof_indices (elem, dof_indices_scl, var); elem_soln.resize(dof_indices_scl.size()); for (unsigned int i = 0; i < dof_indices_scl.size(); i++) elem_soln[i] = system.current_solution(dof_indices_scl[i]); FEInterface::nodal_soln (dim,fe_type, elem, elem_soln, nodal_soln); libmesh_assert_equal_to (nodal_soln.size(), elem->n_nodes()); #ifdef LIBMESH_USE_COMPLEX_NUMBERS libMesh::err << "Complex-valued Ensight output not yet supported" << std::endl; libmesh_not_implemented(); #endif for (unsigned int n=0; n<elem->n_nodes(); n++) local_soln[elem->node(n)] = libmesh_real(nodal_soln[n]); } local_soln_iterator sol = local_soln.begin(); const local_soln_iterator sol_end = local_soln.end(); for(; sol != sol_end; ++sol) fprintf(fout,"%12.5e\n",static_cast<double>((*sol).second)); fclose(fout); }
void Partitioner::set_node_processor_ids(MeshBase & mesh) { START_LOG("set_node_processor_ids()","Partitioner"); // This function must be run on all processors at once libmesh_parallel_only(mesh.comm()); // If we have any unpartitioned elements at this // stage there is a problem libmesh_assert (MeshTools::n_elem(mesh.unpartitioned_elements_begin(), mesh.unpartitioned_elements_end()) == 0); // const dof_id_type orig_n_local_nodes = mesh.n_local_nodes(); // libMesh::err << "[" << mesh.processor_id() << "]: orig_n_local_nodes=" // << orig_n_local_nodes << std::endl; // Build up request sets. Each node is currently owned by a processor because // it is connected to an element owned by that processor. However, during the // repartitioning phase that element may have been assigned a new processor id, but // it is still resident on the original processor. We need to know where to look // for new ids before assigning new ids, otherwise we may be asking the wrong processors // for the wrong information. // // The only remaining issue is what to do with unpartitioned nodes. Since they are required // to live on all processors we can simply rely on ourselves to number them properly. std::vector<std::vector<dof_id_type> > requested_node_ids(mesh.n_processors()); // Loop over all the nodes, count the ones on each processor. We can skip ourself std::vector<dof_id_type> ghost_nodes_from_proc(mesh.n_processors(), 0); MeshBase::node_iterator node_it = mesh.nodes_begin(); const MeshBase::node_iterator node_end = mesh.nodes_end(); for (; node_it != node_end; ++node_it) { Node * node = *node_it; libmesh_assert(node); const processor_id_type current_pid = node->processor_id(); if (current_pid != mesh.processor_id() && current_pid != DofObject::invalid_processor_id) { libmesh_assert_less (current_pid, ghost_nodes_from_proc.size()); ghost_nodes_from_proc[current_pid]++; } } // We know how many objects live on each processor, so reserve() // space for each. for (processor_id_type pid=0; pid != mesh.n_processors(); ++pid) requested_node_ids[pid].reserve(ghost_nodes_from_proc[pid]); // We need to get the new pid for each node from the processor // which *currently* owns the node. We can safely skip ourself for (node_it = mesh.nodes_begin(); node_it != node_end; ++node_it) { Node * node = *node_it; libmesh_assert(node); const processor_id_type current_pid = node->processor_id(); if (current_pid != mesh.processor_id() && current_pid != DofObject::invalid_processor_id) { libmesh_assert_less (current_pid, requested_node_ids.size()); libmesh_assert_less (requested_node_ids[current_pid].size(), ghost_nodes_from_proc[current_pid]); requested_node_ids[current_pid].push_back(node->id()); } // Unset any previously-set node processor ids node->invalidate_processor_id(); } // Loop over all the active elements MeshBase::element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = mesh.active_elements_end(); for ( ; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; libmesh_assert(elem); libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id); // For each node, set the processor ID to the min of // its current value and this Element's processor id. // // TODO: we would probably get better parallel partitioning if // we did something like "min for even numbered nodes, max for // odd numbered". We'd need to be careful about how that would // affect solution ordering for I/O, though. for (unsigned int n=0; n<elem->n_nodes(); ++n) elem->get_node(n)->processor_id() = std::min(elem->get_node(n)->processor_id(), elem->processor_id()); } // And loop over the subactive elements, but don't reassign // nodes that are already active on another processor. MeshBase::element_iterator sub_it = mesh.subactive_elements_begin(); const MeshBase::element_iterator sub_end = mesh.subactive_elements_end(); for ( ; sub_it != sub_end; ++sub_it) { Elem * elem = *sub_it; libmesh_assert(elem); libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id); for (unsigned int n=0; n<elem->n_nodes(); ++n) if (elem->get_node(n)->processor_id() == DofObject::invalid_processor_id) elem->get_node(n)->processor_id() = elem->processor_id(); } // Same for the inactive elements -- we will have already gotten most of these // nodes, *except* for the case of a parent with a subset of children which are // ghost elements. In that case some of the parent nodes will not have been // properly handled yet MeshBase::element_iterator not_it = mesh.not_active_elements_begin(); const MeshBase::element_iterator not_end = mesh.not_active_elements_end(); for ( ; not_it != not_end; ++not_it) { Elem * elem = *not_it; libmesh_assert(elem); libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id); for (unsigned int n=0; n<elem->n_nodes(); ++n) if (elem->get_node(n)->processor_id() == DofObject::invalid_processor_id) elem->get_node(n)->processor_id() = elem->processor_id(); } // We can't assert that all nodes are connected to elements, because // a ParallelMesh with NodeConstraints might have pulled in some // remote nodes solely for evaluating those constraints. // MeshTools::libmesh_assert_connected_nodes(mesh); // For such nodes, we'll do a sanity check later when making sure // that we successfully reset their processor ids to something // valid. // Next set node ids from other processors, excluding self for (processor_id_type p=1; p != mesh.n_processors(); ++p) { // Trade my requests with processor procup and procdown processor_id_type procup = cast_int<processor_id_type> ((mesh.processor_id() + p) % mesh.n_processors()); processor_id_type procdown = cast_int<processor_id_type> ((mesh.n_processors() + mesh.processor_id() - p) % mesh.n_processors()); std::vector<dof_id_type> request_to_fill; mesh.comm().send_receive(procup, requested_node_ids[procup], procdown, request_to_fill); // Fill those requests in-place for (std::size_t i=0; i != request_to_fill.size(); ++i) { Node * node = mesh.node_ptr(request_to_fill[i]); libmesh_assert(node); const processor_id_type new_pid = node->processor_id(); // We may have an invalid processor_id() on nodes that have been // "detatched" from coarsened-away elements but that have not yet // themselves been removed. // libmesh_assert_not_equal_to (new_pid, DofObject::invalid_processor_id); // libmesh_assert_less (new_pid, mesh.n_partitions()); // this is the correct test -- request_to_fill[i] = new_pid; // the number of partitions may } // not equal the number of processors // Trade back the results std::vector<dof_id_type> filled_request; mesh.comm().send_receive(procdown, request_to_fill, procup, filled_request); libmesh_assert_equal_to (filled_request.size(), requested_node_ids[procup].size()); // And copy the id changes we've now been informed of for (std::size_t i=0; i != filled_request.size(); ++i) { Node * node = mesh.node_ptr(requested_node_ids[procup][i]); libmesh_assert(node); // this is the correct test -- the number of partitions may // not equal the number of processors // But: we may have an invalid processor_id() on nodes that // have been "detatched" from coarsened-away elements but // that have not yet themselves been removed. // libmesh_assert_less (filled_request[i], mesh.n_partitions()); node->processor_id(cast_int<processor_id_type>(filled_request[i])); } } #ifdef DEBUG MeshTools::libmesh_assert_valid_procids<Node>(mesh); #endif STOP_LOG("set_node_processor_ids()","Partitioner"); }
bool TreeNode<N>::insert (const Elem * elem) { libmesh_assert(elem); // We first want to find the corners of the cuboid surrounding the cell. const BoundingBox bbox = elem->loose_bounding_box(); // Next, find out whether this cuboid has got non-empty intersection // with the bounding box of the current tree node. // // If not, we should not care about this element. if (!this->bounding_box.intersects(bbox)) return false; // Only add the element if we are active if (this->active()) { elements.push_back (elem); #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS // flag indicating this node contains // infinite elements if (elem->infinite()) this->contains_ifems = true; #endif unsigned int element_count = cast_int<unsigned int>(elements.size()); if (!mesh.get_count_lower_dim_elems_in_point_locator()) { const std::set<unsigned char> & elem_dimensions = mesh.elem_dimensions(); if (elem_dimensions.size() > 1) { element_count = 0; unsigned char highest_dim_elem = *elem_dimensions.rbegin(); for (std::size_t i=0; i<elements.size(); i++) { if (elements[i]->dim() == highest_dim_elem) { element_count++; } } } } // Refine ourself if we reach the target bin size for a TreeNode. if (element_count == tgt_bin_size) this->refine(); return true; } // If we are not active simply pass the element along to // our children libmesh_assert_equal_to (children.size(), N); bool was_inserted = false; for (unsigned int c=0; c<N; c++) if (children[c]->insert (elem)) was_inserted = true; return was_inserted; }