Skip to content

Commit

Permalink
Merge pull request #1196 from sebastiangrimberg/sjg/unsigned-restr-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastiangrimberg committed Apr 27, 2023
2 parents 30d6126 + b04eb3d commit 4b7c8c0
Show file tree
Hide file tree
Showing 14 changed files with 346 additions and 38 deletions.
1 change: 1 addition & 0 deletions backends/cuda-ref/ceed-cuda-restriction.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ int CeedElemRestrictionCreate_Cuda(CeedMemType mem_type, CeedCopyMode copy_mode,

// Register backend functions
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "Apply", CeedElemRestrictionApply_Cuda));
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "ApplyUnsigned", CeedElemRestrictionApply_Cuda));
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "GetOffsets", CeedElemRestrictionGetOffsets_Cuda));
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "Destroy", CeedElemRestrictionDestroy_Cuda));
return CEED_ERROR_SUCCESS;
Expand Down
1 change: 1 addition & 0 deletions backends/hip-ref/ceed-hip-ref-restriction.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ int CeedElemRestrictionCreate_Hip(CeedMemType mem_type, CeedCopyMode copy_mode,

// Register backend functions
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "Apply", CeedElemRestrictionApply_Hip));
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "ApplyUnsigned", CeedElemRestrictionApply_Hip));
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "GetOffsets", CeedElemRestrictionGetOffsets_Hip));
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "Destroy", CeedElemRestrictionDestroy_Hip));
return CEED_ERROR_SUCCESS;
Expand Down
1 change: 1 addition & 0 deletions backends/magma/ceed-magma-restriction.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ int CeedElemRestrictionCreate_Magma(CeedMemType mtype, CeedCopyMode cmode, const
CeedInt layout[3] = {1, elemsize * nelem, elemsize};
CeedCallBackend(CeedElemRestrictionSetELayout(r, layout));
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "Apply", CeedElemRestrictionApply_Magma));
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "ApplyUnsigned", CeedElemRestrictionApply_Magma));
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "GetOffsets", CeedElemRestrictionGetOffsets_Magma));
CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "Destroy", CeedElemRestrictionDestroy_Magma));
CeedCallBackend(CeedFree(&restriction_kernel_path));
Expand Down
1 change: 1 addition & 0 deletions backends/occa/ceed-occa-elem-restriction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ int ElemRestriction::ceedCreate(CeedMemType memType, CeedCopyMode copyMode, cons
CeedChkBackend(CeedElemRestrictionSetELayout(r, defaultLayout));

CeedOccaRegisterFunction(r, "Apply", ElemRestriction::ceedApply);
CeedOccaRegisterFunction(r, "ApplyUnsigned", ElemRestriction::ceedApply);
CeedOccaRegisterFunction(r, "ApplyBlock", ElemRestriction::ceedApplyBlock);
CeedOccaRegisterFunction(r, "GetOffsets", ElemRestriction::ceedGetOffsets);
CeedOccaRegisterFunction(r, "Destroy", ElemRestriction::ceedDestroy);
Expand Down
112 changes: 77 additions & 35 deletions backends/ref/ceed-ref-restriction.c

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion backends/ref/ceed-ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ typedef struct {
// Orientation, if it exists, is true when the face must be flipped (multiplies by -1.).
const bool *orient;
bool *orient_allocated;
int (*Apply)(CeedElemRestriction, CeedInt, CeedInt, CeedInt, CeedInt, CeedInt, CeedTransposeMode, CeedVector, CeedVector, CeedRequest *);
int (*Apply)(CeedElemRestriction, CeedInt, CeedInt, CeedInt, CeedInt, CeedInt, bool, CeedTransposeMode, CeedVector, CeedVector, CeedRequest *);
} CeedElemRestriction_Ref;

typedef struct {
Expand Down
1 change: 1 addition & 0 deletions include/ceed-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ struct CeedVector_private {
struct CeedElemRestriction_private {
Ceed ceed;
int (*Apply)(CeedElemRestriction, CeedTransposeMode, CeedVector, CeedVector, CeedRequest *);
int (*ApplyUnsigned)(CeedElemRestriction, CeedTransposeMode, CeedVector, CeedVector, CeedRequest *);
int (*ApplyBlock)(CeedElemRestriction, CeedInt, CeedTransposeMode, CeedVector, CeedVector, CeedRequest *);
int (*GetOffsets)(CeedElemRestriction, CeedMemType, const CeedInt **);
int (*Destroy)(CeedElemRestriction);
Expand Down
2 changes: 2 additions & 0 deletions include/ceed/ceed.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ CEED_EXTERN int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_e
CEED_EXTERN int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy);
CEED_EXTERN int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *lvec, CeedVector *evec);
CEED_EXTERN int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request);
CEED_EXTERN int CeedElemRestrictionApplyUnsigned(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru,
CeedRequest *request);
CEED_EXTERN int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru,
CeedRequest *request);
CEED_EXTERN int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed);
Expand Down
36 changes: 36 additions & 0 deletions interface/ceed-elemrestriction.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_s
CeedElemRestriction *rstr) {
if (!ceed->ElemRestrictionCreate) {
Ceed delegate;

CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionCreateStrided");
CeedCall(CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, l_size, strides, rstr));
Expand Down Expand Up @@ -631,6 +632,41 @@ int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode,
return CEED_ERROR_SUCCESS;
}

