1*15ed3f7dSjeremylt /// @file 2*15ed3f7dSjeremylt /// Test creation and use of FDM element inverse 3*15ed3f7dSjeremylt /// \test Test creation and use of FDM element inverse 4*15ed3f7dSjeremylt #include <ceed.h> 5*15ed3f7dSjeremylt #include <stdlib.h> 6*15ed3f7dSjeremylt #include <string.h> 7*15ed3f7dSjeremylt #include <math.h> 8*15ed3f7dSjeremylt #include "t541-operator.h" 9*15ed3f7dSjeremylt 10*15ed3f7dSjeremylt int main(int argc, char **argv) { 11*15ed3f7dSjeremylt Ceed ceed; 12*15ed3f7dSjeremylt CeedElemRestriction elem_restr_x_i, elem_restr_u_i, elem_restr_qd_i; 13*15ed3f7dSjeremylt CeedBasis basis_x, basis_u; 14*15ed3f7dSjeremylt CeedQFunction qf_setup_diff, qf_apply; 15*15ed3f7dSjeremylt CeedOperator op_setup_diff, op_apply, op_inv; 16*15ed3f7dSjeremylt CeedVector q_data_diff, X, U, V, W; 17*15ed3f7dSjeremylt CeedInt num_elem = 1, P = 4, Q = 5, dim = 2; 18*15ed3f7dSjeremylt CeedInt num_dofs = P*P, num_qpts = num_elem*Q*Q, q_data_size = dim*(dim+1)/2; 19*15ed3f7dSjeremylt CeedScalar x[dim*num_elem*(2*2)]; 20*15ed3f7dSjeremylt 21*15ed3f7dSjeremylt CeedInit(argv[1], &ceed); 22*15ed3f7dSjeremylt 23*15ed3f7dSjeremylt // DoF Coordinates 24*15ed3f7dSjeremylt for (CeedInt i=0; i<2; i++) 25*15ed3f7dSjeremylt for (CeedInt j=0; j<2; j++) { 26*15ed3f7dSjeremylt x[i+j*2+0*4] = i; 27*15ed3f7dSjeremylt x[i+j*2+1*4] = j; 28*15ed3f7dSjeremylt } 29*15ed3f7dSjeremylt CeedVectorCreate(ceed, dim*num_elem*(2*2), &X); 30*15ed3f7dSjeremylt CeedVectorSetArray(X, CEED_MEM_HOST, CEED_USE_POINTER, x); 31*15ed3f7dSjeremylt 32*15ed3f7dSjeremylt // Qdata Vector 33*15ed3f7dSjeremylt CeedVectorCreate(ceed, q_data_size*num_qpts, &q_data_diff); 34*15ed3f7dSjeremylt 35*15ed3f7dSjeremylt // Element Setup 36*15ed3f7dSjeremylt 37*15ed3f7dSjeremylt // Restrictions 38*15ed3f7dSjeremylt CeedInt strides_x[3] = {1, 2*2, 2*2*dim}; 39*15ed3f7dSjeremylt CeedElemRestrictionCreateStrided(ceed, num_elem, 2*2, dim, dim*num_elem*2*2, 40*15ed3f7dSjeremylt strides_x, &elem_restr_x_i); 41*15ed3f7dSjeremylt 42*15ed3f7dSjeremylt CeedInt strides_u[3] = {1, P*P, P*P}; 43*15ed3f7dSjeremylt CeedElemRestrictionCreateStrided(ceed, num_elem, P*P, 1, num_dofs, strides_u, 44*15ed3f7dSjeremylt &elem_restr_u_i); 45*15ed3f7dSjeremylt 46*15ed3f7dSjeremylt CeedInt strides_qd[3] = {1, Q*Q, q_data_size *Q*Q}; 47*15ed3f7dSjeremylt CeedElemRestrictionCreateStrided(ceed, num_elem, Q*Q, q_data_size, 48*15ed3f7dSjeremylt num_qpts*q_data_size, strides_qd, &elem_restr_qd_i); 49*15ed3f7dSjeremylt 50*15ed3f7dSjeremylt // Bases 51*15ed3f7dSjeremylt CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, 2, Q, CEED_GAUSS, &basis_x); 52*15ed3f7dSjeremylt CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, P, Q, CEED_GAUSS, &basis_u); 53*15ed3f7dSjeremylt 54*15ed3f7dSjeremylt // QFunction - setup diff 55*15ed3f7dSjeremylt CeedQFunctionCreateInterior(ceed, 1, setup_diff, setup_diff_loc, 56*15ed3f7dSjeremylt &qf_setup_diff); 57*15ed3f7dSjeremylt CeedQFunctionAddInput(qf_setup_diff, "dx", dim*dim, CEED_EVAL_GRAD); 58*15ed3f7dSjeremylt CeedQFunctionAddInput(qf_setup_diff, "weight", 1, CEED_EVAL_WEIGHT); 59*15ed3f7dSjeremylt CeedQFunctionAddOutput(qf_setup_diff, "qdata", q_data_size, CEED_EVAL_NONE); 60*15ed3f7dSjeremylt 61*15ed3f7dSjeremylt // Operator - setup diff 62*15ed3f7dSjeremylt CeedOperatorCreate(ceed, qf_setup_diff, CEED_QFUNCTION_NONE, 63*15ed3f7dSjeremylt CEED_QFUNCTION_NONE, &op_setup_diff); 64*15ed3f7dSjeremylt CeedOperatorSetField(op_setup_diff, "dx", elem_restr_x_i, basis_x, 65*15ed3f7dSjeremylt CEED_VECTOR_ACTIVE); 66*15ed3f7dSjeremylt CeedOperatorSetField(op_setup_diff, "weight", CEED_ELEMRESTRICTION_NONE, 67*15ed3f7dSjeremylt basis_x, CEED_VECTOR_NONE); 68*15ed3f7dSjeremylt CeedOperatorSetField(op_setup_diff, "qdata", elem_restr_qd_i, 69*15ed3f7dSjeremylt CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 70*15ed3f7dSjeremylt 71*15ed3f7dSjeremylt // Apply Setup Operator 72*15ed3f7dSjeremylt CeedOperatorApply(op_setup_diff, X, q_data_diff, CEED_REQUEST_IMMEDIATE); 73*15ed3f7dSjeremylt 74*15ed3f7dSjeremylt // QFunction - apply 75*15ed3f7dSjeremylt CeedQFunctionCreateInterior(ceed, 1, apply, apply_loc, &qf_apply); 76*15ed3f7dSjeremylt CeedQFunctionAddInput(qf_apply, "u", dim, CEED_EVAL_GRAD); 77*15ed3f7dSjeremylt CeedQFunctionAddInput(qf_apply, "qdata_diff", q_data_size, CEED_EVAL_NONE); 78*15ed3f7dSjeremylt CeedQFunctionAddOutput(qf_apply, "v", dim, CEED_EVAL_GRAD); 79*15ed3f7dSjeremylt 80*15ed3f7dSjeremylt // Operator - apply 81*15ed3f7dSjeremylt CeedOperatorCreate(ceed, qf_apply, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, 82*15ed3f7dSjeremylt &op_apply); 83*15ed3f7dSjeremylt CeedOperatorSetField(op_apply, "u", elem_restr_u_i, basis_u, 84*15ed3f7dSjeremylt CEED_VECTOR_ACTIVE); 85*15ed3f7dSjeremylt CeedOperatorSetField(op_apply, "qdata_diff", elem_restr_qd_i, 86*15ed3f7dSjeremylt CEED_BASIS_COLLOCATED, q_data_diff); 87*15ed3f7dSjeremylt CeedOperatorSetField(op_apply, "v", elem_restr_u_i, basis_u, 88*15ed3f7dSjeremylt CEED_VECTOR_ACTIVE); 89*15ed3f7dSjeremylt 90*15ed3f7dSjeremylt // Create FDM element inverse 91*15ed3f7dSjeremylt CeedOperatorCreateFDMElementInverse(op_apply, &op_inv, CEED_REQUEST_IMMEDIATE); 92*15ed3f7dSjeremylt 93*15ed3f7dSjeremylt // Create vectors 94*15ed3f7dSjeremylt CeedVectorCreate(ceed, num_dofs, &U); 95*15ed3f7dSjeremylt CeedVectorCreate(ceed, num_dofs, &V); 96*15ed3f7dSjeremylt CeedVectorCreate(ceed, num_dofs, &W); 97*15ed3f7dSjeremylt 98*15ed3f7dSjeremylt // Create Schur complement for element corners 99*15ed3f7dSjeremylt CeedScalar S[16]; 100*15ed3f7dSjeremylt for (CeedInt i = 0; i < 4; i++) { 101*15ed3f7dSjeremylt CeedScalar *u; 102*15ed3f7dSjeremylt CeedVectorSetValue(U, 0.0); 103*15ed3f7dSjeremylt CeedVectorGetArray(U, CEED_MEM_HOST, &u); 104*15ed3f7dSjeremylt switch (i) { 105*15ed3f7dSjeremylt case 0: u[0] = 1.0; break; 106*15ed3f7dSjeremylt case 1: u[P-1] = 1.0; break; 107*15ed3f7dSjeremylt case 2: u[P*P-P] = 1.0; break; 108*15ed3f7dSjeremylt case 3: u[P*P-1] = 1.0; break; 109*15ed3f7dSjeremylt } 110*15ed3f7dSjeremylt CeedVectorRestoreArray(U, &u); 111*15ed3f7dSjeremylt 112*15ed3f7dSjeremylt CeedOperatorApply(op_inv, U, V, CEED_REQUEST_IMMEDIATE); 113*15ed3f7dSjeremylt 114*15ed3f7dSjeremylt const CeedScalar *v; 115*15ed3f7dSjeremylt CeedVectorGetArrayRead(V, CEED_MEM_HOST, &v); 116*15ed3f7dSjeremylt S[0*4+i] = v[0]; 117*15ed3f7dSjeremylt S[1*4+i] = v[P-1]; 118*15ed3f7dSjeremylt S[2*4+i] = v[P*P-P]; 119*15ed3f7dSjeremylt S[3*4+i] = v[P*P-1]; 120*15ed3f7dSjeremylt CeedVectorRestoreArrayRead(V, &v); 121*15ed3f7dSjeremylt } 122*15ed3f7dSjeremylt CeedScalar S_inv[16]; 123*15ed3f7dSjeremylt { 124*15ed3f7dSjeremylt CeedScalar det; 125*15ed3f7dSjeremylt S_inv[0] = S[5] * S[10] * S[15] - 126*15ed3f7dSjeremylt S[5] * S[11] * S[14] - 127*15ed3f7dSjeremylt S[9] * S[6] * S[15] + 128*15ed3f7dSjeremylt S[9] * S[7] * S[14] + 129*15ed3f7dSjeremylt S[13] * S[6] * S[11] - 130*15ed3f7dSjeremylt S[13] * S[7] * S[10]; 131*15ed3f7dSjeremylt 132*15ed3f7dSjeremylt S_inv[4] = -S[4] * S[10] * S[15] + 133*15ed3f7dSjeremylt S[4] * S[11] * S[14] + 134*15ed3f7dSjeremylt S[8] * S[6] * S[15] - 135*15ed3f7dSjeremylt S[8] * S[7] * S[14] - 136*15ed3f7dSjeremylt S[12] * S[6] * S[11] + 137*15ed3f7dSjeremylt S[12] * S[7] * S[10]; 138*15ed3f7dSjeremylt 139*15ed3f7dSjeremylt S_inv[8] = S[4] * S[9] * S[15] - 140*15ed3f7dSjeremylt S[4] * S[11] * S[13] - 141*15ed3f7dSjeremylt S[8] * S[5] * S[15] + 142*15ed3f7dSjeremylt S[8] * S[7] * S[13] + 143*15ed3f7dSjeremylt S[12] * S[5] * S[11] - 144*15ed3f7dSjeremylt S[12] * S[7] * S[9]; 145*15ed3f7dSjeremylt 146*15ed3f7dSjeremylt S_inv[12] = -S[4] * S[9] * S[14] + 147*15ed3f7dSjeremylt S[4] * S[10] * S[13] + 148*15ed3f7dSjeremylt S[8] * S[5] * S[14] - 149*15ed3f7dSjeremylt S[8] * S[6] * S[13] - 150*15ed3f7dSjeremylt S[12] * S[5] * S[10] + 151*15ed3f7dSjeremylt S[12] * S[6] * S[9]; 152*15ed3f7dSjeremylt 153*15ed3f7dSjeremylt S_inv[1] = -S[1] * S[10] * S[15] + 154*15ed3f7dSjeremylt S[1] * S[11] * S[14] + 155*15ed3f7dSjeremylt S[9] * S[2] * S[15] - 156*15ed3f7dSjeremylt S[9] * S[3] * S[14] - 157*15ed3f7dSjeremylt S[13] * S[2] * S[11] + 158*15ed3f7dSjeremylt S[13] * S[3] * S[10]; 159*15ed3f7dSjeremylt 160*15ed3f7dSjeremylt S_inv[5] = S[0] * S[10] * S[15] - 161*15ed3f7dSjeremylt S[0] * S[11] * S[14] - 162*15ed3f7dSjeremylt S[8] * S[2] * S[15] + 163*15ed3f7dSjeremylt S[8] * S[3] * S[14] + 164*15ed3f7dSjeremylt S[12] * S[2] * S[11] - 165*15ed3f7dSjeremylt S[12] * S[3] * S[10]; 166*15ed3f7dSjeremylt 167*15ed3f7dSjeremylt S_inv[9] = -S[0] * S[9] * S[15] + 168*15ed3f7dSjeremylt S[0] * S[11] * S[13] + 169*15ed3f7dSjeremylt S[8] * S[1] * S[15] - 170*15ed3f7dSjeremylt S[8] * S[3] * S[13] - 171*15ed3f7dSjeremylt S[12] * S[1] * S[11] + 172*15ed3f7dSjeremylt S[12] * S[3] * S[9]; 173*15ed3f7dSjeremylt 174*15ed3f7dSjeremylt S_inv[13] = S[0] * S[9] * S[14] - 175*15ed3f7dSjeremylt S[0] * S[10] * S[13] - 176*15ed3f7dSjeremylt S[8] * S[1] * S[14] + 177*15ed3f7dSjeremylt S[8] * S[2] * S[13] + 178*15ed3f7dSjeremylt S[12] * S[1] * S[10] - 179*15ed3f7dSjeremylt S[12] * S[2] * S[9]; 180*15ed3f7dSjeremylt 181*15ed3f7dSjeremylt S_inv[2] = S[1] * S[6] * S[15] - 182*15ed3f7dSjeremylt S[1] * S[7] * S[14] - 183*15ed3f7dSjeremylt S[5] * S[2] * S[15] + 184*15ed3f7dSjeremylt S[5] * S[3] * S[14] + 185*15ed3f7dSjeremylt S[13] * S[2] * S[7] - 186*15ed3f7dSjeremylt S[13] * S[3] * S[6]; 187*15ed3f7dSjeremylt 188*15ed3f7dSjeremylt S_inv[6] = -S[0] * S[6] * S[15] + 189*15ed3f7dSjeremylt S[0] * S[7] * S[14] + 190*15ed3f7dSjeremylt S[4] * S[2] * S[15] - 191*15ed3f7dSjeremylt S[4] * S[3] * S[14] - 192*15ed3f7dSjeremylt S[12] * S[2] * S[7] + 193*15ed3f7dSjeremylt S[12] * S[3] * S[6]; 194*15ed3f7dSjeremylt 195*15ed3f7dSjeremylt S_inv[10] = S[0] * S[5] * S[15] - 196*15ed3f7dSjeremylt S[0] * S[7] * S[13] - 197*15ed3f7dSjeremylt S[4] * S[1] * S[15] + 198*15ed3f7dSjeremylt S[4] * S[3] * S[13] + 199*15ed3f7dSjeremylt S[12] * S[1] * S[7] - 200*15ed3f7dSjeremylt S[12] * S[3] * S[5]; 201*15ed3f7dSjeremylt 202*15ed3f7dSjeremylt S_inv[14] = -S[0] * S[5] * S[14] + 203*15ed3f7dSjeremylt S[0] * S[6] * S[13] + 204*15ed3f7dSjeremylt S[4] * S[1] * S[14] - 205*15ed3f7dSjeremylt S[4] * S[2] * S[13] - 206*15ed3f7dSjeremylt S[12] * S[1] * S[6] + 207*15ed3f7dSjeremylt S[12] * S[2] * S[5]; 208*15ed3f7dSjeremylt 209*15ed3f7dSjeremylt S_inv[3] = -S[1] * S[6] * S[11] + 210*15ed3f7dSjeremylt S[1] * S[7] * S[10] + 211*15ed3f7dSjeremylt S[5] * S[2] * S[11] - 212*15ed3f7dSjeremylt S[5] * S[3] * S[10] - 213*15ed3f7dSjeremylt S[9] * S[2] * S[7] + 214*15ed3f7dSjeremylt S[9] * S[3] * S[6]; 215*15ed3f7dSjeremylt 216*15ed3f7dSjeremylt S_inv[7] = S[0] * S[6] * S[11] - 217*15ed3f7dSjeremylt S[0] * S[7] * S[10] - 218*15ed3f7dSjeremylt S[4] * S[2] * S[11] + 219*15ed3f7dSjeremylt S[4] * S[3] * S[10] + 220*15ed3f7dSjeremylt S[8] * S[2] * S[7] - 221*15ed3f7dSjeremylt S[8] * S[3] * S[6]; 222*15ed3f7dSjeremylt 223*15ed3f7dSjeremylt S_inv[11] = -S[0] * S[5] * S[11] + 224*15ed3f7dSjeremylt S[0] * S[7] * S[9] + 225*15ed3f7dSjeremylt S[4] * S[1] * S[11] - 226*15ed3f7dSjeremylt S[4] * S[3] * S[9] - 227*15ed3f7dSjeremylt S[8] * S[1] * S[7] + 228*15ed3f7dSjeremylt S[8] * S[3] * S[5]; 229*15ed3f7dSjeremylt 230*15ed3f7dSjeremylt S_inv[15] = S[0] * S[5] * S[10] - 231*15ed3f7dSjeremylt S[0] * S[6] * S[9] - 232*15ed3f7dSjeremylt S[4] * S[1] * S[10] + 233*15ed3f7dSjeremylt S[4] * S[2] * S[9] + 234*15ed3f7dSjeremylt S[8] * S[1] * S[6] - 235*15ed3f7dSjeremylt S[8] * S[2] * S[5]; 236*15ed3f7dSjeremylt 237*15ed3f7dSjeremylt det = 1/(S[0]*S_inv[0] + S[1]*S_inv[4] + S[2]*S_inv[8] + S[3]*S_inv[12]); 238*15ed3f7dSjeremylt 239*15ed3f7dSjeremylt for (CeedInt i = 0; i < 16; i++) 240*15ed3f7dSjeremylt S_inv[i] *= det; 241*15ed3f7dSjeremylt } 242*15ed3f7dSjeremylt 243*15ed3f7dSjeremylt // Set initial values 244*15ed3f7dSjeremylt { 245*15ed3f7dSjeremylt CeedScalar nodes[P]; 246*15ed3f7dSjeremylt CeedLobattoQuadrature(P, nodes, NULL); 247*15ed3f7dSjeremylt CeedScalar *u; 248*15ed3f7dSjeremylt CeedVectorGetArray(U, CEED_MEM_HOST, &u); 249*15ed3f7dSjeremylt for (CeedInt i=0; i<P; i++) 250*15ed3f7dSjeremylt for (CeedInt j=0; j<P; j++) 251*15ed3f7dSjeremylt u[i*P+j] = nodes[i] + nodes[j]; 252*15ed3f7dSjeremylt CeedVectorRestoreArray(U, &u); 253*15ed3f7dSjeremylt } 254*15ed3f7dSjeremylt 255*15ed3f7dSjeremylt // Apply original operator 256*15ed3f7dSjeremylt CeedOperatorApply(op_apply, U, V, CEED_REQUEST_IMMEDIATE); 257*15ed3f7dSjeremylt 258*15ed3f7dSjeremylt // Apply FDM element inverse 259*15ed3f7dSjeremylt { 260*15ed3f7dSjeremylt // -- Zero corners 261*15ed3f7dSjeremylt CeedScalar *v; 262*15ed3f7dSjeremylt CeedVectorGetArray(V, CEED_MEM_HOST, &v); 263*15ed3f7dSjeremylt v[0] = 0.0; 264*15ed3f7dSjeremylt v[P-1] = 0.0; 265*15ed3f7dSjeremylt v[P*P-P] = 0.0; 266*15ed3f7dSjeremylt v[P*P-1] = 0.0; 267*15ed3f7dSjeremylt CeedVectorRestoreArray(V, &v); 268*15ed3f7dSjeremylt 269*15ed3f7dSjeremylt // -- Apply FDM inverse to interior 270*15ed3f7dSjeremylt CeedOperatorApply(op_inv, V, W, CEED_REQUEST_IMMEDIATE); 271*15ed3f7dSjeremylt 272*15ed3f7dSjeremylt // -- Pick off corners 273*15ed3f7dSjeremylt const CeedScalar *w; 274*15ed3f7dSjeremylt CeedScalar w_Pi[4]; 275*15ed3f7dSjeremylt CeedVectorGetArrayRead(W, CEED_MEM_HOST, &w); 276*15ed3f7dSjeremylt w_Pi[0] = w[0]; 277*15ed3f7dSjeremylt w_Pi[1] = w[P-1]; 278*15ed3f7dSjeremylt w_Pi[2] = w[P*P-P]; 279*15ed3f7dSjeremylt w_Pi[3] = w[P*P-1]; 280*15ed3f7dSjeremylt CeedVectorRestoreArrayRead(W, &w); 281*15ed3f7dSjeremylt 282*15ed3f7dSjeremylt // -- Apply inverse of Schur complement 283*15ed3f7dSjeremylt CeedScalar v_Pi[4]; 284*15ed3f7dSjeremylt for (CeedInt i=0; i<4; i++) { 285*15ed3f7dSjeremylt CeedScalar sum = 0.0; 286*15ed3f7dSjeremylt for (CeedInt j=0; j<4; j++) { 287*15ed3f7dSjeremylt sum += w_Pi[j] * S_inv[i*4+j]; 288*15ed3f7dSjeremylt } 289*15ed3f7dSjeremylt v_Pi[i] = -sum; 290*15ed3f7dSjeremylt } 291*15ed3f7dSjeremylt 292*15ed3f7dSjeremylt // -- Set corners 293*15ed3f7dSjeremylt CeedVectorGetArray(V, CEED_MEM_HOST, &v); 294*15ed3f7dSjeremylt v[0] = v_Pi[0]; 295*15ed3f7dSjeremylt v[P-1] = v_Pi[1]; 296*15ed3f7dSjeremylt v[P*P-P] = v_Pi[2]; 297*15ed3f7dSjeremylt v[P*P-1] = v_Pi[3]; 298*15ed3f7dSjeremylt CeedVectorRestoreArray(V, &v); 299*15ed3f7dSjeremylt 300*15ed3f7dSjeremylt // -- Apply full FDM inverse again 301*15ed3f7dSjeremylt CeedOperatorApply(op_inv, V, W, CEED_REQUEST_IMMEDIATE); 302*15ed3f7dSjeremylt } 303*15ed3f7dSjeremylt 304*15ed3f7dSjeremylt 305*15ed3f7dSjeremylt // Check output 306*15ed3f7dSjeremylt { 307*15ed3f7dSjeremylt const CeedScalar *u, *w; 308*15ed3f7dSjeremylt CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u); 309*15ed3f7dSjeremylt CeedVectorGetArrayRead(W, CEED_MEM_HOST, &w); 310*15ed3f7dSjeremylt for (CeedInt i=0; i<P; i++) 311*15ed3f7dSjeremylt for (CeedInt j=0; j<P; j++) 312*15ed3f7dSjeremylt if (fabs(u[i*P+j] - w[i*P+j]) > 5e-14) 313*15ed3f7dSjeremylt // LCOV_EXCL_START 314*15ed3f7dSjeremylt printf("[%d, %d] Error in inverse: %e != %e\n", i, j, w[i*P+j], u[i*P+j]); 315*15ed3f7dSjeremylt // LCOV_EXCL_STOP 316*15ed3f7dSjeremylt CeedVectorRestoreArrayRead(U, &u); 317*15ed3f7dSjeremylt CeedVectorRestoreArrayRead(W, &w); 318*15ed3f7dSjeremylt } 319*15ed3f7dSjeremylt 320*15ed3f7dSjeremylt // Cleanup 321*15ed3f7dSjeremylt CeedQFunctionDestroy(&qf_setup_diff); 322*15ed3f7dSjeremylt CeedQFunctionDestroy(&qf_apply); 323*15ed3f7dSjeremylt CeedOperatorDestroy(&op_setup_diff); 324*15ed3f7dSjeremylt CeedOperatorDestroy(&op_apply); 325*15ed3f7dSjeremylt CeedOperatorDestroy(&op_inv); 326*15ed3f7dSjeremylt CeedElemRestrictionDestroy(&elem_restr_u_i); 327*15ed3f7dSjeremylt CeedElemRestrictionDestroy(&elem_restr_x_i); 328*15ed3f7dSjeremylt CeedElemRestrictionDestroy(&elem_restr_qd_i); 329*15ed3f7dSjeremylt CeedBasisDestroy(&basis_x); 330*15ed3f7dSjeremylt CeedBasisDestroy(&basis_u); 331*15ed3f7dSjeremylt CeedVectorDestroy(&X); 332*15ed3f7dSjeremylt CeedVectorDestroy(&q_data_diff); 333*15ed3f7dSjeremylt CeedVectorDestroy(&U); 334*15ed3f7dSjeremylt CeedVectorDestroy(&V); 335*15ed3f7dSjeremylt CeedVectorDestroy(&W); 336*15ed3f7dSjeremylt CeedDestroy(&ceed); 337*15ed3f7dSjeremylt return 0; 338*15ed3f7dSjeremylt } 339