template <int dim>
class ProblemInterface : public NOX::Epetra::Interface::Required,
public NOX::Epetra::Interface::Preconditioner,
public NOX::Epetra::Interface::Jacobian
{
public:
ProblemInterface(std::function<void(const TrilinosWrappers::MPI::Vector&, const TrilinosWrappers::MPI::Vector&, TrilinosWrappers::MPI::Vector&)> residual_function,
std::function<void(Epetra_CrsMatrix &)> jacobian_function,
const MPI_Comm &mpi_communicator,
const IndexSet &locally_owned_dofs,
const IndexSet &locally_relevant_dofs) :
residual_function(residual_function),
jacobian_function(jacobian_function),
mpi_communicator(mpi_communicator),
locally_owned_dofs(locally_owned_dofs),
locally_relevant_dofs(locally_relevant_dofs)
{
residual_vec.reinit(locally_owned_dofs, locally_relevant_dofs, mpi_communicator);
temp_f_vec.reinit(locally_owned_dofs, locally_relevant_dofs, mpi_communicator);
f_vec.reinit(locally_owned_dofs, locally_relevant_dofs, mpi_communicator);
};
~ProblemInterface(){
};
bool computeF(const Epetra_Vector &x, Epetra_Vector &FVec, NOX::Epetra::Interface::Required::FillType)
{
Epetra_Vector temp_f_epetra_vec = Epetra_Vector(View, temp_f_vec.trilinos_vector(), 0);
Epetra_Vector f_epetra_vec = Epetra_Vector(View, f_vec.trilinos_vector(), 0);
rhs = &FVec;
int err = 0;
err = rhs->PutScalar(0.0);
if(err != 0)
throw;
temp_f_vec = 0.;
residual_vec = 0.;
//std::cout << f_vec.size() << '\t' << locally_owned_dofs.size() << '\t' << x.MyLength() << '\n';
f_epetra_vec = x;
//Fill rhs
// Vector<double> f_vec(FVec.MyLength()), residual_vec(FVec.MyLength()), temp_f_vec(FVec.MyLength());
// for(size_t i = 0; i < f_vec.size(); ++i)
// f_vec[i] = x[i];
residual_function(temp_f_vec, f_vec, residual_vec);
FVec = Epetra_Vector(Copy, residual_vec.trilinos_vector(), 0);
return true;
}
private:
std::function<void(const TrilinosWrappers::MPI::Vector&, const TrilinosWrappers::MPI::Vector&, TrilinosWrappers::MPI::Vector&)> residual_function;
std::function<void(Epetra_CrsMatrix&)> jacobian_function;
Epetra_Vector *rhs;
MPI_Comm mpi_communicator;
IndexSet locally_owned_dofs, locally_relevant_dofs;
TrilinosWrappers::MPI::Vector f_vec, temp_f_vec, residual_vec;
};
template <int dim>
void Step5<dim>::calculate_residual(const TrilinosWrappers::MPI::Vector &u, TrilinosWrappers::MPI::Vector &residual)
{
QGauss<dim> quadrature_formula(fe.degree + 1);
FEValues<dim> fe_values(fe,
quadrature_formula,
update_values | update_gradients |
update_quadrature_points | update_JxW_values);
const unsigned int dofs_per_cell = fe.dofs_per_cell;
const unsigned int n_q_points = quadrature_formula.size();
residual.reinit(locally_owned_dofs, locally_relevant_dofs, mpi_communicator);
std::vector<Tensor<1, dim>> grad_u(quadrature_formula.size());
std::vector<double> val_u(quadrature_formula.size());
//pcout << "Create evaluation point\n";
TrilinosWrappers::MPI::Vector local_evaluation_point = TrilinosWrappers::MPI::Vector(u);
Vector<double> cell_rhs(dofs_per_cell);
std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
//pcout << "Looping over cells\n";
for (const auto &cell : dof_handler.active_cell_iterators())
{
if(cell->is_locally_owned())
{
cell_rhs = 0.;
fe_values.reinit(cell);
fe_values.get_function_values(local_evaluation_point, val_u);
fe_values.get_function_gradients(local_evaluation_point, grad_u);
for (unsigned int q = 0; q < n_q_points; ++q)
{
for (unsigned int i = 0; i < dofs_per_cell; ++i)
{
assemble_rhs(cell_rhs(i),
-1,
val_u[q],
grad_u[q],
fe_values.quadrature_point(q),
fe_values.shape_value(i, q),
fe_values.shape_grad(i, q),
fe_values.JxW(q));
}
}
cell->get_dof_indices(local_dof_indices);
hanging_node_constraints.distribute_local_to_global(cell_rhs,
local_dof_indices,
residual);
}
}
residual.compress(VectorOperation::add);
}
template <int dim>
void Step5<dim>::assemble_rhs(double &return_value,
const double factor,
const double &val_u,
const Tensor<1, dim> &grad_u,
const Point<dim> p,
const double &fe_values_value,
const Tensor<1, dim> &fe_gradient_value,
const double JxW_value)
{
(void) val_u;
return_value += factor
* (coefficient(p)
* fe_values_value
+ grad_u
* fe_gradient_value
)
* JxW_value;
}
On 4/29/19 7:35 AM, 'Maxi Miller' via deal.II User Group wrote:
> Could get it to work, now the code works equally fine for one or several
> MPI threads.
What did you have to do? I was going to reproduce your problem today by
installing a Trilinos version that has NOX enabled. Is this moot now,
i.e., was it a bug in your code or did you just work around the issue in
some way that doesn't expose it?
> Still, the next open question is how to apply non-zero
> Dirichlet boundary conditions (as in the file, for cos(pi*x)*cos(pi*y).
> When applying them as I do in the file, I get the warning that the
> solver is not converged. When using Neumann-Conditions, the solver
> converges and I get the correct output. What would be the solution for that?
The question to ask is who is right. When you get the message that the
solver is not converged, is this correct? That is, does it converge if
you allow more iterations? What if you use a case where you know the
exact solution -- is the computed solution actively wrong?
Maxi,
> What did you have to do? I was going to reproduce your problem today by
> installing a Trilinos version that has NOX enabled. Is this moot now,
> i.e., was it a bug in your code or did you just work around the issue in
> some way that doesn't expose it?
>
> NOX expects vectors containing only the local elements, but no ghost elements.
> Thus I had to initialize all vectors going in or out from any NOX-related
> function using locally_owned_dofs, and copy accordingly if external vectors
> contained ghost elements.
I see. So this is a NOX requirement, not something that we could have done
anything about on the deal.II side?
> The solver does not converge, and the output looks as if it is using
> Dirichlet-conditions with u = 0, independently of the "real" boundary conditions.
I don't know NOX, but is it using an update that it adds to the solution in
each step? If so, you need to have the correct boundary conditions in the
initial guess already. What happens if you only allow NOX to do zero or one
iterations?
Best
W.