/**
@brief Restrict an L-vector to an E-vector or apply its transpose ignoring any
provided orientations
@param[in] rstr CeedElemRestriction
@param[in] t_mode Apply restriction or transpose
@param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
@param[out] ru Output vector (of shape [@a num_elem * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE).
Ordering of the e-vector is decided by the backend.
@param[in] request Request or @ref CEED_REQUEST_IMMEDIATE
@return An error code: 0 - success, otherwise - failure
@ref User
**/
int CeedElemRestrictionApplyUnsigned(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) {
CeedInt m, n;

CeedCheck(rstr->ApplyUnsigned, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionApplyUnsigned");

if (t_mode == CEED_NOTRANSPOSE) {
m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
n = rstr->l_size;
} else {
m = rstr->l_size;
n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
}
CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION,
"Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n);
CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION,
"Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n);
if (rstr->num_elem > 0) CeedCall(rstr->ApplyUnsigned(rstr, t_mode, u, ru, request));
return CEED_ERROR_SUCCESS;
}

/**
@brief Restrict an L-vector to a block of an E-vector or apply its transpose
Expand Down
5 changes: 4 additions & 1 deletion interface/ceed-preconditioning.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ static inline int CeedSingleOperatorAssembleAddDiagonal_Core(CeedOperator op, Ce
CeedCall(CeedVectorRestoreArray(elem_diag, &elem_diag_array));

// Assemble local operator diagonal
CeedCall(CeedElemRestrictionApply(diag_elem_rstr, CEED_TRANSPOSE, elem_diag, assembled, request));
CeedCall(CeedElemRestrictionApplyUnsigned(diag_elem_rstr, CEED_TRANSPOSE, elem_diag, assembled, request));

// Cleanup
if (is_pointblock) CeedCall(CeedElemRestrictionDestroy(&diag_elem_rstr));
Expand Down Expand Up @@ -442,6 +442,9 @@ static inline int CeedCompositeOperatorLinearAssembleAddDiagonal(CeedOperator op
Users should generally use CeedOperatorLinearAssembleSymbolic()
Note: For operators using oriented element restrictions, entries in rows or cols may be negative indicating the assembled value at this nonzero
should be negated
@param[in] op CeedOperator to assemble nonzero pattern
@param[in] offset Offset for number of entries
@param[out] rows Row number for each entry
Expand Down
1 change: 1 addition & 0 deletions interface/ceed.c
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,7 @@ int CeedInit(const char *resource, Ceed *ceed) {
CEED_FTABLE_ENTRY(CeedVector, Reciprocal),
CEED_FTABLE_ENTRY(CeedVector, Destroy),
CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnsigned),
CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets),
CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
Expand Down
3 changes: 2 additions & 1 deletion tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ The tests are organized by API object, and some tests are further organized, as
5.3. CeedOperator diagonal and CeedQFunction assembly tests
5.4. CeedOperator element inverse tests
5.5. CeedOperator multigrid level tests
5.6. CeedOperator full assembly tests
5.6. CeedOperator full assembly tests
5.7. CeedOperator extra diagonal and full assembly tests
147 changes: 147 additions & 0 deletions tests/t570-operator.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/// @file
/// Test assembly of H(div) mass matrix operator diagonal
/// \test Test assembly of H(div) mass matrix operator diagonal
#include "t570-operator.h"

#include <ceed.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#include "t330-basis.h"

int main(int argc, char **argv) {
Ceed ceed;
CeedElemRestriction elem_restriction_x, elem_restriction_u;
CeedBasis basis_x, basis_u;
CeedQFunction qf_mass;
CeedOperator op_mass;
CeedVector x, assembled, u, v;
CeedInt dim = 2, p = 8, q = 3, px = 2;
CeedInt n_x = 1, n_y = 1; // Currently only implemented for single element
CeedInt row, column, offset;
CeedInt num_elem = n_x * n_y, num_faces = (n_x + 1) * n_y + (n_y + 1) * n_x;
CeedInt num_dofs_x = (n_x + 1) * (n_y + 1), num_dofs_u = num_faces * 2, num_qpts = q * q;
CeedInt ind_x[num_elem * px * px], ind_u[num_elem * p];
bool orient_u[num_elem * p];
CeedScalar assembled_true[num_dofs_u];
CeedScalar q_ref[dim * num_qpts], q_weight[num_qpts];
CeedScalar interp[dim * p * num_qpts], div[p * num_qpts];

CeedInit(argv[1], &ceed);

// Vectors
CeedVectorCreate(ceed, dim * num_dofs_x, &x);
{
CeedScalar x_array[dim * num_dofs_x];

for (CeedInt i = 0; i < n_x + 1; i++) {
for (CeedInt j = 0; j < n_y + 1; j++) {
x_array[i + j * (n_x + 1) + 0 * num_dofs_x] = i / (CeedScalar)n_x;
x_array[i + j * (n_x + 1) + 1 * num_dofs_x] = j / (CeedScalar)n_y;
}
}
CeedVectorSetArray(x, CEED_MEM_HOST, CEED_COPY_VALUES, x_array);
}
CeedVectorCreate(ceed, num_dofs_u, &u);
CeedVectorCreate(ceed, num_dofs_u, &v);

// Restrictions
for (CeedInt i = 0; i < num_elem; i++) {
column = i % n_x;
row = i / n_x;
offset = column * (px - 1) + row * (n_x + 1) * (px - 1);

for (CeedInt j = 0; j < px; j++) {
for (CeedInt k = 0; k < px; k++) {
ind_x[px * (px * i + k) + j] = offset + k * (n_x + 1) + j;
}
}
}
bool orient_u_local[8] = {false, false, false, false, true, true, true, true};
CeedInt ind_u_local[8] = {0, 1, 6, 7, 2, 3, 4, 5};
for (CeedInt j = 0; j < n_y; j++) {
for (CeedInt i = 0; i < n_x; i++) {
for (CeedInt k = 0; k < p; k++) {
ind_u[k] = ind_u_local[k];
orient_u[k] = orient_u_local[k];
}
}
}
CeedElemRestrictionCreate(ceed, num_elem, px * px, dim, num_dofs_x, dim * num_dofs_x, CEED_MEM_HOST, CEED_USE_POINTER, ind_x, &elem_restriction_x);
CeedElemRestrictionCreateOriented(ceed, num_elem, p, 1, 1, num_dofs_u, CEED_MEM_HOST, CEED_COPY_VALUES, ind_u, orient_u, &elem_restriction_u);

// Bases
CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, px, q, CEED_GAUSS, &basis_x);

BuildHdivQuadrilateral(q, q_ref, q_weight, interp, div, CEED_GAUSS);
CeedBasisCreateHdiv(ceed, CEED_TOPOLOGY_QUAD, 1, p, num_qpts, interp, div, q_ref, q_weight, &basis_u);

// QFunctions
CeedQFunctionCreateInterior(ceed, 1, mass, mass_loc, &qf_mass);
CeedQFunctionAddInput(qf_mass, "weight", 1, CEED_EVAL_WEIGHT);
CeedQFunctionAddInput(qf_mass, "dx", dim * dim, CEED_EVAL_GRAD);
CeedQFunctionAddInput(qf_mass, "u", dim, CEED_EVAL_INTERP);
CeedQFunctionAddOutput(qf_mass, "v", dim, CEED_EVAL_INTERP);

// Operators
CeedOperatorCreate(ceed, qf_mass, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, &op_mass);
CeedOperatorSetField(op_mass, "weight", CEED_ELEMRESTRICTION_NONE, basis_x, CEED_VECTOR_NONE);
CeedOperatorSetField(op_mass, "dx", elem_restriction_x, basis_x, x);
CeedOperatorSetField(op_mass, "u", elem_restriction_u, basis_u, CEED_VECTOR_ACTIVE);
CeedOperatorSetField(op_mass, "v", elem_restriction_u, basis_u, CEED_VECTOR_ACTIVE);

// Assemble diagonal
CeedVectorCreate(ceed, num_dofs_u, &assembled);
CeedOperatorLinearAssembleDiagonal(op_mass, assembled, CEED_REQUEST_IMMEDIATE);

// Manually assemble diagonal
CeedVectorSetValue(u, 0.0);
for (int i = 0; i < num_dofs_u; i++) {
CeedScalar *u_array;
const CeedScalar *v_array;

// Set input
CeedVectorGetArray(u, CEED_MEM_HOST, &u_array);
u_array[i] = 1.0;
if (i) u_array[i - 1] = 0.0;
CeedVectorRestoreArray(u, &u_array);

// Compute diag entry for DoF i
CeedOperatorApply(op_mass, u, v, CEED_REQUEST_IMMEDIATE);

// Retrieve entry
CeedVectorGetArrayRead(v, CEED_MEM_HOST, &v_array);
assembled_true[i] = v_array[i];
CeedVectorRestoreArrayRead(v, &v_array);
}

// Check output
{
const CeedScalar *assembled_array;

CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembled_array);
for (int i = 0; i < num_dofs_u; i++) {
if (fabs(assembled_array[i] - assembled_true[i]) > 100. * CEED_EPSILON) {
// LCOV_EXCL_START
printf("[%" CeedInt_FMT "] Error in assembly: %f != %f\n", i, assembled_array[i], assembled_true[i]);
// LCOV_EXCL_STOP
}
}
CeedVectorRestoreArrayRead(assembled, &assembled_array);
}

// Cleanup
CeedVectorDestroy(&x);
CeedVectorDestroy(&assembled);
CeedVectorDestroy(&u);
CeedVectorDestroy(&v);
CeedElemRestrictionDestroy(&elem_restriction_u);
CeedElemRestrictionDestroy(&elem_restriction_x);
CeedBasisDestroy(&basis_u);
CeedBasisDestroy(&basis_x);
CeedQFunctionDestroy(&qf_mass);
CeedOperatorDestroy(&op_mass);
CeedDestroy(&ceed);
return 0;
}
71 changes: 71 additions & 0 deletions tests/t570-operator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
// All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
//
// SPDX-License-Identifier: BSD-2-Clause
//
// This file is part of CEED: http://github.com/ceed

#include <ceed.h>

// Compute det(A)
CEED_QFUNCTION_HELPER CeedScalar MatDet2x2(const CeedScalar A[2][2]) { return A[0][0] * A[1][1] - A[1][0] * A[0][1]; }

// Compute alpha * A^T * B = C
CEED_QFUNCTION_HELPER int AlphaMatTransposeMatMult2x2(const CeedScalar alpha, const CeedScalar A[2][2], const CeedScalar B[2][2],
CeedScalar C[2][2]) {
for (CeedInt j = 0; j < 2; j++) {
for (CeedInt k = 0; k < 2; k++) {
C[j][k] = 0;
for (CeedInt m = 0; m < 2; m++) {
C[j][k] += alpha * A[m][j] * B[m][k];
}
}
}

return 0;
}

// Compute matrix-vector product: alpha*A*u
CEED_QFUNCTION_HELPER int AlphaMatVecMult2x2(const CeedScalar alpha, const CeedScalar A[2][2], const CeedScalar u[2], CeedScalar v[2]) {
// Compute v = alpha*A*u
for (CeedInt k = 0; k < 2; k++) {
v[k] = 0;
for (CeedInt m = 0; m < 2; m++) v[k] += A[k][m] * u[m] * alpha;
}

return 0;
};

CEED_QFUNCTION(mass)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
// Inputs
const CeedScalar(*w) = in[0], (*dxdX)[2][CEED_Q_VLA] = (const CeedScalar(*)[2][CEED_Q_VLA])in[1],
(*u)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2];

// Outputs
CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];

// Quadrature Point Loop
CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
// Setup, J = dx/dX
const CeedScalar J[2][2] = {
{dxdX[0][0][i], dxdX[1][0][i]},
{dxdX[0][1][i], dxdX[1][1][i]}
};
const CeedScalar det_J = MatDet2x2(J);

CeedScalar u1[2] = {u[0][i], u[1][i]}, v1[2];
// *INDENT-ON*
// Piola map: J^T*J*u*w/detJ
// 1) Compute J^T * J
CeedScalar JT_J[2][2];
AlphaMatTransposeMatMult2x2(1., J, J, JT_J);

// 2) Compute J^T*J*u * w /detJ
AlphaMatVecMult2x2(w[i] / det_J, JT_J, u1, v1);
for (CeedInt k = 0; k < 2; k++) {
v[k][i] = v1[k];
}
} // End of Quadrature Point Loop

return 0;
}

0 comments on commit 4b7c8c0

Please sign in to comment.