// pointers to these functions to the MeshWorker framework. If, however,
// these functions would want to access member variables (or needed
// additional arguments beyond the ones specified below), we could use the
- // facilities of boost::bind (or std::bind, respectively) to provide the
+ // facilities of lambda functions to provide the
// MeshWorker framework with objects that act as if they had the required
// number and types of arguments, but have in fact other arguments already
// bound.
// integrator class are not actually function pointers. Rather, they are
// objects that can be called like functions with a certain number of
// arguments. Consequently, we could also pass objects with appropriate
- // operator() implementations here, or the result of std::bind if the local
+ // operator() implementations here, or lambda functions if the local
// integrators were, for example, non-static member functions.
MeshWorker::loop<dim,
dim,
Threads::Task<> rhs_task =
Threads::new_task(&Solver<dim>::assemble_rhs, *this, linear_system.rhs);
- WorkStream::run(dof_handler.begin_active(),
- dof_handler.end(),
- std::bind(&Solver<dim>::local_assemble_matrix,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3),
- std::bind(&Solver<dim>::copy_local_to_global,
- this,
- std::placeholders::_1,
- std::ref(linear_system)),
- AssemblyScratchData(*fe, *quadrature),
- AssemblyCopyData());
+ WorkStream::run(
+ dof_handler.begin_active(),
+ dof_handler.end(),
+ [this](const typename DoFHandler<dim>::active_cell_iterator &cell,
+ AssemblyScratchData &scratch_data,
+ AssemblyCopyData & copy_data) {
+ this->local_assemble_matrix(cell, scratch_data, copy_data);
+ },
+ [this, &linear_system](const AssemblyCopyData ©_data) {
+ this->copy_local_to_global(copy_data, linear_system);
+ },
+ AssemblyScratchData(*fe, *quadrature),
+ AssemblyCopyData());
linear_system.hanging_node_constraints.condense(linear_system.matrix);
- // The syntax above using <code>std::bind</code> requires
+ // The syntax above using lambda functions requires
// some explanation. There are multiple version of
// WorkStream::run that expect different arguments. In step-9,
// we used one version that took a pair of iterators, a pair of
// function that just takes function objects -- objects that
// have an <code>operator()</code> and that consequently can be
// called like functions, whatever they really represent. The
- // typical way to generate such function objects is using
- // <code>std::bind</code> (or, if the compiler is too old, a
- // replacement for it, which we generically call
- // <code>std::bind</code>) which takes a pointer to a
- // (member) function and then <i>binds</i> individual arguments
- // to fixed values. For example, you can create a function that
- // takes an iterator, a scratch object and a copy object by
- // taking the address of a member function and binding the
- // (implicit) argument to the object on which it is to work to
- // <code>*this</code>. This is what we do in the first call
- // above. In the second call, we need to create a function
- // object that takes a copy object, and we do so by taking the
- // address of a member function that takes an implicit pointer
- // to <code>*this</code>, a reference to a copy object, and a
- // reference to a linear system, and binding the first and third
- // of these, leaving something that has only one open argument
- // that can then be filled by WorkStream::run().
+ // typical way to generate such function objects is using a
+ // <a href="http://en.wikipedia.org/wiki/Anonymous_function">lambda
+ // function</a> that wraps the function call including the individual
+ // arguments with fixed values. The fixed values are passed into the
+ // lambda function using the capture list
+ // ([...]). All the other arguments the wrapped function requires and are
+ // part of the outer function signature are specified as regular function
+ // parameters in the lambda function.
//
- // There remains the question of what the
- // <code>std::placeholders::_1</code>, <code>std::placeholders::_2</code>,
- // etc., mean. (These arguments are called <i>placeholders</i>.) The idea
- // of using <code>std::bind</code> in the first of the two cases above is
- // that it produces an object that can be called with three arguments. But
- // how are the three arguments the function object is being called with
- // going to be distributed to the four arguments
- // <code>local_assemble_matrix()</code> (including the implicit
- // <code>this</code> pointer)? As specified, the first argument
- // given to the function object will become the first argument
- // given to <code>local_assemble_matrix()</code>, the second the
- // second, etc. This is trivial here, but allows for interesting
- // games in other circumstances. Consider, for example, having a
- // function <code>void f(double x, double y)</code>. Then,
- // creating a variable <code>p</code> of type
- // <code>std::function@<void f(double,double)@></code> and
- // initializing <code>p=std::bind(&f, std::placeholders::_2,
- // std::placeholders::_1)</code> then calling <code>p(1,2)</code> will
- // result in calling <code>f(2,1)</code>.
- //
- // @note An alternative to using <code>std::bind</code> is to use C++'s
- // version of <a
- // href="http://en.wikipedia.org/wiki/Anonymous_function">lambda
- // functions</a>. In essence, a lambda function is a function without a
- // name that is defined right at the one place where it is going to be
- // used -- i.e., where we pass the third and fourth argument to
- // WorkStream::run. The functions one would define in these locations
- // would take 3 and 1 arguments, respectively, and all they do is call
- // <code>Solver::local_assemble_matrix</code> and
- // <code>Solver::copy_local_to_global</code> with the required number of
- // arguments, utilizing what the lambda function has gotten as arguments
- // itself. We won't show the syntax this would require since it is no
- // less confusing than the one used above.
-
// At this point, we have assembled the matrix and condensed
// it. The right hand side may or may not have been completely
// assembled, but we would like to condense the right hand side
Threads::Task<> rhs_task =
Threads::new_task(&Solver<dim>::assemble_rhs, *this, linear_system.rhs);
- WorkStream::run(dof_handler.begin_active(),
- dof_handler.end(),
- std::bind(&Solver<dim>::local_assemble_matrix,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3),
- std::bind(&Solver<dim>::copy_local_to_global,
- this,
- std::placeholders::_1,
- std::ref(linear_system)),
- AssemblyScratchData(*fe, *quadrature),
- AssemblyCopyData());
+ WorkStream::run(
+ dof_handler.begin_active(),
+ dof_handler.end(),
+ [this](const typename DoFHandler<dim>::active_cell_iterator &cell,
+ AssemblyScratchData &scratch_data,
+ AssemblyCopyData & copy_data) {
+ this->local_assemble_matrix(cell, scratch_data, copy_data);
+ },
+ [this, &linear_system](const AssemblyCopyData ©_data) {
+ this->copy_local_to_global(copy_data, linear_system);
+ },
+ AssemblyScratchData(*fe, *quadrature),
+ AssemblyCopyData());
linear_system.hanging_node_constraints.condense(linear_system.matrix);
std::map<types::global_dof_index, double> boundary_value_map;
WorkStream::run(
DualSolver<dim>::dof_handler.begin_active(),
DualSolver<dim>::dof_handler.end(),
- std::bind(&WeightedResidual<dim>::estimate_on_one_cell,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3,
- std::ref(error_indicators),
- std::ref(face_integrals)),
+ [this,
+ &error_indicators,
+ &face_integrals](const active_cell_iterator & cell,
+ WeightedResidualScratchData &scratch_data,
+ WeightedResidualCopyData & copy_data) {
+ this->estimate_on_one_cell(
+ cell, scratch_data, copy_data, error_indicators, face_integrals);
+ },
std::function<void(const WeightedResidualCopyData &)>(),
WeightedResidualScratchData(*DualSolver<dim>::fe,
*DualSolver<dim>::quadrature,
std::pair<std::vector<unsigned int>, std::vector<double>> res =
FESeries::process_coefficients<dim>(
fourier_coefficients,
- std::bind(&LaplaceProblem<dim>::predicate,
- this,
- std::placeholders::_1),
+ [this](const TableIndices<dim> &indices) {
+ return this->predicate(indices);
+ },
VectorTools::Linfty_norm);
Assert(res.first.size() == res.second.size(), ExcInternalError());
// specific signatures: three arguments in the first and one
// argument in the latter case (see the documentation of the
// WorkStream::run function for the meaning of these arguments).
- // Note how we use the construct <code>std::bind</code> to
+ // Note how we use a lambda functions to
// create a function object that satisfies this requirement. It uses
- // placeholders <code>std::placeholders::_1, std::placeholders::_2,
- // std::placeholders::_3</code> for the local assembly function that specify
- // cell, scratch data, and copy data, as well as the placeholder
- // <code>std::placeholders::_1</code> for the copy function that expects the
- // data to be written into the global matrix (for placeholder
- // arguments, also see the discussion in step-13's
- // <code>assemble_linear_system()</code> function). On the other
+ // function arguments for the local assembly function that specify
+ // cell, scratch data, and copy data, as well as function argument
+ // for the copy function that expects the
+ // data to be written into the global matrix (also see the discussion in
+ // step-13's <code>assemble_linear_system()</code> function). On the other
// hand, the implicit zeroth argument of member functions (namely
// the <code>this</code> pointer of the object on which that member
// function is to operate on) is <i>bound</i> to the
- // <code>this</code> pointer of the current function. The
+ // <code>this</code> pointer of the current function and is captured. The
// WorkStream::run function, as a consequence, does not need to know
// anything about the object these functions work on.
//
CellFilter(IteratorFilters::LocallyOwnedCell(),
stokes_dof_handler.begin_active()),
CellFilter(IteratorFilters::LocallyOwnedCell(), stokes_dof_handler.end()),
- std::bind(
- &BoussinesqFlowProblem<dim>::local_assemble_stokes_preconditioner,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3),
- std::bind(
- &BoussinesqFlowProblem<dim>::copy_local_to_global_stokes_preconditioner,
- this,
- std::placeholders::_1),
+ [this](const typename DoFHandler<dim>::active_cell_iterator &cell,
+ Assembly::Scratch::StokesPreconditioner<dim> & scratch,
+ Assembly::CopyData::StokesPreconditioner<dim> & data) {
+ this->local_assemble_stokes_preconditioner(cell, scratch, data);
+ },
+ [this](const Assembly::CopyData::StokesPreconditioner<dim> &data) {
+ this->copy_local_to_global_stokes_preconditioner(data);
+ },
Assembly::Scratch::StokesPreconditioner<dim>(stokes_fe,
quadrature_formula,
mapping,
CellFilter(IteratorFilters::LocallyOwnedCell(),
stokes_dof_handler.begin_active()),
CellFilter(IteratorFilters::LocallyOwnedCell(), stokes_dof_handler.end()),
- std::bind(&BoussinesqFlowProblem<dim>::local_assemble_stokes_system,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3),
- std::bind(&BoussinesqFlowProblem<dim>::copy_local_to_global_stokes_system,
- this,
- std::placeholders::_1),
+ [this](const typename DoFHandler<dim>::active_cell_iterator &cell,
+ Assembly::Scratch::StokesSystem<dim> & scratch,
+ Assembly::CopyData::StokesSystem<dim> & data) {
+ this->local_assemble_stokes_system(cell, scratch, data);
+ },
+ [this](const Assembly::CopyData::StokesSystem<dim> &data) {
+ this->copy_local_to_global_stokes_system(data);
+ },
Assembly::Scratch::StokesSystem<dim>(
stokes_fe,
mapping,
temperature_dof_handler.begin_active()),
CellFilter(IteratorFilters::LocallyOwnedCell(),
temperature_dof_handler.end()),
- std::bind(&BoussinesqFlowProblem<dim>::local_assemble_temperature_matrix,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3),
- std::bind(
- &BoussinesqFlowProblem<dim>::copy_local_to_global_temperature_matrix,
- this,
- std::placeholders::_1),
+ [this](const typename DoFHandler<dim>::active_cell_iterator &cell,
+ Assembly::Scratch::TemperatureMatrix<dim> & scratch,
+ Assembly::CopyData::TemperatureMatrix<dim> & data) {
+ this->local_assemble_temperature_matrix(cell, scratch, data);
+ },
+ [this](const Assembly::CopyData::TemperatureMatrix<dim> &data) {
+ this->copy_local_to_global_temperature_matrix(data);
+ },
Assembly::Scratch::TemperatureMatrix<dim>(temperature_fe,
mapping,
quadrature_formula),
temperature_dof_handler.begin_active()),
CellFilter(IteratorFilters::LocallyOwnedCell(),
temperature_dof_handler.end()),
- std::bind(&BoussinesqFlowProblem<dim>::local_assemble_temperature_rhs,
- this,
- global_T_range,
- maximal_velocity,
- global_entropy_variation,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3),
- std::bind(
- &BoussinesqFlowProblem<dim>::copy_local_to_global_temperature_rhs,
- this,
- std::placeholders::_1),
+ [this, global_T_range, maximal_velocity, global_entropy_variation](
+ const typename DoFHandler<dim>::active_cell_iterator &cell,
+ Assembly::Scratch::TemperatureRHS<dim> & scratch,
+ Assembly::CopyData::TemperatureRHS<dim> & data) {
+ this->local_assemble_temperature_rhs(global_T_range,
+ maximal_velocity,
+ global_entropy_variation,
+ cell,
+ scratch,
+ data);
+ },
+ [this](const Assembly::CopyData::TemperatureRHS<dim> &data) {
+ this->copy_local_to_global_temperature_rhs(data);
+ },
Assembly::Scratch::TemperatureRHS<dim>(
temperature_fe, stokes_fe, mapping, quadrature_formula),
Assembly::CopyData::TemperatureRHS<dim>(temperature_fe));
// call to WorkStream because assemble_system_tangent_one_cell
// is a constant function and copy_local_to_global_K is
// non-constant.
- WorkStream::run(dof_handler.active_cell_iterators(),
- std::bind(&Solid<dim>::assemble_system_tangent_one_cell,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3),
- std::bind(&Solid<dim>::copy_local_to_global_K,
- this,
- std::placeholders::_1),
- scratch_data,
- per_task_data);
+ WorkStream::run(
+ dof_handler.active_cell_iterators(),
+ [this](const typename DoFHandler<dim>::active_cell_iterator &cell,
+ ScratchData_K & scratch,
+ PerTaskData_K & data) {
+ this->assemble_system_tangent_one_cell(cell, scratch, data);
+ },
+ [this](const PerTaskData_K &data) { this->copy_local_to_global_K(data); },
+ scratch_data,
+ per_task_data);
timer.leave_subsection();
}
PerTaskData_RHS per_task_data(dofs_per_cell);
ScratchData_RHS scratch_data(fe, qf_cell, uf_cell, qf_face, uf_face);
- WorkStream::run(dof_handler.active_cell_iterators(),
- std::bind(&Solid<dim>::assemble_system_rhs_one_cell,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3),
- std::bind(&Solid<dim>::copy_local_to_global_rhs,
- this,
- std::placeholders::_1),
- scratch_data,
- per_task_data);
+ WorkStream::run(
+ dof_handler.active_cell_iterators(),
+ [this](const typename DoFHandler<dim>::active_cell_iterator &cell,
+ ScratchData_RHS & scratch,
+ PerTaskData_RHS & data) {
+ this->assemble_system_rhs_one_cell(cell, scratch, data);
+ },
+ [this](const PerTaskData_RHS &data) {
+ this->copy_local_to_global_rhs(data);
+ },
+ scratch_data,
+ per_task_data);
timer.leave_subsection();
}
// the address of a function that takes a point and returns a point, an object
// that has an <code>operator()</code> like the code below, or for example, a
// <code>std::function@<Point@<2@>(const Point@<2@>)@></code> object one can
-// get via <code>std::bind</code> in more complex cases. Here we have a simple
-// transformation and use the simplest method: a lambda function.
+// get as a lambda function. Here we choose the latter option.
void grid_5()
{
Triangulation<2> triangulation;
PostProcessScratchData scratch(
fe_u_post, fe_local, quadrature_formula, local_flags, flags);
- WorkStream::run(dof_handler_u_post.begin_active(),
- dof_handler_u_post.end(),
- std::bind(&HDG<dim>::postprocess_one_cell,
- std::ref(*this),
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3),
- std::function<void(const unsigned int &)>(),
- scratch,
- 0U);
+ WorkStream::run(
+ dof_handler_u_post.begin_active(),
+ dof_handler_u_post.end(),
+ [this](const typename DoFHandler<dim>::active_cell_iterator &cell,
+ PostProcessScratchData & scratch,
+ unsigned int & data) {
+ this->postprocess_one_cell(cell, scratch, data);
+ },
+ [](const unsigned int &) {},
+ scratch,
+ 0U);
}
Vector<float> difference_per_cell(triangulation.n_active_cells());