cleanup
This commit is contained in:
@@ -14,10 +14,6 @@ namespace mfem::future
|
||||
namespace LocalQFImpl
|
||||
{
|
||||
|
||||
// Applies J^T using the cached Jacobian from DerivativeSetup.
|
||||
// Inputs/outputs play swapped roles compared to DerivativeApply:
|
||||
// direction_l : concatenated OUTPUT L-space direction (test space)
|
||||
// ye : element-space result in INPUT space (trial/derivative field)
|
||||
template<
|
||||
int derivative_id,
|
||||
typename qfunc_t,
|
||||
@@ -154,10 +150,10 @@ struct DerivativeApplyTranspose
|
||||
// [dir_at_qp region] [result_at_qp region] [scratch]
|
||||
const int output_size_on_qp =
|
||||
std::accumulate(out_qp_size.begin(), out_qp_size.end(), 0);
|
||||
dir_at_qp_offset = 0;
|
||||
dir_at_qp_offset = 0;
|
||||
result_at_qp_offset = output_size_on_qp * num_qp;
|
||||
scratch_offset = result_at_qp_offset
|
||||
+ trial_vdim * total_trial_op_dim * num_qp;
|
||||
scratch_offset =
|
||||
result_at_qp_offset + trial_vdim * total_trial_op_dim * num_qp;
|
||||
|
||||
// Conservative scratch: 6 * q1d^3 (matches get_shmem_info).
|
||||
const int scratch_per_buf = (q1d > 0) ? q1d * q1d * q1d : 1;
|
||||
@@ -182,13 +178,11 @@ struct DerivativeApplyTranspose
|
||||
"DerivativeApplyTranspose: derivative field not found in infds");
|
||||
|
||||
// Number of DOFs per element for the derivative input field.
|
||||
{
|
||||
const auto &fd = ctx.infds[deriv_infd_idx];
|
||||
auto R = get_restriction<Entity::Element>(fd, dof_ordering);
|
||||
MFEM_ASSERT(R != nullptr,
|
||||
"LocalQFBackend: missing element restriction for deriv input");
|
||||
deriv_in_elem_sz = num_entities ? (R->Height() / num_entities) : 0;
|
||||
}
|
||||
const auto &fd = ctx.infds[deriv_infd_idx];
|
||||
auto R = get_restriction<Entity::Element>(fd, dof_ordering);
|
||||
MFEM_ASSERT(R != nullptr,
|
||||
"LocalQFBackend: missing element restriction for deriv input");
|
||||
deriv_in_elem_sz = num_entities ? (R->Height() / num_entities) : 0;
|
||||
}
|
||||
|
||||
void operator()(
|
||||
@@ -198,30 +192,26 @@ struct DerivativeApplyTranspose
|
||||
{
|
||||
if (ctx.attr.Size() == 0) { return; }
|
||||
|
||||
// --- Restrict OUTPUT direction from L-space to element space ---
|
||||
// direction_l is the concatenation of L-space vectors for each outfd.
|
||||
int l_offset = 0;
|
||||
int e_offset = 0;
|
||||
for_constexpr<noutputs>([&](auto o)
|
||||
{
|
||||
int l_offset = 0;
|
||||
int e_offset = 0;
|
||||
for_constexpr<noutputs>([&](auto o)
|
||||
{
|
||||
const size_t outfd_idx = output_to_outfd[o];
|
||||
const auto &fd = ctx.outfds[outfd_idx];
|
||||
const int l_size = GetVSize(fd);
|
||||
const size_t outfd_idx = output_to_outfd[o];
|
||||
const auto &fd = ctx.outfds[outfd_idx];
|
||||
const int l_size = GetVSize(fd);
|
||||
|
||||
Vector dir_o_l(const_cast<real_t *>(direction_l->GetData()) + l_offset,
|
||||
l_size);
|
||||
Vector dir_o_l(const_cast<real_t *>(direction_l->GetData()) + l_offset,
|
||||
l_size);
|
||||
|
||||
// Temporary element-space slice for output o.
|
||||
const int e_size = out_elem_dof_size[o] * num_entities;
|
||||
Vector dir_o_e(dir_out_e.GetData() + e_offset, e_size);
|
||||
// Temporary element-space slice for output o.
|
||||
const int e_size = out_elem_dof_size[o] * num_entities;
|
||||
Vector dir_o_e(dir_out_e.GetData() + e_offset, e_size);
|
||||
|
||||
restriction<Entity::Element>(fd, dir_o_l, dir_o_e, dof_ordering);
|
||||
restriction<Entity::Element>(fd, dir_o_l, dir_o_e, dof_ordering);
|
||||
|
||||
l_offset += l_size;
|
||||
e_offset += e_size;
|
||||
});
|
||||
}
|
||||
l_offset += l_size;
|
||||
e_offset += e_size;
|
||||
});
|
||||
|
||||
// Wrap output direction element data as [elem_dof, entity].
|
||||
// Offsets into dir_out_e for each output field.
|
||||
@@ -307,8 +297,6 @@ struct DerivativeApplyTranspose
|
||||
scratch_buf_size);
|
||||
}
|
||||
|
||||
// --- Step 1: Map OUTPUT direction element DOFs → QPs ---
|
||||
// Concatenate per-output dir_at_qp slices.
|
||||
int qp_offset = 0;
|
||||
for_constexpr<noutputs>([&](auto o)
|
||||
{
|
||||
@@ -344,9 +332,9 @@ struct DerivativeApplyTranspose
|
||||
});
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// --- Step 2: Contract J^T ---
|
||||
// Forward: result(i,k,q) = sum_{j,m} J(i,k,j,m,q) * dir(j,m,q)
|
||||
// Transpose: result(j,m,q) = sum_{i,k} J(i,k,j,m,q) * dir(i,k,q)
|
||||
// contract J^T
|
||||
// forward: result(i,k,q) = sum_{j,m} J(i,k,j,m,q) * dir(j,m,q)
|
||||
// transpose: result(j,m,q) = sum_{i,k} J(i,k,j,m,q) * dir(i,k,q)
|
||||
MFEM_FOREACH_THREAD(q, x, num_qp_local)
|
||||
{
|
||||
for (int j = 0; j < trial_vdim_local; j++)
|
||||
@@ -390,7 +378,6 @@ struct DerivativeApplyTranspose
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// --- Step 3: Map result QPs → INPUT derivative element DOFs ---
|
||||
auto ye_deriv = DeviceTensor<2, real_t>(
|
||||
ye_deriv_ptr, deriv_in_elem_sz_local, num_entities_local);
|
||||
auto result_dof = Reshape(&ye_deriv(0, e), deriv_in_elem_sz_local / trial_vdim_local,
|
||||
@@ -416,26 +403,26 @@ struct DerivativeApplyTranspose
|
||||
}
|
||||
|
||||
IntegratorContext ctx;
|
||||
qfunc_t qfunc;
|
||||
inputs_t inputs;
|
||||
qfunc_t qfunc;
|
||||
inputs_t inputs;
|
||||
outputs_t outputs;
|
||||
const Vector &qp_cache;
|
||||
|
||||
std::array<size_t, noutputs> output_to_outfd;
|
||||
std::array<size_t, ninputs> input_to_field;
|
||||
std::array<size_t, ninputs> input_to_field;
|
||||
std::array<size_t, noutputs> output_to_field;
|
||||
|
||||
int dimension = 0;
|
||||
int dimension = 0;
|
||||
int num_entities = 0;
|
||||
int num_qp = 0;
|
||||
int q1d = 0;
|
||||
int num_qp = 0;
|
||||
int q1d = 0;
|
||||
bool use_sum_factorization = false;
|
||||
ElementDofOrdering dof_ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
|
||||
ThreadBlocks thread_blocks;
|
||||
|
||||
std::vector<const DofToQuad*> dtqs;
|
||||
std::array<DofToQuadMap, ninputs> input_dtq_maps;
|
||||
std::vector<const DofToQuad*> dtqs;
|
||||
std::array<DofToQuadMap, ninputs> input_dtq_maps;
|
||||
std::array<DofToQuadMap, noutputs> output_dtq_maps;
|
||||
|
||||
std::array<int, noutputs> out_qp_size;
|
||||
@@ -447,17 +434,17 @@ struct DerivativeApplyTranspose
|
||||
std::vector<int> input_size_on_qp;
|
||||
std::array<bool, ninputs> input_is_dependent;
|
||||
|
||||
int trial_vdim = 1;
|
||||
int total_trial_op_dim = 0;
|
||||
size_t deriv_input_idx = SIZE_MAX;
|
||||
size_t deriv_infd_idx = SIZE_MAX;
|
||||
int deriv_in_elem_sz = 0;
|
||||
int trial_vdim = 1;
|
||||
int total_trial_op_dim = 0;
|
||||
size_t deriv_input_idx = SIZE_MAX;
|
||||
size_t deriv_infd_idx = SIZE_MAX;
|
||||
int deriv_in_elem_sz = 0;
|
||||
|
||||
// Shared memory layout offsets (in reals).
|
||||
int dir_at_qp_offset = 0;
|
||||
// Shared memory layout offsets (in real_t).
|
||||
int dir_at_qp_offset = 0;
|
||||
int result_at_qp_offset = 0;
|
||||
int scratch_offset = 0;
|
||||
int shmem_per_elem = 0;
|
||||
int scratch_offset = 0;
|
||||
int shmem_per_elem = 0;
|
||||
|
||||
mutable Vector shmem_cache;
|
||||
mutable Vector dir_out_e;
|
||||
|
||||
@@ -25,7 +25,7 @@ template<
|
||||
struct DerivativeAssemble
|
||||
{
|
||||
static constexpr auto inout_tuple =
|
||||
merge_mfem_tuples_as_empty_std_tuple(inputs_t {}, outputs_t {});
|
||||
merge_mfem_tuples_as_empty_std_tuple(inputs_t {}, outputs_t {});
|
||||
static constexpr auto filtered_inout_tuple = filter_fields(inout_tuple);
|
||||
static constexpr size_t nfields = count_unique_field_ids(filtered_inout_tuple);
|
||||
|
||||
@@ -108,9 +108,9 @@ struct DerivativeAssemble
|
||||
|
||||
// Get test and trial spaces
|
||||
test_fes = std::get_if<const ParFiniteElementSpace *>(
|
||||
&ctx.unionfds[test_field_idx].data);
|
||||
&ctx.unionfds[test_field_idx].data);
|
||||
trial_fes = std::get_if<const ParFiniteElementSpace *>(
|
||||
&ctx.unionfds[trial_field_idx].data);
|
||||
&ctx.unionfds[trial_field_idx].data);
|
||||
|
||||
MFEM_ASSERT(test_fes != nullptr && *test_fes != nullptr,
|
||||
"LocalQFBackend: test space is not a ParFiniteElementSpace");
|
||||
@@ -144,16 +144,19 @@ struct DerivativeAssemble
|
||||
// Accumulate trial_op_dim for all dependent inputs
|
||||
if (input_is_dependent[i])
|
||||
{
|
||||
total_trial_op_dim += get<i>(this->inputs).size_on_qp / get<i>(this->inputs).vdim;
|
||||
total_trial_op_dim += get<i>(this->inputs).size_on_qp / get<i>
|
||||
(this->inputs).vdim;
|
||||
}
|
||||
});
|
||||
|
||||
MFEM_ASSERT(trial_vdim > 0, "LocalQFBackend: could not determine trial vdim");
|
||||
MFEM_ASSERT(total_trial_op_dim > 0, "LocalQFBackend: no dependent inputs found");
|
||||
MFEM_ASSERT(total_trial_op_dim > 0,
|
||||
"LocalQFBackend: no dependent inputs found");
|
||||
|
||||
num_trial_dof = (*trial_fes)->GetFE(0)->GetDof();
|
||||
num_trial_dof_1d = (dimension > 0) ?
|
||||
static_cast<int>(std::floor(std::pow(num_trial_dof, 1.0 / dimension) + 0.5)) : 0;
|
||||
static_cast<int>(std::floor(std::pow(num_trial_dof,
|
||||
1.0 / dimension) + 0.5)) : 0;
|
||||
|
||||
// Setup DofToQuad maps
|
||||
dtqs.reserve(ctx.unionfds.size());
|
||||
@@ -203,7 +206,8 @@ struct DerivativeAssemble
|
||||
{
|
||||
if (input_is_dependent[i])
|
||||
{
|
||||
inputs_trial_op_dim[i] = get<i>(this->inputs).size_on_qp / get<i>(this->inputs).vdim;
|
||||
inputs_trial_op_dim[i] = get<i>(this->inputs).size_on_qp / get<i>
|
||||
(this->inputs).vdim;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -212,9 +216,7 @@ struct DerivativeAssemble
|
||||
});
|
||||
}
|
||||
|
||||
void operator()(
|
||||
std::vector<Vector> &fields_e,
|
||||
SparseMatrix *&A) const
|
||||
void operator()(SparseMatrix *&A) const
|
||||
{
|
||||
if (ctx.attr.Size() == 0) { return; }
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../integrator_ctx.hpp"
|
||||
#include "../../../kernel_dispatch.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
@@ -25,67 +26,20 @@ struct DerivativeAssembleDiagonal
|
||||
static constexpr size_t nfields = count_unique_field_ids(filtered_inout_tuple);
|
||||
|
||||
template <typename fop_t>
|
||||
MFEM_HOST_DEVICE static inline real_t EvalFactor2D(
|
||||
MFEM_HOST_DEVICE static inline real_t EvalFactor1D(
|
||||
const DofToQuadMap &dtq,
|
||||
const int dof,
|
||||
const int td1d,
|
||||
const int k,
|
||||
const int qx,
|
||||
const int qy)
|
||||
const int axis,
|
||||
const int q,
|
||||
const int d)
|
||||
{
|
||||
const auto B = dtq.B;
|
||||
const auto G = dtq.G;
|
||||
|
||||
// This is the reverse mapping from the 1D index dof
|
||||
// to the 2D (ix, iy) indices on the dofs.
|
||||
const int ix = dof % td1d;
|
||||
const int iy = dof / td1d;
|
||||
|
||||
if constexpr (is_value_fop<fop_t>::value)
|
||||
{
|
||||
return (k == 0) ? B(qx, 0, ix) * B(qy, 0, iy) : 0.0;
|
||||
return (k == 0) ? dtq.B(q, 0, d) : 0.0;
|
||||
}
|
||||
else if constexpr (is_gradient_fop<fop_t>::value)
|
||||
{
|
||||
if (k == 0) { return G(qx, 0, ix) * B(qy, 0, iy); }
|
||||
if (k == 1) { return B(qx, 0, ix) * G(qy, 0, iy); }
|
||||
return 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename fop_t>
|
||||
MFEM_HOST_DEVICE static inline real_t EvalFactor3D(
|
||||
const DofToQuadMap &dtq,
|
||||
const int dof,
|
||||
const int td1d,
|
||||
const int k,
|
||||
const int qx,
|
||||
const int qy,
|
||||
const int qz)
|
||||
{
|
||||
const auto B = dtq.B;
|
||||
const auto G = dtq.G;
|
||||
|
||||
// This is the reverse mapping from the 1D index dof
|
||||
// to the 3D (ix, iy, iz) indices on the dofs.
|
||||
const int ix = dof % td1d;
|
||||
const int iy = (dof / td1d) % td1d;
|
||||
const int iz = dof / (td1d * td1d);
|
||||
|
||||
if constexpr (is_value_fop<fop_t>::value)
|
||||
{
|
||||
return (k == 0) ? B(qx, 0, ix) * B(qy, 0, iy) * B(qz, 0, iz) : 0.0;
|
||||
}
|
||||
else if constexpr (is_gradient_fop<fop_t>::value)
|
||||
{
|
||||
if (k == 0) { return G(qx, 0, ix) * B(qy, 0, iy) * B(qz, 0, iz); }
|
||||
if (k == 1) { return B(qx, 0, ix) * G(qy, 0, iy) * B(qz, 0, iz); }
|
||||
if (k == 2) { return B(qx, 0, ix) * B(qy, 0, iy) * G(qz, 0, iz); }
|
||||
return 0.0;
|
||||
return (k == axis) ? dtq.G(q, 0, d) : dtq.B(q, 0, d);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -228,36 +182,11 @@ struct DerivativeAssembleDiagonal
|
||||
|
||||
if (!is_square) { return; }
|
||||
|
||||
if (use_sum_factorization)
|
||||
{
|
||||
const auto &dm =
|
||||
dynamic_cast<const TensorBasisElement &>(*(*test_fes)->GetFE(0)).GetDofMap();
|
||||
dofmap_h = dm;
|
||||
}
|
||||
|
||||
elem_vdofs.SetSize(num_test_dof * test_vdim * num_entities);
|
||||
auto elem_vdofs_h = Reshape(elem_vdofs.HostWrite(),
|
||||
num_test_dof * test_vdim, num_entities);
|
||||
for (int e = 0; e < num_entities; e++)
|
||||
{
|
||||
Array<int> vdofs;
|
||||
(*test_fes)->GetElementVDofs(e, vdofs);
|
||||
|
||||
for (int vd = 0; vd < test_vdim; vd++)
|
||||
{
|
||||
for (int i = 0; i < num_test_dof; i++)
|
||||
{
|
||||
const int native_i = (dofmap_h.Size() > 0) ? dofmap_h[i] : i;
|
||||
elem_vdofs_h(i + vd * num_test_dof, e) =
|
||||
vdofs[native_i + vd * num_test_dof];
|
||||
}
|
||||
}
|
||||
}
|
||||
Ye_mem.SetSize(num_test_dof * test_vdim * num_entities);
|
||||
Ye_mem.UseDevice(true);
|
||||
}
|
||||
|
||||
void operator()(
|
||||
std::vector<Vector> &/*fields_e*/,
|
||||
Vector &diag_l) const
|
||||
void operator()(Vector &diag_e) const
|
||||
{
|
||||
if (!is_square) { return; }
|
||||
if (ctx.attr.Size() == 0) { return; }
|
||||
@@ -268,6 +197,10 @@ struct DerivativeAssembleDiagonal
|
||||
"for tensor-product 2D/3D elements only");
|
||||
return;
|
||||
}
|
||||
MFEM_VERIFY(num_test_dof_1d == num_trial_dof_1d,
|
||||
"DerivativeAssembleDiagonal requires matching tensor dofs");
|
||||
MFEM_VERIFY(num_test_dof_1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
|
||||
const bool has_attr = ctx.attr.Size() > 0;
|
||||
const auto d_attr = ctx.attr.Read();
|
||||
@@ -277,8 +210,7 @@ struct DerivativeAssembleDiagonal
|
||||
qp_cache.Read(), residual_size_on_qp, num_qp, num_entities);
|
||||
|
||||
const int num_dofs_per_elem = num_test_dof * test_vdim;
|
||||
auto diag = diag_l.ReadWrite();
|
||||
auto elem_vdofs_d = Reshape(elem_vdofs.Read(), num_dofs_per_elem, num_entities);
|
||||
auto Ye = Reshape(Ye_mem.ReadWrite(), num_dofs_per_elem, num_entities);
|
||||
|
||||
const auto output_dtq_map_local = output_dtq_maps[0];
|
||||
const auto input_dtq_maps_local = input_dtq_maps;
|
||||
@@ -301,6 +233,8 @@ struct DerivativeAssembleDiagonal
|
||||
|
||||
mfem::forall(num_entities, [=] MFEM_HOST_DEVICE (int e) mutable
|
||||
{
|
||||
constexpr int MD1 = DofQuadLimits::MAX_D1D;
|
||||
constexpr int MQ1 = DofQuadLimits::MAX_Q1D;
|
||||
if (has_attr && !d_attr[d_elem_attr[e] - 1]) { return; }
|
||||
|
||||
auto qpdc = Reshape(&cache_tensor(0, 0, e),
|
||||
@@ -308,83 +242,178 @@ struct DerivativeAssembleDiagonal
|
||||
trial_vdim_local, total_trial_op_dim_local,
|
||||
num_qp_local);
|
||||
|
||||
for (int vd = 0; vd < test_vdim_local; vd++)
|
||||
if (dimension_local == 2)
|
||||
{
|
||||
for (int dof = 0; dof < num_test_dof_local; dof++)
|
||||
real_t QD[MQ1][MD1];
|
||||
for (int vd = 0; vd < test_vdim_local; vd++)
|
||||
{
|
||||
real_t val = 0.0;
|
||||
for (int q = 0; q < num_qp_local; q++)
|
||||
auto Y = Reshape(&Ye(vd * num_test_dof_local, e),
|
||||
num_test_dof_1d_local, num_test_dof_1d_local);
|
||||
for (int dy = 0; dy < num_test_dof_1d_local; dy++)
|
||||
{
|
||||
// This is the reverse mapping from the 1D index q
|
||||
// to the 3D (qx, qy, qz) indices on the quadrature points.
|
||||
const int qx = q % q1d_local;
|
||||
const int qy = (dimension_local == 2)
|
||||
? q / q1d_local
|
||||
: (q / q1d_local) % q1d_local;
|
||||
const int qz = q / (q1d_local * q1d_local);
|
||||
|
||||
for (int k = 0; k < test_op_dim_local; k++)
|
||||
for (int dx = 0; dx < num_test_dof_1d_local; dx++)
|
||||
{
|
||||
real_t psi = 0.0;
|
||||
if (dimension_local == 2)
|
||||
{
|
||||
psi = EvalFactor2D<test_fop_t>(output_dtq_map_local,
|
||||
dof, num_test_dof_1d_local,
|
||||
k, qx, qy);
|
||||
}
|
||||
else
|
||||
{
|
||||
psi = EvalFactor3D<test_fop_t>(output_dtq_map_local,
|
||||
dof, num_test_dof_1d_local,
|
||||
k, qx, qy, qz);
|
||||
}
|
||||
|
||||
if (psi == 0.0) { continue; }
|
||||
|
||||
real_t trial_contraction = 0.0;
|
||||
int m_offset = 0;
|
||||
[[maybe_unused]] const auto &inputs_ref = inputs_local;
|
||||
for_constexpr<ninputs>([&](auto s)
|
||||
{
|
||||
using fop_t = std::decay_t<decltype(get<s>(inputs_ref))>;
|
||||
|
||||
const int trial_op_dim = itod[static_cast<int>(s)];
|
||||
if (trial_op_dim == 0) { return; }
|
||||
|
||||
const auto &dtq = input_dtq_maps_local[s];
|
||||
for (int m = 0; m < trial_op_dim; m++)
|
||||
{
|
||||
real_t phi = 0.0;
|
||||
if (dimension_local == 2)
|
||||
{
|
||||
phi = EvalFactor2D<fop_t>(dtq, dof,
|
||||
num_trial_dof_1d_local,
|
||||
m, qx, qy);
|
||||
}
|
||||
else
|
||||
{
|
||||
phi = EvalFactor3D<fop_t>(dtq, dof,
|
||||
num_trial_dof_1d_local,
|
||||
m, qx, qy, qz);
|
||||
}
|
||||
trial_contraction += qpdc(vd, k, vd, m_offset + m, q) * phi;
|
||||
}
|
||||
|
||||
m_offset += trial_op_dim;
|
||||
});
|
||||
|
||||
val += psi * trial_contraction;
|
||||
Y(dx,dy) = 0.0;
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < test_op_dim_local; k++)
|
||||
{
|
||||
int m_offset = 0;
|
||||
[[maybe_unused]] const auto &inputs_ref = inputs_local;
|
||||
for_constexpr<ninputs>([&](auto s)
|
||||
{
|
||||
using fop_t = std::decay_t<decltype(get<s>(inputs_ref))>;
|
||||
const int trial_op_dim = itod[static_cast<int>(s)];
|
||||
if (trial_op_dim == 0) { return; }
|
||||
|
||||
const int local = dof + vd * num_test_dof_local;
|
||||
const int gdof = elem_vdofs_d(local, e);
|
||||
const int abs_gdof = (gdof >= 0) ? gdof : (-1 - gdof);
|
||||
const real_t sign = (gdof >= 0) ? 1.0 : -1.0;
|
||||
AtomicAdd(diag[abs_gdof], sign * val);
|
||||
for (int m = 0; m < trial_op_dim; m++)
|
||||
{
|
||||
for (int qx = 0; qx < q1d_local; qx++)
|
||||
{
|
||||
for (int dy = 0; dy < num_test_dof_1d_local; dy++)
|
||||
{
|
||||
QD[qx][dy] = 0.0;
|
||||
for (int qy = 0; qy < q1d_local; qy++)
|
||||
{
|
||||
const int q = qx + qy * q1d_local;
|
||||
const real_t Ly =
|
||||
EvalFactor1D<test_fop_t>(output_dtq_map_local,
|
||||
k, 1, qy, dy);
|
||||
const real_t Ry =
|
||||
EvalFactor1D<fop_t>(input_dtq_maps_local[s],
|
||||
m, 1, qy, dy);
|
||||
QD[qx][dy] += Ly * Ry *
|
||||
qpdc(vd, k, vd, m_offset + m, q);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < num_test_dof_1d_local; dy++)
|
||||
{
|
||||
for (int dx = 0; dx < num_test_dof_1d_local; dx++)
|
||||
{
|
||||
real_t accum = 0.0;
|
||||
for (int qx = 0; qx < q1d_local; qx++)
|
||||
{
|
||||
const real_t Lx =
|
||||
EvalFactor1D<test_fop_t>(output_dtq_map_local,
|
||||
k, 0, qx, dx);
|
||||
const real_t Rx =
|
||||
EvalFactor1D<fop_t>(input_dtq_maps_local[s],
|
||||
m, 0, qx, dx);
|
||||
accum += Lx * Rx * QD[qx][dy];
|
||||
}
|
||||
Y(dx,dy) += accum;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_offset += trial_op_dim;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
real_t QQD[MQ1][MQ1][MD1];
|
||||
real_t QDD[MQ1][MD1][MD1];
|
||||
for (int vd = 0; vd < test_vdim_local; vd++)
|
||||
{
|
||||
auto Y = Reshape(&Ye(vd * num_test_dof_local, e),
|
||||
num_test_dof_1d_local, num_test_dof_1d_local,
|
||||
num_test_dof_1d_local);
|
||||
for (int dz = 0; dz < num_test_dof_1d_local; dz++)
|
||||
{
|
||||
for (int dy = 0; dy < num_test_dof_1d_local; dy++)
|
||||
{
|
||||
for (int dx = 0; dx < num_test_dof_1d_local; dx++)
|
||||
{
|
||||
Y(dx,dy,dz) = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < test_op_dim_local; k++)
|
||||
{
|
||||
int m_offset = 0;
|
||||
[[maybe_unused]] const auto &inputs_ref = inputs_local;
|
||||
for_constexpr<ninputs>([&](auto s)
|
||||
{
|
||||
using fop_t = std::decay_t<decltype(get<s>(inputs_ref))>;
|
||||
const int trial_op_dim = itod[static_cast<int>(s)];
|
||||
if (trial_op_dim == 0) { return; }
|
||||
|
||||
for (int m = 0; m < trial_op_dim; m++)
|
||||
{
|
||||
for (int qx = 0; qx < q1d_local; qx++)
|
||||
{
|
||||
for (int qy = 0; qy < q1d_local; qy++)
|
||||
{
|
||||
for (int dz = 0; dz < num_test_dof_1d_local; dz++)
|
||||
{
|
||||
QQD[qx][qy][dz] = 0.0;
|
||||
for (int qz = 0; qz < q1d_local; qz++)
|
||||
{
|
||||
const int q = qx + (qy + qz * q1d_local) * q1d_local;
|
||||
const real_t Lz =
|
||||
EvalFactor1D<test_fop_t>(output_dtq_map_local,
|
||||
k, 2, qz, dz);
|
||||
const real_t Rz =
|
||||
EvalFactor1D<fop_t>(input_dtq_maps_local[s],
|
||||
m, 2, qz, dz);
|
||||
QQD[qx][qy][dz] += Lz * Rz *
|
||||
qpdc(vd, k, vd, m_offset + m, q);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qx = 0; qx < q1d_local; qx++)
|
||||
{
|
||||
for (int dz = 0; dz < num_test_dof_1d_local; dz++)
|
||||
{
|
||||
for (int dy = 0; dy < num_test_dof_1d_local; dy++)
|
||||
{
|
||||
QDD[qx][dy][dz] = 0.0;
|
||||
for (int qy = 0; qy < q1d_local; qy++)
|
||||
{
|
||||
const real_t Ly =
|
||||
EvalFactor1D<test_fop_t>(output_dtq_map_local,
|
||||
k, 1, qy, dy);
|
||||
const real_t Ry =
|
||||
EvalFactor1D<fop_t>(input_dtq_maps_local[s],
|
||||
m, 1, qy, dy);
|
||||
QDD[qx][dy][dz] += Ly * Ry * QQD[qx][qy][dz];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < num_test_dof_1d_local; dz++)
|
||||
{
|
||||
for (int dy = 0; dy < num_test_dof_1d_local; dy++)
|
||||
{
|
||||
for (int dx = 0; dx < num_test_dof_1d_local; dx++)
|
||||
{
|
||||
real_t accum = 0.0;
|
||||
for (int qx = 0; qx < q1d_local; qx++)
|
||||
{
|
||||
const real_t Lx =
|
||||
EvalFactor1D<test_fop_t>(output_dtq_map_local,
|
||||
k, 0, qx, dx);
|
||||
const real_t Rx =
|
||||
EvalFactor1D<fop_t>(input_dtq_maps_local[s],
|
||||
m, 0, qx, dx);
|
||||
accum += Lx * Rx * QDD[qx][dy][dz];
|
||||
}
|
||||
Y(dx,dy,dz) += accum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_offset += trial_op_dim;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
diag_e += Ye_mem;
|
||||
}
|
||||
|
||||
IntegratorContext ctx;
|
||||
@@ -428,8 +457,7 @@ struct DerivativeAssembleDiagonal
|
||||
std::array<bool, ninputs> input_is_dependent;
|
||||
std::array<int, ninputs> inputs_trial_op_dim {};
|
||||
|
||||
Array<int> dofmap_h;
|
||||
Array<int> elem_vdofs;
|
||||
mutable Vector Ye_mem;
|
||||
|
||||
int residual_size_on_qp = 0;
|
||||
};
|
||||
|
||||
@@ -396,9 +396,7 @@ struct DerivativeSetup
|
||||
std::make_integer_sequence<int, nargs> {});
|
||||
}
|
||||
|
||||
void operator()(
|
||||
const std::vector<Vector *> &xe,
|
||||
const Vector &direction_l) const
|
||||
void operator()(const std::vector<Vector *> &xe) const
|
||||
{
|
||||
if (ctx.attr.Size() == 0) { return; }
|
||||
|
||||
@@ -407,8 +405,6 @@ struct DerivativeSetup
|
||||
static_assert(tuple_size<qf_param_ts>::value == ninputs + noutputs,
|
||||
"qfunc parameter count must match inputs+outputs");
|
||||
|
||||
// Don't need direction_l for full Jacobian computation (unused)
|
||||
|
||||
std::array<DeviceTensor<2>, nfields> wrapped_fields_e;
|
||||
for (size_t uf = 0; uf < nfields; uf++)
|
||||
{
|
||||
|
||||
@@ -122,17 +122,13 @@ std::shared_ptr<DerivativeOperator> DifferentiableOperator::GetDerivative(
|
||||
// Prolong to L-space
|
||||
prolongation(infds, bx, infields_l);
|
||||
|
||||
// Get the direction field (the field corresponding to derivative_id)
|
||||
Vector direction_l(GetVSize(infds[dfidx]));
|
||||
prolongation(infds[dfidx], bx.GetBlock(dfidx), direction_l);
|
||||
|
||||
// Restrict to element space
|
||||
restriction<Entity::Element>(infds, infields_l, infields_e);
|
||||
|
||||
// Run all setup callbacks to populate the cache
|
||||
for (const auto &setup_callback : derivative_setup_callbacks[derivative_id])
|
||||
{
|
||||
setup_callback(infields_e, direction_l);
|
||||
setup_callback(infields_e);
|
||||
}
|
||||
|
||||
return std::make_shared<DerivativeOperator>(
|
||||
@@ -223,7 +219,7 @@ std::shared_ptr<DerivativeOperator> DifferentiableOperator::GetDerivative(
|
||||
// Run all setup callbacks to populate the cache
|
||||
for (const auto &setup_callback : derivative_setup_callbacks[derivative_id])
|
||||
{
|
||||
setup_callback(infields_e, direction_l);
|
||||
setup_callback(infields_e);
|
||||
}
|
||||
|
||||
return std::make_shared<DerivativeOperator>(
|
||||
|
||||
+14
-12
@@ -30,7 +30,7 @@ using action_t =
|
||||
|
||||
/// @brief Type alias for a function that computes the cache for the action of a derivative
|
||||
using derivative_setup_t =
|
||||
std::function<void(const std::vector<Vector *> &, const Vector &)>;
|
||||
std::function<void(const std::vector<Vector *> &)>;
|
||||
|
||||
/// @brief Type alias for a function that computes the action of a derivative
|
||||
using derivative_action_t =
|
||||
@@ -39,17 +39,16 @@ using derivative_action_t =
|
||||
/// @brief Type alias for a function that assembles the SparseMatrix of a
|
||||
/// derivative operator
|
||||
using assemble_derivative_sparsematrix_callback_t =
|
||||
std::function<void(std::vector<Vector> &, SparseMatrix *&)>;
|
||||
std::function<void(SparseMatrix *&)>;
|
||||
|
||||
/// @brief Type alias for a function that assembles the HypreParMatrix of a
|
||||
/// derivative operator
|
||||
using assemble_derivative_hypreparmatrix_callback_t =
|
||||
std::function<void(std::vector<Vector> &, HypreParMatrix *&)>;
|
||||
std::function<void(HypreParMatrix *&)>;
|
||||
|
||||
/// @brief Type alias for a function that assembles the diagonal of a derivative
|
||||
/// operator into an L-vector
|
||||
using assemble_diagonal_callback_t =
|
||||
std::function<void(std::vector<Vector> &, Vector &)>;
|
||||
/// operator into an E-vector
|
||||
using assemble_diagonal_callback_t = std::function<void(Vector &)>;
|
||||
|
||||
/// @brief Type alias for a function that applies the appropriate restriction to
|
||||
/// the solution and parameters
|
||||
@@ -251,7 +250,7 @@ public:
|
||||
|
||||
for (const auto &f : assemble_derivative_sparsematrix_callbacks)
|
||||
{
|
||||
f(fields_e, A);
|
||||
f(A);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +265,7 @@ public:
|
||||
|
||||
for (const auto &f : assemble_derivative_hypreparmatrix_callbacks)
|
||||
{
|
||||
f(fields_e, A);
|
||||
f(A);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,21 +276,24 @@ public:
|
||||
{
|
||||
MFEM_ASSERT(!assemble_diagonal_callbacks.empty(),
|
||||
"derivative can't assemble diagonal");
|
||||
MFEM_ASSERT(outfds.size() == 1,
|
||||
"AssembleDiagonal currently requires a single output field");
|
||||
|
||||
const auto *test_pf =
|
||||
std::get_if<const ParFiniteElementSpace *>(&outfds[0].data);
|
||||
MFEM_ASSERT(test_pf && *test_pf,
|
||||
"AssembleDiagonal: test field must be a ParFiniteElementSpace");
|
||||
|
||||
Vector diag_l((*test_pf)->GetVSize());
|
||||
diag_l = 0.0;
|
||||
prepare_residual<Entity::Element>(outfds, daction_e);
|
||||
for (auto *v : daction_e) { *v = 0.0; }
|
||||
|
||||
for (const auto &f : assemble_diagonal_callbacks)
|
||||
{
|
||||
f(fields_e, diag_l);
|
||||
f(*daction_e[0]);
|
||||
}
|
||||
|
||||
(*test_pf)->GetProlongationMatrix()->MultTranspose(diag_l, diag);
|
||||
restriction_transpose<Entity::Element>(outfds, daction_e, daction_l);
|
||||
prolongation_transpose(outfds[0], *daction_l[0], diag);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user