13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3ed264d09SValeria Barra // 43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 5ed264d09SValeria Barra // 63d8e8822SJeremy L Thompson // This file is part of CEED: http://github.com/ceed 7ed264d09SValeria Barra 8ed264d09SValeria Barra /// @file 9ed264d09SValeria Barra /// libCEED QFunctions for mass operator example for a scalar field on the sphere using PETSc 10ed264d09SValeria Barra 11f6b55d2cSvaleriabarra #ifndef bp1sphere_h 12f6b55d2cSvaleriabarra #define bp1sphere_h 13f6b55d2cSvaleriabarra 14*c9c2c079SJeremy L Thompson #include <ceed.h> 15ed264d09SValeria Barra #include <math.h> 16ed264d09SValeria Barra 17e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 18ed264d09SValeria Barra // This QFunction sets up the geometric factors required for integration and 19ed264d09SValeria Barra // coordinate transformations when reference coordinates have a different 20ed264d09SValeria Barra // dimension than the one of physical coordinates 21ed264d09SValeria Barra // 22ed264d09SValeria Barra // Reference (parent) 2D coordinates: X \in [-1, 1]^2 23ed264d09SValeria Barra // 24ed264d09SValeria Barra // Global 3D physical coordinates given by the mesh: xx \in [-R, R]^3 25ed264d09SValeria Barra // with R radius of the sphere 26ed264d09SValeria Barra // 27ed264d09SValeria Barra // Local 3D physical coordinates on the 2D manifold: x \in [-l, l]^3 28ed264d09SValeria Barra // with l half edge of the cube inscribed in the sphere 29ed264d09SValeria Barra // 30ed264d09SValeria Barra // Change of coordinates matrix computed by the library: 31ed264d09SValeria Barra // (physical 3D coords relative to reference 2D coords) 32ed264d09SValeria Barra // dxx_j/dX_i (indicial notation) [3 * 2] 33ed264d09SValeria Barra // 34ed264d09SValeria Barra // Change of coordinates x (on the 2D manifold) relative to xx (phyisical 3D): 35ed264d09SValeria Barra // dx_i/dxx_j (indicial notation) [3 * 3] 36ed264d09SValeria Barra // 37ed264d09SValeria Barra // Change of coordinates x (on the 2D manifold) relative to X (reference 2D): 38ed264d09SValeria Barra // (by chain rule) 39ed264d09SValeria Barra // dx_i/dX_j [3 * 2] = dx_i/dxx_k [3 * 3] * dxx_k/dX_j [3 * 2] 40ed264d09SValeria Barra // 419b072555Sjeremylt // mod_J is given by the magnitude of the cross product of the columns of dx_i/dX_j 42ed264d09SValeria Barra // 439b072555Sjeremylt // The quadrature data is stored in the array q_data. 44ed264d09SValeria Barra // 45ed264d09SValeria Barra // We require the determinant of the Jacobian to properly compute integrals of 46ed264d09SValeria Barra // the form: int( u v ) 47ed264d09SValeria Barra // 489b072555Sjeremylt // Qdata: mod_J * w 49ed264d09SValeria Barra // 50e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 51ed264d09SValeria Barra CEED_QFUNCTION(SetupMassGeo)(void *ctx, const CeedInt Q, 52ed264d09SValeria Barra const CeedScalar *const *in, 53ed264d09SValeria Barra CeedScalar *const *out) { 54ed264d09SValeria Barra // Inputs 55ed264d09SValeria Barra const CeedScalar *X = in[0], *J = in[1], *w = in[2]; 56ed264d09SValeria Barra // Outputs 579b072555Sjeremylt CeedScalar *q_data = out[0]; 58ed264d09SValeria Barra 59ed264d09SValeria Barra // Quadrature Point Loop 60ed264d09SValeria Barra CeedPragmaSIMD 61ed264d09SValeria Barra for (CeedInt i=0; i<Q; i++) { 62ed264d09SValeria Barra // Read global Cartesian coordinates 63ed264d09SValeria Barra const CeedScalar xx[3] = {X[i+0*Q], 64ed264d09SValeria Barra X[i+1*Q], 65ed264d09SValeria Barra X[i+2*Q] 66ed264d09SValeria Barra }; 67ed264d09SValeria Barra 68ed264d09SValeria Barra // Read dxxdX Jacobian entries, stored as 69ed264d09SValeria Barra // 0 3 70ed264d09SValeria Barra // 1 4 71ed264d09SValeria Barra // 2 5 72ed264d09SValeria Barra const CeedScalar dxxdX[3][2] = {{J[i+Q*0], 73ed264d09SValeria Barra J[i+Q*3]}, 74ed264d09SValeria Barra {J[i+Q*1], 75ed264d09SValeria Barra J[i+Q*4]}, 76ed264d09SValeria Barra {J[i+Q*2], 77ed264d09SValeria Barra J[i+Q*5]} 78ed264d09SValeria Barra }; 79ed264d09SValeria Barra 80ed264d09SValeria Barra // Setup 81ed264d09SValeria Barra // x = xx (xx^T xx)^{-1/2} 82ed264d09SValeria Barra // dx/dxx = I (xx^T xx)^{-1/2} - xx xx^T (xx^T xx)^{-3/2} 839b072555Sjeremylt const CeedScalar mod_xx_sq = xx[0]*xx[0]+xx[1]*xx[1]+xx[2]*xx[2]; 849b072555Sjeremylt CeedScalar xx_sq[3][3]; 85ed264d09SValeria Barra for (int j=0; j<3; j++) 86ed264d09SValeria Barra for (int k=0; k<3; k++) 879b072555Sjeremylt xx_sq[j][k] = xx[j]*xx[k] / (sqrt(mod_xx_sq) * mod_xx_sq); 88ed264d09SValeria Barra 899b072555Sjeremylt const CeedScalar dxdxx[3][3] = {{1./sqrt(mod_xx_sq) - xx_sq[0][0], 909b072555Sjeremylt -xx_sq[0][1], 919b072555Sjeremylt -xx_sq[0][2]}, 929b072555Sjeremylt {-xx_sq[1][0], 939b072555Sjeremylt 1./sqrt(mod_xx_sq) - xx_sq[1][1], 949b072555Sjeremylt -xx_sq[1][2]}, 959b072555Sjeremylt {-xx_sq[2][0], 969b072555Sjeremylt -xx_sq[2][1], 979b072555Sjeremylt 1./sqrt(mod_xx_sq) - xx_sq[2][2]} 98ed264d09SValeria Barra }; 99ed264d09SValeria Barra 100ed264d09SValeria Barra CeedScalar dxdX[3][2]; 101ed264d09SValeria Barra for (int j=0; j<3; j++) 102ed264d09SValeria Barra for (int k=0; k<2; k++) { 103ed264d09SValeria Barra dxdX[j][k] = 0; 104ed264d09SValeria Barra for (int l=0; l<3; l++) 105ed264d09SValeria Barra dxdX[j][k] += dxdxx[j][l]*dxxdX[l][k]; 106ed264d09SValeria Barra } 107ed264d09SValeria Barra 108ed264d09SValeria Barra // J is given by the cross product of the columns of dxdX 109ed264d09SValeria Barra const CeedScalar J[3] = {dxdX[1][0]*dxdX[2][1] - dxdX[2][0]*dxdX[1][1], 110ed264d09SValeria Barra dxdX[2][0]*dxdX[0][1] - dxdX[0][0]*dxdX[2][1], 111ed264d09SValeria Barra dxdX[0][0]*dxdX[1][1] - dxdX[1][0]*dxdX[0][1] 112ed264d09SValeria Barra }; 113ed264d09SValeria Barra 114ed264d09SValeria Barra // Use the magnitude of J as our detJ (volume scaling factor) 1159b072555Sjeremylt const CeedScalar mod_J = sqrt(J[0]*J[0]+J[1]*J[1]+J[2]*J[2]); 116ed264d09SValeria Barra 1179b072555Sjeremylt // Interp-to-Interp q_data 1189b072555Sjeremylt q_data[i+Q*0] = mod_J * w[i]; 119ed264d09SValeria Barra } // End of Quadrature Point Loop 120ed264d09SValeria Barra 121ed264d09SValeria Barra return 0; 122ed264d09SValeria Barra } 123ed264d09SValeria Barra 124e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 125ed264d09SValeria Barra // This QFunction sets up the rhs and true solution for the problem 126ed264d09SValeria Barra // ----------------------------------------------------------------------------- 127ed264d09SValeria Barra CEED_QFUNCTION(SetupMassRhs)(void *ctx, const CeedInt Q, 128ed264d09SValeria Barra const CeedScalar *const *in, 129ed264d09SValeria Barra CeedScalar *const *out) { 130ed264d09SValeria Barra // Inputs 1319b072555Sjeremylt const CeedScalar *X = in[0], *q_data = in[1]; 132ed264d09SValeria Barra // Outputs 133ed264d09SValeria Barra CeedScalar *true_soln = out[0], *rhs = out[1]; 134ed264d09SValeria Barra 135ed264d09SValeria Barra // Context 136ed264d09SValeria Barra const CeedScalar *context = (const CeedScalar*)ctx; 137ed264d09SValeria Barra const CeedScalar R = context[0]; 138ed264d09SValeria Barra 139ed264d09SValeria Barra // Quadrature Point Loop 140ed264d09SValeria Barra CeedPragmaSIMD 141ed264d09SValeria Barra for (CeedInt i=0; i<Q; i++) { 142ed264d09SValeria Barra // Compute latitude 143ed264d09SValeria Barra const CeedScalar theta = asin(X[i+2*Q] / R); 144ed264d09SValeria Barra 1459b072555Sjeremylt // Use absolute value of latitude for true solution 146ed264d09SValeria Barra true_soln[i] = fabs(theta); 147ed264d09SValeria Barra 1489b072555Sjeremylt rhs[i] = q_data[i] * true_soln[i]; 149ed264d09SValeria Barra } // End of Quadrature Point Loop 150ed264d09SValeria Barra 151ed264d09SValeria Barra return 0; 152ed264d09SValeria Barra } 153ed264d09SValeria Barra 154e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 155ed264d09SValeria Barra // This QFunction applies the mass operator for a scalar field. 156ed264d09SValeria Barra // 157ed264d09SValeria Barra // Inputs: 158ed264d09SValeria Barra // u - Input vector at quadrature points 1599b072555Sjeremylt // q_data - Geometric factors 160ed264d09SValeria Barra // 161ed264d09SValeria Barra // Output: 162ed264d09SValeria Barra // v - Output vector (test functions) at quadrature points 163ed264d09SValeria Barra // 164ed264d09SValeria Barra // ----------------------------------------------------------------------------- 165ed264d09SValeria Barra CEED_QFUNCTION(Mass)(void *ctx, const CeedInt Q, 166ed264d09SValeria Barra const CeedScalar *const *in, CeedScalar *const *out) { 167ed264d09SValeria Barra // Inputs 1689b072555Sjeremylt const CeedScalar *u = in[0], *q_data = in[1]; 169ed264d09SValeria Barra // Outputs 170ed264d09SValeria Barra CeedScalar *v = out[0]; 171ed264d09SValeria Barra 172ed264d09SValeria Barra // Quadrature Point Loop 173ed264d09SValeria Barra CeedPragmaSIMD 174ed264d09SValeria Barra for (CeedInt i=0; i<Q; i++) 1759b072555Sjeremylt v[i] = q_data[i] * u[i]; 176ed264d09SValeria Barra 177ed264d09SValeria Barra return 0; 178ed264d09SValeria Barra } 179ed264d09SValeria Barra // ----------------------------------------------------------------------------- 180f6b55d2cSvaleriabarra 181f6b55d2cSvaleriabarra #endif // bp1sphere_h 182