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
[email protected]
https://lists.sourceforge.net/lists/listinfo/libmesh-devel