void MaterialPropertyStorage::restrictStatefulProps( const std::vector<std::pair<unsigned int, QpMap>> & coarsening_map, const std::vector<const Elem *> & coarsened_element_children, QBase & qrule, QBase & qrule_face, MaterialData & material_data, const Elem & elem, int input_side) { unsigned int side; bool doing_a_side = input_side != -1; unsigned int n_qpoints = 0; if (!doing_a_side) { side = 0; // Use 0 for the elem n_qpoints = qrule.n_points(); } else { side = input_side; n_qpoints = qrule_face.n_points(); } initProps(material_data, elem, side, n_qpoints); // Copy from the child stateful properties for (unsigned int qp = 0; qp < coarsening_map.size(); qp++) { const std::pair<unsigned int, QpMap> & qp_pair = coarsening_map[qp]; unsigned int child = qp_pair.first; mooseAssert(child < coarsened_element_children.size(), "Coarsened element children vector not initialized"); const Elem * child_elem = coarsened_element_children[child]; const QpMap & qp_map = qp_pair.second; for (unsigned int i = 0; i < _stateful_prop_id_to_prop_id.size(); ++i) { mooseAssert(props().contains(child_elem), "Child element pointer is not in the MaterialProps data structure"); PropertyValue * child_property = props(child_elem, side)[i]; PropertyValue * parent_property = props(&elem, side)[i]; parent_property->qpCopy(qp, child_property, qp_map._to); propsOld(&elem, side)[i]->qpCopy(qp, propsOld(child_elem, side)[i], qp_map._to); if (hasOlderProperties()) propsOlder(&elem, side)[i]->qpCopy(qp, propsOlder(child_elem, side)[i], qp_map._to); } } }
void MaxQpsThread::operator() (const ConstElemRange & range) { ParallelUniqueId puid; _tid = puid.id; // For short circuiting reinit std::set<ElemType> seen_it; for (ConstElemRange::const_iterator elem_it = range.begin() ; elem_it != range.end(); ++elem_it) { const Elem * elem = *elem_it; // Only reinit if the element type has not previously been seen if (seen_it.insert(elem->type()).second) { FEType fe_type(FIRST, LAGRANGE); unsigned int dim = elem->dim(); unsigned int side = 0; // we assume that any element will have at least one side ;) // We cannot mess with the FE objects in Assembly, because we might need to request second derivatives // later on. If we used them, we'd call reinit on them, thus making the call to request second // derivatives harmful (i.e. leading to segfaults/asserts). Thus, we have to use a locally allocated object here. FEBase * fe = FEBase::build(dim, fe_type).release(); // figure out the number of qps for volume QBase * qrule = QBase::build(_qtype, dim, _order).release(); fe->attach_quadrature_rule(qrule); fe->reinit(elem); if (qrule->n_points() > _max) _max = qrule->n_points(); delete qrule; // figure out the number of qps for the face // NOTE: user might specify higher order rule for faces, thus possibly ending up with more qps than in the volume QBase * qrule_face = QBase::build(_qtype, dim - 1, _face_order).release(); fe->attach_quadrature_rule(qrule_face); fe->reinit(elem, side); if (qrule_face->n_points() > _max) _max = qrule_face->n_points(); delete qrule_face; delete fe; } } }
void QBase::tensor_product_prism(const QBase& q1D, const QBase& q2D) { const unsigned int n_points1D = q1D.n_points(); const unsigned int n_points2D = q2D.n_points(); _points.resize (n_points1D * n_points2D); _weights.resize (n_points1D * n_points2D); unsigned int qp=0; for (unsigned int j=0; j<n_points1D; j++) for (unsigned int i=0; i<n_points2D; i++) { _points[qp](0) = q2D.qp(i)(0); _points[qp](1) = q2D.qp(i)(1); _points[qp](2) = q1D.qp(j)(0); _weights[qp] = q2D.w(i) * q1D.w(j); qp++; } }
void QBase::tensor_product_quad(const QBase& q1D) { const unsigned int n_points = q1D.n_points(); _points.resize(n_points * n_points); _weights.resize(n_points * n_points); unsigned int qp=0; for (unsigned int j=0; j<n_points; j++) for (unsigned int i=0; i<n_points; i++) { _points[qp](0) = q1D.qp(i)(0); _points[qp](1) = q1D.qp(j)(0); _weights[qp] = q1D.w(i)*q1D.w(j); qp++; } }
void QBase::tensor_product_quad(const QBase& q1D) { const unsigned int np = q1D.n_points(); _points.resize(np * np); _weights.resize(np * np); unsigned int q=0; for (unsigned int j=0; j<np; j++) for (unsigned int i=0; i<np; i++) { _points[q](0) = q1D.qp(i)(0); _points[q](1) = q1D.qp(j)(0); _weights[q] = q1D.w(i)*q1D.w(j); q++; } }
void MaterialPropertyStorage::prolongStatefulProps(const std::vector<std::vector<QpMap> > & refinement_map, QBase & qrule, QBase & qrule_face, MaterialPropertyStorage & parent_material_props, MaterialData & child_material_data, const Elem & elem, const int input_parent_side, const int input_child, const int input_child_side) { mooseAssert(input_child != -1 || input_parent_side == input_child_side, "Invalid inputs!"); unsigned int n_qpoints = 0; // If we passed in -1 for these then we really need to store properties at 0 unsigned int parent_side = input_parent_side == -1 ? 0 : input_parent_side; unsigned int child_side = input_child_side == -1 ? 0 : input_child_side; if (input_child_side == -1) // Not doing side projection (ie, doing volume projection) n_qpoints = qrule.n_points(); else n_qpoints = qrule_face.n_points(); child_material_data.size(n_qpoints); unsigned int n_children = elem.n_children(); std::vector<unsigned int> children; if (input_child != -1) // Passed in a child explicitly children.push_back(input_child); else { children.resize(n_children); for (unsigned int child=0; child < n_children; child++) children[child] = child; } for (const auto & child : children) { // If we're not projecting an internal child side, but we are projecting sides, see if this child is on that side if (input_child == -1 && input_child_side != -1 && !elem.is_child_on_side(child, parent_side)) continue; const Elem * child_elem = elem.child(child); mooseAssert(child < refinement_map.size(), "Refinement_map vector not initialized"); const std::vector<QpMap> & child_map = refinement_map[child]; if (props()[child_elem][child_side].size() == 0) props()[child_elem][child_side].resize(_stateful_prop_id_to_prop_id.size()); if (propsOld()[child_elem][child_side].size() == 0) propsOld()[child_elem][child_side].resize(_stateful_prop_id_to_prop_id.size()); if (propsOlder()[child_elem][child_side].size() == 0) propsOlder()[child_elem][child_side].resize(_stateful_prop_id_to_prop_id.size()); // init properties (allocate memory. etc) for (unsigned int i=0; i < _stateful_prop_id_to_prop_id.size(); ++i) { // duplicate the stateful property in property storage (all three states - we will reuse the allocated memory there) // also allocating the right amount of memory, so we do not have to resize, etc. if (props()[child_elem][child_side][i] == NULL) props()[child_elem][child_side][i] = child_material_data.props()[ _stateful_prop_id_to_prop_id[i] ]->init(n_qpoints); if (propsOld()[child_elem][child_side][i] == NULL) propsOld()[child_elem][child_side][i] = child_material_data.propsOld()[ _stateful_prop_id_to_prop_id[i] ]->init(n_qpoints); if (hasOlderProperties()) if (propsOlder()[child_elem][child_side][i] == NULL) propsOlder()[child_elem][child_side][i] = child_material_data.propsOlder()[ _stateful_prop_id_to_prop_id[i] ]->init(n_qpoints); // Copy from the parent stateful properties for (unsigned int qp=0; qp<refinement_map[child].size(); qp++) { PropertyValue * child_property = props()[child_elem][child_side][i]; mooseAssert(props().contains(&elem), "Parent pointer is not in the MaterialProps data structure"); PropertyValue * parent_property = parent_material_props.props()[&elem][parent_side][i]; child_property->qpCopy(qp, parent_property, child_map[qp]._to); propsOld()[child_elem][child_side][i]->qpCopy(qp, parent_material_props.propsOld()[&elem][parent_side][i], child_map[qp]._to); if (hasOlderProperties()) propsOlder()[child_elem][child_side][i]->qpCopy(qp, parent_material_props.propsOlder()[&elem][parent_side][i], child_map[qp]._to); } } } }
void MaterialPropertyStorage::restrictStatefulProps(const std::vector<std::pair<unsigned int, QpMap> > & coarsening_map, std::vector<const Elem *> & coarsened_element_children, QBase & qrule, QBase & qrule_face, MaterialData & material_data, const Elem & elem, int input_side) { unsigned int side; bool doing_a_side = input_side != -1; unsigned int n_qpoints = 0; if (!doing_a_side) { side = 0; // Use 0 for the elem n_qpoints = qrule.n_points(); } else { side = input_side; n_qpoints = qrule_face.n_points(); } material_data.size(n_qpoints); // First, make sure that storage has been set aside for this element. //initStatefulProps(material_data, mats, n_qpoints, elem, side); if (props()[&elem][side].size() == 0) props()[&elem][side].resize(_stateful_prop_id_to_prop_id.size()); if (propsOld()[&elem][side].size() == 0) propsOld()[&elem][side].resize(_stateful_prop_id_to_prop_id.size()); if (propsOlder()[&elem][side].size() == 0) propsOlder()[&elem][side].resize(_stateful_prop_id_to_prop_id.size()); // init properties (allocate memory. etc) for (unsigned int i=0; i < _stateful_prop_id_to_prop_id.size(); ++i) { // duplicate the stateful property in property storage (all three states - we will reuse the allocated memory there) // also allocating the right amount of memory, so we do not have to resize, etc. if (props()[&elem][side][i] == NULL) props()[&elem][side][i] = material_data.props()[ _stateful_prop_id_to_prop_id[i] ]->init(n_qpoints); if (propsOld()[&elem][side][i] == NULL) propsOld()[&elem][side][i] = material_data.propsOld()[ _stateful_prop_id_to_prop_id[i] ]->init(n_qpoints); if (hasOlderProperties()) if (propsOlder()[&elem][side][i] == NULL) propsOlder()[&elem][side][i] = material_data.propsOlder()[ _stateful_prop_id_to_prop_id[i] ]->init(n_qpoints); } // Copy from the child stateful properties for (unsigned int qp=0; qp<coarsening_map.size(); qp++) { const std::pair<unsigned int, QpMap> & qp_pair = coarsening_map[qp]; unsigned int child = qp_pair.first; mooseAssert(child < coarsened_element_children.size(), "Coarsened element children vector not initialized"); const Elem * child_elem = coarsened_element_children[child]; const QpMap & qp_map = qp_pair.second; for (unsigned int i=0; i < _stateful_prop_id_to_prop_id.size(); ++i) { mooseAssert(props().contains(child_elem), "Child element pointer is not in the MaterialProps data structure"); PropertyValue * child_property = props()[child_elem][side][i]; PropertyValue * parent_property = props()[&elem][side][i]; parent_property->qpCopy(qp, child_property, qp_map._to); propsOld()[&elem][side][i]->qpCopy(qp, propsOld()[child_elem][side][i], qp_map._to); if (hasOlderProperties()) propsOlder()[&elem][side][i]->qpCopy(qp, propsOlder()[child_elem][side][i], qp_map._to); } } }
void ExactSolution::_compute_error(const std::string & sys_name, const std::string & unknown_name, std::vector<Real> & error_vals) { // Make sure we aren't "overconfigured" libmesh_assert (!(_exact_values.size() && _equation_systems_fine)); // We need a commmunicator. const Parallel::Communicator & communicator(_equation_systems.comm()); // This function must be run on all processors at once libmesh_parallel_only(communicator); // Get a reference to the system whose error is being computed. // If we have a fine grid, however, we'll integrate on that instead // for more accuracy. const System & computed_system = _equation_systems_fine ? _equation_systems_fine->get_system(sys_name) : _equation_systems.get_system (sys_name); const Real time = _equation_systems.get_system(sys_name).time; const unsigned int sys_num = computed_system.number(); const unsigned int var = computed_system.variable_number(unknown_name); const unsigned int var_component = computed_system.variable_scalar_number(var, 0); // Prepare a global solution and a MeshFunction of the coarse system if we need one UniquePtr<MeshFunction> coarse_values; UniquePtr<NumericVector<Number> > comparison_soln = NumericVector<Number>::build(_equation_systems.comm()); if (_equation_systems_fine) { const System & comparison_system = _equation_systems.get_system(sys_name); std::vector<Number> global_soln; comparison_system.update_global_solution(global_soln); comparison_soln->init(comparison_system.solution->size(), true, SERIAL); (*comparison_soln) = global_soln; coarse_values = UniquePtr<MeshFunction> (new MeshFunction(_equation_systems, *comparison_soln, comparison_system.get_dof_map(), comparison_system.variable_number(unknown_name))); coarse_values->init(); } // Initialize any functors we're going to use for (unsigned int i=0; i != _exact_values.size(); ++i) if (_exact_values[i]) _exact_values[i]->init(); for (unsigned int i=0; i != _exact_derivs.size(); ++i) if (_exact_derivs[i]) _exact_derivs[i]->init(); for (unsigned int i=0; i != _exact_hessians.size(); ++i) if (_exact_hessians[i]) _exact_hessians[i]->init(); // Get a reference to the dofmap and mesh for that system const DofMap & computed_dof_map = computed_system.get_dof_map(); const MeshBase & _mesh = computed_system.get_mesh(); // Grab which element dimensions are present in the mesh const std::set<unsigned char> & elem_dims = _mesh.elem_dimensions(); // Zero the error before summation // 0 - sum of square of function error (L2) // 1 - sum of square of gradient error (H1 semi) // 2 - sum of square of Hessian error (H2 semi) // 3 - sum of sqrt(square of function error) (L1) // 4 - max of sqrt(square of function error) (Linfty) // 5 - sum of square of curl error (HCurl semi) // 6 - sum of square of div error (HDiv semi) error_vals = std::vector<Real>(7, 0.); // Construct Quadrature rule based on default quadrature order const FEType & fe_type = computed_dof_map.variable_type(var); unsigned int n_vec_dim = FEInterface::n_vec_dim( _mesh, fe_type ); // FIXME: MeshFunction needs to be updated to support vector-valued // elements before we can use a reference solution. if( (n_vec_dim > 1) && _equation_systems_fine ) { libMesh::err << "Error calculation using reference solution not yet\n" << "supported for vector-valued elements." << std::endl; libmesh_not_implemented(); } // Allow space for dims 0-3, even if we don't use them all std::vector<FEGenericBase<OutputShape> *> fe_ptrs(4, libmesh_nullptr); std::vector<QBase *> q_rules(4, libmesh_nullptr); // Prepare finite elements for each dimension present in the mesh for( std::set<unsigned char>::const_iterator d_it = elem_dims.begin(); d_it != elem_dims.end(); ++d_it ) { q_rules[*d_it] = fe_type.default_quadrature_rule (*d_it, _extra_order).release(); // Construct finite element object fe_ptrs[*d_it] = FEGenericBase<OutputShape>::build(*d_it, fe_type).release(); // Attach quadrature rule to FE object fe_ptrs[*d_it]->attach_quadrature_rule (q_rules[*d_it]); } // The global degree of freedom indices associated // with the local degrees of freedom. std::vector<dof_id_type> dof_indices; // // Begin the loop over the elements // // TODO: this ought to be threaded (and using subordinate // MeshFunction objects in each thread rather than a single // master) MeshBase::const_element_iterator el = _mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = _mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { // Store a pointer to the element we are currently // working on. This allows for nicer syntax later. const Elem * elem = *el; const unsigned int dim = elem->dim(); const subdomain_id_type elem_subid = elem->subdomain_id(); // If the variable is not active on this subdomain, don't bother if(!computed_system.variable(var).active_on_subdomain(elem_subid)) continue; /* If the variable is active, then we're going to restrict the MeshFunction evaluations to the current element subdomain. This is for cases such as mixed dimension meshes where we want to restrict the calculation to one particular domain. */ std::set<subdomain_id_type> subdomain_id; subdomain_id.insert(elem_subid); FEGenericBase<OutputShape> * fe = fe_ptrs[dim]; QBase * qrule = q_rules[dim]; libmesh_assert(fe); libmesh_assert(qrule); // The Jacobian*weight at the quadrature points. const std::vector<Real> & JxW = fe->get_JxW(); // The value of the shape functions at the quadrature points // i.e. phi(i) = phi_values[i][qp] const std::vector<std::vector<OutputShape> > & phi_values = fe->get_phi(); // The value of the shape function gradients at the quadrature points const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient> > & dphi_values = fe->get_dphi(); // The value of the shape function curls at the quadrature points // Only computed for vector-valued elements const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputShape> > * curl_values = libmesh_nullptr; // The value of the shape function divergences at the quadrature points // Only computed for vector-valued elements const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputDivergence> > * div_values = libmesh_nullptr; if( FEInterface::field_type(fe_type) == TYPE_VECTOR ) { curl_values = &fe->get_curl_phi(); div_values = &fe->get_div_phi(); } #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES // The value of the shape function second derivatives at the quadrature points const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputTensor> > & d2phi_values = fe->get_d2phi(); #endif // The XYZ locations (in physical space) of the quadrature points const std::vector<Point> & q_point = fe->get_xyz(); // reinitialize the element-specific data // for the current element fe->reinit (elem); // Get the local to global degree of freedom maps computed_dof_map.dof_indices (elem, dof_indices, var); // The number of quadrature points const unsigned int n_qp = qrule->n_points(); // The number of shape functions const unsigned int n_sf = cast_int<unsigned int>(dof_indices.size()); // // Begin the loop over the Quadrature points. // for (unsigned int qp=0; qp<n_qp; qp++) { // Real u_h = 0.; // RealGradient grad_u_h; typename FEGenericBase<OutputShape>::OutputNumber u_h(0.); typename FEGenericBase<OutputShape>::OutputNumberGradient grad_u_h; #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES typename FEGenericBase<OutputShape>::OutputNumberTensor grad2_u_h; #endif typename FEGenericBase<OutputShape>::OutputNumber curl_u_h(0.0); typename FEGenericBase<OutputShape>::OutputNumberDivergence div_u_h = 0.0; // Compute solution values at the current // quadrature point. This reqiures a sum // over all the shape functions evaluated // at the quadrature point. for (unsigned int i=0; i<n_sf; i++) { // Values from current solution. u_h += phi_values[i][qp]*computed_system.current_solution (dof_indices[i]); grad_u_h += dphi_values[i][qp]*computed_system.current_solution (dof_indices[i]); #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES grad2_u_h += d2phi_values[i][qp]*computed_system.current_solution (dof_indices[i]); #endif if( FEInterface::field_type(fe_type) == TYPE_VECTOR ) { curl_u_h += (*curl_values)[i][qp]*computed_system.current_solution (dof_indices[i]); div_u_h += (*div_values)[i][qp]*computed_system.current_solution (dof_indices[i]); } } // Compute the value of the error at this quadrature point typename FEGenericBase<OutputShape>::OutputNumber exact_val(0); RawAccessor<typename FEGenericBase<OutputShape>::OutputNumber> exact_val_accessor( exact_val, dim ); if (_exact_values.size() > sys_num && _exact_values[sys_num]) { for( unsigned int c = 0; c < n_vec_dim; c++) exact_val_accessor(c) = _exact_values[sys_num]-> component(var_component+c, q_point[qp], time); } else if (_equation_systems_fine) { // FIXME: Needs to be updated for vector-valued elements DenseVector<Number> output(1); (*coarse_values)(q_point[qp],time,output,&subdomain_id); exact_val = output(0); } const typename FEGenericBase<OutputShape>::OutputNumber val_error = u_h - exact_val; // Add the squares of the error to each contribution Real error_sq = TensorTools::norm_sq(val_error); error_vals[0] += JxW[qp]*error_sq; Real norm = sqrt(error_sq); error_vals[3] += JxW[qp]*norm; if(error_vals[4]<norm) { error_vals[4] = norm; } // Compute the value of the error in the gradient at this // quadrature point typename FEGenericBase<OutputShape>::OutputNumberGradient exact_grad; RawAccessor<typename FEGenericBase<OutputShape>::OutputNumberGradient> exact_grad_accessor( exact_grad, LIBMESH_DIM ); if (_exact_derivs.size() > sys_num && _exact_derivs[sys_num]) { for (unsigned int c = 0; c < n_vec_dim; c++) for (unsigned int d = 0; d < LIBMESH_DIM; d++) exact_grad_accessor(d + c*LIBMESH_DIM) = _exact_derivs[sys_num]-> component(var_component+c, q_point[qp], time)(d); } else if (_equation_systems_fine) { // FIXME: Needs to be updated for vector-valued elements std::vector<Gradient> output(1); coarse_values->gradient(q_point[qp],time,output,&subdomain_id); exact_grad = output[0]; } const typename FEGenericBase<OutputShape>::OutputNumberGradient grad_error = grad_u_h - exact_grad; error_vals[1] += JxW[qp]*grad_error.norm_sq(); if( FEInterface::field_type(fe_type) == TYPE_VECTOR ) { // Compute the value of the error in the curl at this // quadrature point typename FEGenericBase<OutputShape>::OutputNumber exact_curl(0.0); if (_exact_derivs.size() > sys_num && _exact_derivs[sys_num]) { exact_curl = TensorTools::curl_from_grad( exact_grad ); } else if (_equation_systems_fine) { // FIXME: Need to implement curl for MeshFunction and support reference // solution for vector-valued elements } const typename FEGenericBase<OutputShape>::OutputNumber curl_error = curl_u_h - exact_curl; error_vals[5] += JxW[qp]*TensorTools::norm_sq(curl_error); // Compute the value of the error in the divergence at this // quadrature point typename FEGenericBase<OutputShape>::OutputNumberDivergence exact_div = 0.0; if (_exact_derivs.size() > sys_num && _exact_derivs[sys_num]) { exact_div = TensorTools::div_from_grad( exact_grad ); } else if (_equation_systems_fine) { // FIXME: Need to implement div for MeshFunction and support reference // solution for vector-valued elements } const typename FEGenericBase<OutputShape>::OutputNumberDivergence div_error = div_u_h - exact_div; error_vals[6] += JxW[qp]*TensorTools::norm_sq(div_error); } #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES // Compute the value of the error in the hessian at this // quadrature point typename FEGenericBase<OutputShape>::OutputNumberTensor exact_hess; RawAccessor<typename FEGenericBase<OutputShape>::OutputNumberTensor> exact_hess_accessor( exact_hess, dim ); if (_exact_hessians.size() > sys_num && _exact_hessians[sys_num]) { //FIXME: This needs to be implemented to support rank 3 tensors // which can't happen until type_n_tensor is fully implemented // and a RawAccessor<TypeNTensor> is fully implemented if( FEInterface::field_type(fe_type) == TYPE_VECTOR ) libmesh_not_implemented(); for( unsigned int c = 0; c < n_vec_dim; c++) for( unsigned int d = 0; d < dim; d++ ) for( unsigned int e =0; e < dim; e++ ) exact_hess_accessor(d + e*dim + c*dim*dim) = _exact_hessians[sys_num]-> component(var_component+c, q_point[qp], time)(d,e); } else if (_equation_systems_fine) { // FIXME: Needs to be updated for vector-valued elements std::vector<Tensor> output(1); coarse_values->hessian(q_point[qp],time,output,&subdomain_id); exact_hess = output[0]; } const typename FEGenericBase<OutputShape>::OutputNumberTensor grad2_error = grad2_u_h - exact_hess; // FIXME: PB: Is this what we want for rank 3 tensors? error_vals[2] += JxW[qp]*grad2_error.norm_sq(); #endif } // end qp loop } // end element loop // Clean up the FE and QBase pointers we created for( std::set<unsigned char>::const_iterator d_it = elem_dims.begin(); d_it != elem_dims.end(); ++d_it ) { delete fe_ptrs[*d_it]; delete q_rules[*d_it]; } // Add up the error values on all processors, except for the L-infty // norm, for which the maximum is computed. Real l_infty_norm = error_vals[4]; communicator.max(l_infty_norm); communicator.sum(error_vals); error_vals[4] = l_infty_norm; }