On Mon, 27 Feb 2012, Boyce Griffith wrote:
On 2/24/12 7:53 PM, Roy Stogner wrote:Anything I'm missing? I'm going to start coding and testing everything this weekend, bearing in mind that I may tear it all up and start over if Ben's got better ideas based on his recent FIN-S true-Dirichlet experience.Let me know if I can help. I have some time this week that I could spend working on this.
That would be great, since I don't have time to work on this. But why let that stop me? Updated patch is posted; thanks also to Derek for offering to test. Assuming this doesn't break anyone's adaptive, periodic, etc. codes, then I'll commit and add a Dirichlet constraints generation routine (probably an API along the lines of the functor version of System::project_boundary_solution unless anyone dislikes that) this week. --- Roy
Index: include/base/dof_map.h =================================================================== --- include/base/dof_map.h (revision 5180) +++ include/base/dof_map.h (working copy) @@ -79,9 +79,9 @@ * a pointer-to-std::map; the destructor isn't virtual! */ class DofConstraints : public std::map<unsigned int, - DofConstraintRow, + std::pair<DofConstraintRow,Number>, std::less<unsigned int>, - Threads::scalable_allocator<std::pair<const unsigned int, DofConstraintRow> > > + Threads::scalable_allocator<std::pair<const unsigned int, std::pair<DofConstraintRow,Number> > > > { }; @@ -103,9 +103,9 @@ * a pointer-to-std::map; the destructor isn't virtual! */ class NodeConstraints : public std::map<const Node *, - NodeConstraintRow, - std::less<const Node *>, - Threads::scalable_allocator<std::pair<const Node * const, NodeConstraintRow> > > + std::pair<NodeConstraintRow,Point>, + std::less<const Node *>, + Threads::scalable_allocator<std::pair<const Node * const, std::pair<NodeConstraintRow,Point> > > > { }; #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS @@ -475,12 +475,23 @@ void process_constraints (); /** - * Adds a copy of the user-defined row to the constraint matrix. + * Adds a copy of the user-defined row to the constraint matrix, using + * an inhomogeneous right-hand-side for the constraint equation. + */ + void add_constraint_row (const unsigned int dof_number, + const DofConstraintRow& constraint_row, + const Number constraint_rhs, + const bool forbid_constraint_overwrite); + + /** + * Adds a copy of the user-defined row to the constraint matrix, using + * a homogeneous right-hand-side for the constraint equation. * By default, produces an error if the DOF was already constrained. */ void add_constraint_row (const unsigned int dof_number, - const DofConstraintRow& constraint_row, - const bool forbid_constraint_overwrite = true); + const DofConstraintRow& constraint_row, + const bool forbid_constraint_overwrite = true) + { add_constraint_row(dof_number, constraint_row, 0., forbid_constraint_overwrite); } /** * Returns an iterator pointing to the first DoF constraint row @@ -593,6 +604,28 @@ DenseVector<Number>& rhs, std::vector<unsigned int>& elem_dofs, bool asymmetric_constraint_rows = true) const; + /** + * Constrains the element matrix and vector. This method requires + * the element matrix to be square, in which case the elem_dofs + * correspond to the global DOF indices of both the rows and + * columns of the element matrix. For this case the rows + * and columns of the matrix necessarily correspond to variables + * of the same approximation order. + * + * The heterogenous version of this method creates linear systems in + * which heterogenously constrained degrees of freedom will solve to + * their correct offset values, as would be appropriate for finding + * a solution to a linear problem in a single algebraic solve. The + * non-heterogenous version of this method creates linear systems in + * which even heterogenously constrained degrees of freedom are + * solved without offset values taken into account, as would be + * appropriate for finding linearized updates to a solution in which + * heterogenous constraints are already satisfied. + */ + void heterogenously_constrain_element_matrix_and_vector (DenseMatrix<Number>& matrix, + DenseVector<Number>& rhs, + std::vector<unsigned int>& elem_dofs, + bool asymmetric_constraint_rows = true) const; /** * Constrains a dyadic element matrix B = v w'. This method @@ -823,6 +856,21 @@ const bool called_recursively=false) const; /** + * Build the constraint matrix C and the forcing vector H + * associated with the element degree of freedom indices elem_dofs. + * The optional parameter \p called_recursively should be left at + * the default value \p false. This is used to handle the special + * case of an element's degrees of freedom being constrained in + * terms of other, local degrees of freedom. The usual case is for + * an elements DOFs to be constrained by some other, external DOFs + * and/or Dirichlet conditions. + */ + void build_constraint_matrix_and_vector (DenseMatrix<Number>& C, + DenseVector<Number>& H, + std::vector<unsigned int>& elem_dofs, + const bool called_recursively=false) const; + + /** * Finds all the DOFS associated with the element DOFs elem_dofs. * This will account for off-element couplings via hanging nodes. */ Index: src/fe/fe_base.C =================================================================== --- src/fe/fe_base.C (revision 5180) +++ src/fe/fe_base.C (working copy) @@ -2190,7 +2190,7 @@ Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); DofConstraintRow& constraint_row = - constraints[my_dof_g]; + constraints[my_dof_g].first; constraint_row.insert(std::make_pair(their_dof_g, their_dof_value)); @@ -2325,7 +2325,7 @@ Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); // A reference to the constraint row. - NodeConstraintRow& constraint_row = constraints[my_node]; + NodeConstraintRow& constraint_row = constraints[my_node].first; constraint_row.insert(std::make_pair (their_node, 0.)); @@ -2341,7 +2341,7 @@ Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); // A reference to the constraint row. - NodeConstraintRow& constraint_row = constraints[my_node]; + NodeConstraintRow& constraint_row = constraints[my_node].first; constraint_row.insert(std::make_pair (their_node, their_value)); @@ -2571,7 +2571,7 @@ continue; DofConstraintRow& their_constraint_row = - constraints[their_dof_g]; + constraints[their_dof_g].first; for (unsigned int js = 0; js != n_side_dofs; ++js) { @@ -2619,7 +2619,7 @@ Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); DofConstraintRow& constraint_row = - constraints[my_dof_g]; + constraints[my_dof_g].first; constraint_row.insert(std::make_pair(their_dof_g, their_dof_value)); @@ -2777,7 +2777,7 @@ continue; const NodeConstraintRow& their_constraint_row = - constraints[their_node]; + constraints[their_node].first; for (unsigned int orig_side_n=0; orig_side_n < n_side_nodes; @@ -2834,7 +2834,7 @@ Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); NodeConstraintRow& constraint_row = - constraints[my_node]; + constraints[my_node].first; constraint_row.insert(std::make_pair(their_node, their_value)); Index: src/fe/fe_lagrange.C =================================================================== --- src/fe/fe_lagrange.C (revision 5180) +++ src/fe/fe_lagrange.C (working copy) @@ -730,7 +730,7 @@ Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); // A reference to the constraint row. - DofConstraintRow& constraint_row = constraints[my_dof_g]; + DofConstraintRow& constraint_row = constraints[my_dof_g].first; constraint_row.insert(std::make_pair (their_dof_g, their_dof_value)); Index: src/base/dof_map.C =================================================================== --- src/base/dof_map.C (revision 5180) +++ src/base/dof_map.C (working copy) @@ -1973,7 +1973,7 @@ libmesh_assert (pos != _dof_constraints.end()); - const DofConstraintRow& constraint_row = pos->second; + const DofConstraintRow& constraint_row = pos->second.first; // adaptive p refinement currently gives us lots of empty constraint // rows - we should optimize those DoFs away in the future. [RHS] @@ -2502,34 +2502,41 @@ #if defined(LIBMESH_ENABLE_AMR) || defined(LIBMESH_ENABLE_PERIODIC) - unsigned int n_constraints = 0, max_constraint_length = 0; + unsigned int n_constraints = 0, max_constraint_length = 0, + n_rhss = 0; long double avg_constraint_length = 0.; #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS - unsigned int n_hanging_nodes = 0, max_node_constraint_length = 0; + unsigned int n_node_constraints = 0, max_node_constraint_length = 0, + n_node_rhss = 0; long double avg_node_constraint_length = 0.; #endif for (DofConstraints::const_iterator it=_dof_constraints.begin(); it != _dof_constraints.end(); ++it) { - const DofConstraintRow& row = it->second; + const DofConstraintRow& row = it->second.first; unsigned int rowsize = row.size(); max_constraint_length = std::max(max_constraint_length, rowsize); avg_constraint_length += rowsize; n_constraints++; + + if (it->second.second) + n_rhss++; } os << " DofMap Constraints\n Number of DoF Constraints = " << n_constraints; + if (n_rhss) + os << '\n' + << " Number of heterogenous constraints= " << n_rhss; if (n_constraints) { avg_constraint_length /= n_constraints; - os << " DofMap Constraints\n Number of Constraints = " << n_constraints - << '\n' + os << '\n' << " Average DoF Constraint Length= " << avg_constraint_length; } @@ -2537,19 +2544,25 @@ for (NodeConstraints::const_iterator it=_node_constraints.begin(); it != _node_constraints.end(); ++it) { - const NodeConstraintRow& row = it->second; + const NodeConstraintRow& row = it->second.first; unsigned int rowsize = row.size(); max_node_constraint_length = std::max(max_node_constraint_length, rowsize); avg_node_constraint_length += rowsize; - n_hanging_nodes++; + n_node_constraints++; + + if (it->second.second != Point(0)) + n_node_rhss++; } - if (n_hanging_nodes) + os << "\n Number of Node Constraints = " << n_node_constraints; + if (n_rhss) + os << '\n' + << " Number of heterogenous node constraints= " << n_node_rhss; + if (n_node_constraints) { - os << "\n Number of Node Constraints = " << n_hanging_nodes; - avg_node_constraint_length /= n_hanging_nodes; + avg_node_constraint_length /= n_node_constraints; os << "\n Maximum Node Constraint Length= " << max_node_constraint_length << '\n' << " Average Node Constraint Length= " << avg_node_constraint_length; Index: src/base/dof_map_constraints.C =================================================================== --- src/base/dof_map_constraints.C (revision 5180) +++ src/base/dof_map_constraints.C (working copy) @@ -276,6 +276,7 @@ void DofMap::add_constraint_row (const unsigned int dof_number, const DofConstraintRow& constraint_row, + const Number constraint_rhs, const bool forbid_constraint_overwrite) { // Optionally allow the user to overwrite constraints. Defaults to false. @@ -287,7 +288,7 @@ libmesh_error(); } - std::pair<unsigned int, DofConstraintRow> kv(dof_number, constraint_row); + std::pair<unsigned int, std::pair<DofConstraintRow,Number> > kv(dof_number, std::make_pair(constraint_row, constraint_rhs)); _dof_constraints.insert(kv); } @@ -304,7 +305,8 @@ it != _node_constraints.end(); ++it) { const Node *node = it->first; - const NodeConstraintRow& row = it->second; + const NodeConstraintRow& row = it->second.first; + const Point& offset = it->second.second; os << "Constraints for Node id " << node->id() << ": \t"; @@ -314,6 +316,8 @@ os << " (" << pos->first->id() << "," << pos->second << ")\t"; + os << "rhs: " << offset; + os << std::endl; } #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS @@ -325,7 +329,8 @@ it != _dof_constraints.end(); ++it) { const unsigned int i = it->first; - const DofConstraintRow& row = it->second; + const DofConstraintRow& row = it->second.first; + const Number rhs = it->second.second; os << "Constraints for DoF " << i << ": \t"; @@ -335,6 +340,8 @@ os << " (" << pos->first << "," << pos->second << ")\t"; + os << "rhs: " << rhs; + os << std::endl; } } @@ -390,7 +397,7 @@ libmesh_assert (pos != _dof_constraints.end()); - const DofConstraintRow& constraint_row = pos->second; + const DofConstraintRow& constraint_row = pos->second.first; libmesh_assert (!constraint_row.empty()); @@ -463,7 +470,7 @@ libmesh_assert (pos != _dof_constraints.end()); - const DofConstraintRow& constraint_row = pos->second; + const DofConstraintRow& constraint_row = pos->second.first; // p refinement creates empty constraint rows // libmesh_assert (!constraint_row.empty()); @@ -483,18 +490,97 @@ // compute matrix/vector product C.vector_mult_transpose(rhs, old_rhs); + } // end if is constrained... - libmesh_assert (elem_dofs.size() == rhs.size()); + STOP_LOG("cnstrn_elem_mat_vec()", "DofMap"); +} + + +void DofMap::heterogenously_constrain_element_matrix_and_vector + (DenseMatrix<Number>& matrix, + DenseVector<Number>& rhs, + std::vector<unsigned int>& elem_dofs, + bool asymmetric_constraint_rows) const +{ + libmesh_assert (elem_dofs.size() == matrix.m()); + libmesh_assert (elem_dofs.size() == matrix.n()); + libmesh_assert (elem_dofs.size() == rhs.size()); + + // check for easy return + if (this->n_constrained_dofs() == 0) + return; + + // The constrained matrix is built up as C^T K C. + // The constrained RHS is built up as C^T (F - K H) + DenseMatrix<Number> C; + DenseVector<Number> H; + + this->build_constraint_matrix_and_vector (C, H, elem_dofs); + + START_LOG("hetero_cnstrn_elem_mat_vec()", "DofMap"); + + // It is possible that the matrix is not constrained at all. + if ((C.m() == matrix.m()) && + (C.n() == elem_dofs.size())) // It the matrix is constrained + { + // Compute matrix/vector product K H + DenseVector<Number> KH; + matrix.vector_mult(KH, H); + + // Compute the matrix-vector product C^T (F - KH) + DenseVector<Number> F_minus_KH(rhs); + F_minus_KH -= KH; + C.vector_mult_transpose(rhs, F_minus_KH); + + // Compute the matrix-matrix-matrix product C^T K C + matrix.left_multiply_transpose (C); + matrix.right_multiply (C); + + libmesh_assert (matrix.m() == matrix.n()); + libmesh_assert (matrix.m() == elem_dofs.size()); + libmesh_assert (matrix.n() == elem_dofs.size()); + for (unsigned int i=0; i<elem_dofs.size(); i++) if (this->is_constrained_dof(elem_dofs[i])) { + for (unsigned int j=0; j<matrix.n(); j++) + matrix(i,j) = 0.; + // If the DOF is constrained - rhs(i) = 0.; + matrix(i,i) = 1.; + + // This will put a nonsymmetric entry in the constraint + // row to ensure that the linear system produces the + // correct value for the constrained DOF. + if (asymmetric_constraint_rows) + { + DofConstraints::const_iterator + pos = _dof_constraints.find(elem_dofs[i]); + + libmesh_assert (pos != _dof_constraints.end()); + + const DofConstraintRow& constraint_row = pos->second.first; + +// p refinement creates empty constraint rows +// libmesh_assert (!constraint_row.empty()); + + for (DofConstraintRow::const_iterator + it=constraint_row.begin(); it != constraint_row.end(); + ++it) + for (unsigned int j=0; j<elem_dofs.size(); j++) + if (elem_dofs[j] == it->first) + matrix(i,j) = -it->second; + + rhs(i) = -pos->second.second; + } + else + rhs(i) = 0.; } + } // end if is constrained... - STOP_LOG("cnstrn_elem_mat_vec()", "DofMap"); + STOP_LOG("hetero_cnstrn_elem_mat_vec()", "DofMap"); } @@ -561,7 +647,7 @@ libmesh_assert (pos != _dof_constraints.end()); - const DofConstraintRow& constraint_row = pos->second; + const DofConstraintRow& constraint_row = pos->second.first; libmesh_assert (!constraint_row.empty()); @@ -611,7 +697,12 @@ if (this->is_constrained_dof(row_dofs[i])) { // If the DOF is constrained - rhs(i) = 0.; + DofConstraints::const_iterator + pos = _dof_constraints.find(row_dofs[i]); + + libmesh_assert (pos != _dof_constraints.end()); + + rhs(i) = -pos->second.second; } } // end if the RHS is constrained. @@ -660,7 +751,12 @@ if (this->is_constrained_dof(row_dofs[i])) { // If the DOF is constrained - v(i) = 0.; + DofConstraints::const_iterator + pos = _dof_constraints.find(row_dofs[i]); + + libmesh_assert (pos != _dof_constraints.end()); + + v(i) = -pos->second.second; } } // end if the RHS is constrained. @@ -755,9 +851,9 @@ constrained_dof >= this->end_dof()) continue; - const DofConstraintRow constraint_row = c_it->second; + const DofConstraintRow constraint_row = c_it->second.first; - Number exact_value = 0; + Number exact_value = c_it->second.second; for (DofConstraintRow::const_iterator j=constraint_row.begin(); j != constraint_row.end(); ++j) @@ -831,7 +927,12 @@ global_dof >= vec.first_local_index() && global_dof < vec.last_local_index()) { - Number exact_value = 0; + DofConstraints::const_iterator + pos = _dof_constraints.find(global_dof); + + libmesh_assert (pos != _dof_constraints.end()); + + Number exact_value = pos->second.second; for (unsigned int j=0; j!=C.n(); ++j) { if (local_dof_indices[j] != global_dof) @@ -881,7 +982,7 @@ libmesh_assert (pos != _dof_constraints.end()); - const DofConstraintRow& constraint_row = pos->second; + const DofConstraintRow& constraint_row = pos->second.first; // Constraint rows in p refinement may be empty // libmesh_assert (!constraint_row.empty()); @@ -933,7 +1034,7 @@ libmesh_assert (pos != _dof_constraints.end()); - const DofConstraintRow& constraint_row = pos->second; + const DofConstraintRow& constraint_row = pos->second.first; // p refinement creates empty constraint rows // libmesh_assert (!constraint_row.empty()); @@ -972,6 +1073,135 @@ } + +void DofMap::build_constraint_matrix_and_vector + (DenseMatrix<Number>& C, + DenseVector<Number>& H, + std::vector<unsigned int>& elem_dofs, + const bool called_recursively) const +{ + if (!called_recursively) + START_LOG("build_constraint_matrix_and_vector()", "DofMap"); + + // Create a set containing the DOFs we already depend on + typedef std::set<unsigned int> RCSet; + RCSet dof_set; + + bool we_have_constraints = false; + + // Next insert any other dofs the current dofs might be constrained + // in terms of. Note that in this case we may not be done: Those + // may in turn depend on others. So, we need to repeat this process + // in that case until the system depends only on unconstrained + // degrees of freedom. + for (unsigned int i=0; i<elem_dofs.size(); i++) + if (this->is_constrained_dof(elem_dofs[i])) + { + we_have_constraints = true; + + // If the DOF is constrained + DofConstraints::const_iterator + pos = _dof_constraints.find(elem_dofs[i]); + + libmesh_assert (pos != _dof_constraints.end()); + + const DofConstraintRow& constraint_row = pos->second.first; + +// Constraint rows in p refinement may be empty +// libmesh_assert (!constraint_row.empty()); + + for (DofConstraintRow::const_iterator + it=constraint_row.begin(); it != constraint_row.end(); + ++it) + dof_set.insert (it->first); + } + + // May be safe to return at this point + // (but remember to stop the perflog) + if (!we_have_constraints) + { + STOP_LOG("build_constraint_matrix_and_vector()", "DofMap"); + return; + } + + // delay inserting elem_dofs for efficiency in the case of + // no constraints. In that case we don't get here! + dof_set.insert (elem_dofs.begin(), + elem_dofs.end()); + + // If we added any DOFS then we need to do this recursively. + // It is possible that we just added a DOF that is also + // constrained! + // + // Also, we need to handle the special case of an element having DOFs + // constrained in terms of other, local DOFs + if ((dof_set.size() != elem_dofs.size()) || // case 1: constrained in terms of other DOFs + !called_recursively) // case 2: constrained in terms of our own DOFs + { + // Create a new list of element DOFs containing the + // contents of the current dof_set. + std::vector<unsigned int> new_elem_dofs (dof_set.begin(), + dof_set.end()); + + // Now we can build the constraint matrix. + // Note that resize also zeros for a DenseMatrix<Number>. + C.resize (elem_dofs.size(), new_elem_dofs.size()); + + // Create the C constraint matrix. + for (unsigned int i=0; i<elem_dofs.size(); i++) + if (this->is_constrained_dof(elem_dofs[i])) + { + // If the DOF is constrained + DofConstraints::const_iterator + pos = _dof_constraints.find(elem_dofs[i]); + + libmesh_assert (pos != _dof_constraints.end()); + + const DofConstraintRow& constraint_row = pos->second.first; + +// p refinement creates empty constraint rows +// libmesh_assert (!constraint_row.empty()); + + for (DofConstraintRow::const_iterator + it=constraint_row.begin(); it != constraint_row.end(); + ++it) + for (unsigned int j=0; j<new_elem_dofs.size(); j++) + if (new_elem_dofs[j] == it->first) + C(i,j) = it->second; + } + else + { + for (unsigned int j=0; j<new_elem_dofs.size(); j++) + if (new_elem_dofs[j] == elem_dofs[i]) + C(i,j) = 1.; + } + + // May need to do this recursively. It is possible + // that we just replaced a constrained DOF with another + // constrained DOF. + elem_dofs = new_elem_dofs; + + DenseMatrix<Number> Cnew; + DenseVector<Number> Hnew; + + this->build_constraint_matrix_and_vector (Cnew, Hnew, elem_dofs, true); + + // If x = Cy + h and y = Dz + g + // Then x = (CD)z + (Cg + h) + C.vector_mult_add(H, 1, Hnew); + + if ((C.n() == Cnew.m()) && // If the constraint matrix + (Cnew.n() == elem_dofs.size())) // is constrained... + C.right_multiply(Cnew); + + libmesh_assert (C.n() == elem_dofs.size()); + } + + if (!called_recursively) + STOP_LOG("build_constraint_matrix_and_vector()", "DofMap"); +} + + // NodeConstraints can fail in parallel when we try to look up a node // that our processor doesn't have. Until we have a fix for that, // let's just disable the allgather attempt. @@ -1068,12 +1298,13 @@ libMesh::processor_id() - p) % libMesh::n_processors(); - // Pack the dof constraint rows to push to procup + // Pack the dof constraint rows and rhs's to push to procup std::vector<std::vector<unsigned int> > pushed_keys(pushed_ids[procup].size()); std::vector<std::vector<Real> > pushed_vals(pushed_ids[procup].size()); + std::vector<Number> pushed_rhss(pushed_ids[procup].size()); for (unsigned int i = 0; i != pushed_ids[procup].size(); ++i) { - DofConstraintRow &row = _dof_constraints[pushed_ids[procup][i]]; + DofConstraintRow &row = _dof_constraints[pushed_ids[procup][i]].first; unsigned int row_size = row.size(); pushed_keys[i].reserve(row_size); pushed_vals[i].reserve(row_size); @@ -1083,16 +1314,18 @@ pushed_keys[i].push_back(j->first); pushed_vals[i].push_back(j->second); } + pushed_rhss[i] = _dof_constraints[pushed_ids[procup][i]].second; } #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS // Pack the node constraint rows to push to procup std::vector<std::vector<unsigned int> > pushed_node_keys(pushed_node_ids[procup].size()); std::vector<std::vector<Real> > pushed_node_vals(pushed_node_ids[procup].size()); + std::vector<Point> pushed_node_offsets(pushed_node_ids[procup].size()); for (unsigned int i = 0; i != pushed_node_ids[procup].size(); ++i) { const Node *node = mesh.node_ptr(pushed_node_ids[procup][i]); - NodeConstraintRow &row = _node_constraints[node]; + NodeConstraintRow &row = _node_constraints[node].first; unsigned int row_size = row.size(); pushed_node_keys[i].reserve(row_size); pushed_node_vals[i].reserve(row_size); @@ -1102,6 +1335,7 @@ pushed_node_keys[i].push_back(j->first->id()); pushed_node_vals[i].push_back(j->second); } + pushed_node_offsets[i] = _node_constraints[node].second; } #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS @@ -1109,28 +1343,36 @@ std::vector<unsigned int> pushed_ids_to_me; std::vector<std::vector<unsigned int> > pushed_keys_to_me; std::vector<std::vector<Real> > pushed_vals_to_me; + std::vector<Number> pushed_rhss_to_me; Parallel::send_receive(procup, pushed_ids[procup], procdown, pushed_ids_to_me); Parallel::send_receive(procup, pushed_keys, procdown, pushed_keys_to_me); Parallel::send_receive(procup, pushed_vals, procdown, pushed_vals_to_me); + Parallel::send_receive(procup, pushed_rhss, + procdown, pushed_rhss_to_me); libmesh_assert (pushed_ids_to_me.size() == pushed_keys_to_me.size()); libmesh_assert (pushed_ids_to_me.size() == pushed_vals_to_me.size()); + libmesh_assert (pushed_ids_to_me.size() == pushed_rhss_to_me.size()); #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS // Trade pushed node constraint rows std::vector<unsigned int> pushed_node_ids_to_me; std::vector<std::vector<unsigned int> > pushed_node_keys_to_me; std::vector<std::vector<Real> > pushed_node_vals_to_me; + std::vector<Point> pushed_node_offsets_to_me; Parallel::send_receive(procup, pushed_node_ids[procup], procdown, pushed_node_ids_to_me); Parallel::send_receive(procup, pushed_node_keys, procdown, pushed_node_keys_to_me); Parallel::send_receive(procup, pushed_node_vals, procdown, pushed_node_vals_to_me); + Parallel::send_receive(procup, pushed_node_offsets, + procdown, pushed_node_offsets_to_me); libmesh_assert (pushed_node_ids_to_me.size() == pushed_node_keys_to_me.size()); libmesh_assert (pushed_node_ids_to_me.size() == pushed_node_vals_to_me.size()); + libmesh_assert (pushed_node_ids_to_me.size() == pushed_node_offsets_to_me.size()); #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS // Add the dof constraints that I've been sent @@ -1144,11 +1386,12 @@ // add the one we were sent if (!this->is_constrained_dof(constrained)) { - DofConstraintRow &row = _dof_constraints[constrained]; + DofConstraintRow &row = _dof_constraints[constrained].first; for (unsigned int j = 0; j != pushed_keys_to_me[i].size(); ++j) { row[pushed_keys_to_me[i][j]] = pushed_vals_to_me[i][j]; } + _dof_constraints[constrained].second = pushed_rhss_to_me[i]; } } @@ -1165,13 +1408,14 @@ const Node *constrained = mesh.node_ptr(constrained_id); if (!this->is_constrained_node(constrained)) { - NodeConstraintRow &row = _node_constraints[constrained]; + NodeConstraintRow &row = _node_constraints[constrained].first; for (unsigned int j = 0; j != pushed_node_keys_to_me[i].size(); ++j) { const Node *key_node = mesh.node_ptr(pushed_node_keys_to_me[i][j]); libmesh_assert(key_node); row[key_node] = pushed_node_vals_to_me[i][j]; } + _node_constraints[constrained].second = pushed_node_offsets_to_me[i]; } } #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS @@ -1228,7 +1472,7 @@ for (DoF_RCSet::iterator i = unexpanded_dofs.begin(); i != unexpanded_dofs.end(); ++i) { - DofConstraintRow &row = _dof_constraints[*i]; + DofConstraintRow &row = _dof_constraints[*i].first; for (DofConstraintRow::iterator j = row.begin(); j != row.end(); ++j) dof_request_set.insert(j->first); @@ -1238,7 +1482,7 @@ for (Node_RCSet::iterator i = unexpanded_nodes.begin(); i != unexpanded_nodes.end(); ++i) { - NodeConstraintRow &row = _node_constraints[*i]; + NodeConstraintRow &row = _node_constraints[*i].first; for (NodeConstraintRow::iterator j = row.begin(); j != row.end(); ++j) { @@ -1314,12 +1558,14 @@ node_row_keys(node_request_to_fill.size()); std::vector<std::vector<Real> > dof_row_vals(dof_request_to_fill.size()), node_row_vals(node_request_to_fill.size()); + std::vector<Number> dof_row_rhss(dof_request_to_fill.size()); + std::vector<Point> node_row_rhss(node_request_to_fill.size()); for (unsigned int i=0; i != dof_request_to_fill.size(); ++i) { unsigned int constrained = dof_request_to_fill[i]; if (_dof_constraints.count(constrained)) { - DofConstraintRow &row = _dof_constraints[constrained]; + DofConstraintRow &row = _dof_constraints[constrained].first; unsigned int row_size = row.size(); dof_row_keys[i].reserve(row_size); dof_row_vals[i].reserve(row_size); @@ -1329,6 +1575,7 @@ dof_row_keys[i].push_back(j->first); dof_row_vals[i].push_back(j->second); } + dof_row_rhss[i] = _dof_constraints[constrained].second; } } @@ -1339,7 +1586,7 @@ const Node *constrained_node = mesh.node_ptr(constrained_id); if (_node_constraints.count(constrained_node)) { - const NodeConstraintRow &row = _node_constraints[constrained_node]; + const NodeConstraintRow &row = _node_constraints[constrained_node].first; unsigned int row_size = row.size(); node_row_keys[i].reserve(row_size); node_row_vals[i].reserve(row_size); @@ -1349,6 +1596,7 @@ node_row_keys[i].push_back(j->first->id()); node_row_vals[i].push_back(j->second); } + node_row_rhss[i] = _node_constraints[constrained_node].second; } } #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS @@ -1358,6 +1606,8 @@ node_filled_keys; std::vector<std::vector<Real> > dof_filled_vals, node_filled_vals; + std::vector<Number> dof_filled_rhss; + std::vector<Point> node_filled_rhss; Parallel::send_receive(procdown, dof_row_keys, procup, dof_filled_keys); Parallel::send_receive(procdown, dof_row_vals, @@ -1367,11 +1617,15 @@ procup, node_filled_keys); Parallel::send_receive(procdown, node_row_vals, procup, node_filled_vals); + Parallel::send_receive(procdown, node_row_rhss, + procup, node_filled_rhss); #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS libmesh_assert (dof_filled_keys.size() == requested_dof_ids[procup].size()); libmesh_assert (dof_filled_vals.size() == requested_dof_ids[procup].size()); + libmesh_assert (dof_filled_rhss.size() == requested_dof_ids[procup].size()); libmesh_assert (node_filled_keys.size() == requested_node_ids[procup].size()); libmesh_assert (node_filled_vals.size() == requested_node_ids[procup].size()); + libmesh_assert (node_filled_rhss.size() == requested_node_ids[procup].size()); // Add any new constraint rows we've found for (unsigned int i=0; i != requested_dof_ids[procup].size(); ++i) @@ -1381,9 +1635,10 @@ if (!dof_filled_keys[i].empty()) { unsigned int constrained = requested_dof_ids[procup][i]; - DofConstraintRow &row = _dof_constraints[constrained]; + DofConstraintRow &row = _dof_constraints[constrained].first; for (unsigned int j = 0; j != dof_filled_keys[i].size(); ++j) row[dof_filled_keys[i][j]] = dof_filled_vals[i][j]; + _dof_constraints[constrained].second = dof_filled_rhss[i]; // And prepare to check for more recursive constraints unexpanded_dofs.insert(constrained); @@ -1398,7 +1653,7 @@ { unsigned int constrained_id = requested_node_ids[procup][i]; const Node* constrained_node = mesh.node_ptr(constrained_id); - NodeConstraintRow &row = _node_constraints[constrained_node]; + NodeConstraintRow &row = _node_constraints[constrained_node].first; for (unsigned int j = 0; j != node_filled_keys[i].size(); ++j) { const Node* key_node = @@ -1406,6 +1661,7 @@ libmesh_assert(key_node); row[key_node] = node_filled_vals[i][j]; } + _node_constraints[constrained_node].second = node_filled_rhss[i]; // And prepare to check for more recursive constraints unexpanded_nodes.insert(constrained_node); @@ -1444,14 +1700,14 @@ libmesh_assert (pos != _dof_constraints.end()); - DofConstraintRow& constraint_row = pos->second; + DofConstraintRow& constraint_row = pos->second.first; std::vector<unsigned int> constraints_to_expand; for (DofConstraintRow::const_iterator it=constraint_row.begin(); it != constraint_row.end(); ++it) - if (this->is_constrained_dof(it->first)) + if (it->first != *i && this->is_constrained_dof(it->first)) { unexpanded_set.insert(it->first); constraints_to_expand.push_back(it->first); @@ -1467,7 +1723,7 @@ libmesh_assert (subpos != _dof_constraints.end()); - const DofConstraintRow& subconstraint_row = subpos->second; + const DofConstraintRow& subconstraint_row = subpos->second.first; for (DofConstraintRow::const_iterator it=subconstraint_row.begin(); @@ -1518,7 +1774,7 @@ constrained_dof >= this->end_dof()) continue; - DofConstraintRow& constraint_row = i->second; + DofConstraintRow& constraint_row = i->second.first; for (DofConstraintRow::const_iterator j=constraint_row.begin(); j != constraint_row.end(); ++j) @@ -1582,7 +1838,10 @@ // Add "this is zero" constraint rows for high p vertex // dofs for (unsigned int i = low_nc; i != high_nc; ++i) - _dof_constraints[node->dof_number(sys_num,var,i)].clear(); + { + _dof_constraints[node->dof_number(sys_num,var,i)].first.clear(); + _dof_constraints[node->dof_number(sys_num,var,i)].second = 0.; + } } else { @@ -1593,7 +1852,8 @@ for (unsigned int j = low_nc; j != high_nc; ++j) { const unsigned int i = total_dofs - j - 1; - _dof_constraints[node->dof_number(sys_num,var,i)].clear(); + _dof_constraints[node->dof_number(sys_num,var,i)].first.clear(); + _dof_constraints[node->dof_number(sys_num,var,i)].second = 0.; } } }
------------------------------------------------------------------------------ Try before you buy = See our experts in action! The most comprehensive online learning library for Microsoft developers is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3, Metro Style Apps, more. Free future releases when you subscribe now! http://p.sf.net/sfu/learndevnow-dev2
_______________________________________________ Libmesh-devel mailing list Libmesh-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libmesh-devel