1*afeb93e9SKartiki Pandeusing LibCEED, Printf 2*afeb93e9SKartiki Pande 3*afeb93e9SKartiki Pandeinclude("common.jl") 4*afeb93e9SKartiki Pande 5*afeb93e9SKartiki Pandefunction transform_mesh_coords!(dim, mesh_size, mesh_coords) 6*afeb93e9SKartiki Pande @witharray coords = mesh_coords begin 7*afeb93e9SKartiki Pande if dim == 1 8*afeb93e9SKartiki Pande for i = 1:mesh_size 9*afeb93e9SKartiki Pande # map [0,1] to [0,1] varying the mesh density 10*afeb93e9SKartiki Pande coords[i] = 0.5 + 1.0/sqrt(3.0)*sin((2.0/3.0)*pi*(coords[i] - 0.5)) 11*afeb93e9SKartiki Pande end 12*afeb93e9SKartiki Pande exact_volume = 1.0 13*afeb93e9SKartiki Pande else 14*afeb93e9SKartiki Pande num_nodes = mesh_size÷dim 15*afeb93e9SKartiki Pande @inbounds @simd for i = 1:num_nodes 16*afeb93e9SKartiki Pande # map (x,y) from [0,1]x[0,1] to the quarter annulus with polar 17*afeb93e9SKartiki Pande # coordinates, (r,phi) in [1,2]x[0,pi/2] with area = 3/4*pi 18*afeb93e9SKartiki Pande u = coords[i] 19*afeb93e9SKartiki Pande v = coords[i+num_nodes] 20*afeb93e9SKartiki Pande u = 1.0 + u 21*afeb93e9SKartiki Pande v = pi/2*v 22*afeb93e9SKartiki Pande coords[i] = u*cos(v) 23*afeb93e9SKartiki Pande coords[i+num_nodes] = u*sin(v) 24*afeb93e9SKartiki Pande end 25*afeb93e9SKartiki Pande exact_volume = 3.0/4.0*pi 26*afeb93e9SKartiki Pande end 27*afeb93e9SKartiki Pande return exact_volume 28*afeb93e9SKartiki Pande end 29*afeb93e9SKartiki Pandeend 30*afeb93e9SKartiki Pande 31*afeb93e9SKartiki Pandefunction run_ex3(; ceed_spec, dim, mesh_order, sol_order, num_qpts, prob_size) 32*afeb93e9SKartiki Pande ncompx = dim 33*afeb93e9SKartiki Pande prob_size < 0 && (prob_size = 256*1024) 34*afeb93e9SKartiki Pande 35*afeb93e9SKartiki Pande ceed = Ceed(ceed_spec) 36*afeb93e9SKartiki Pande mesh_basis = 37*afeb93e9SKartiki Pande create_tensor_h1_lagrange_basis(ceed, dim, ncompx, mesh_order + 1, num_qpts, GAUSS) 38*afeb93e9SKartiki Pande sol_basis = 39*afeb93e9SKartiki Pande create_tensor_h1_lagrange_basis(ceed, dim, 1, sol_order + 1, num_qpts, GAUSS) 40*afeb93e9SKartiki Pande 41*afeb93e9SKartiki Pande # Determine the mesh size based on the given approximate problem size. 42*afeb93e9SKartiki Pande nxyz = get_cartesian_mesh_size(dim, sol_order, prob_size) 43*afeb93e9SKartiki Pande println("Mesh size: ", nxyz) 44*afeb93e9SKartiki Pande 45*afeb93e9SKartiki Pande # Build CeedElemRestriction objects describing the mesh and solution discrete 46*afeb93e9SKartiki Pande # representations. 47*afeb93e9SKartiki Pande mesh_size, mesh_rstr, _ = 48*afeb93e9SKartiki Pande build_cartesian_restriction(ceed, dim, nxyz, mesh_order, ncompx, num_qpts) 49*afeb93e9SKartiki Pande num_q_comp = 1 + div(dim*(dim + 1), 2) 50*afeb93e9SKartiki Pande sol_size, _, qdata_rstr_i = build_cartesian_restriction( 51*afeb93e9SKartiki Pande ceed, 52*afeb93e9SKartiki Pande dim, 53*afeb93e9SKartiki Pande nxyz, 54*afeb93e9SKartiki Pande sol_order, 55*afeb93e9SKartiki Pande num_q_comp, 56*afeb93e9SKartiki Pande num_qpts, 57*afeb93e9SKartiki Pande mode=StridedOnly, 58*afeb93e9SKartiki Pande ) 59*afeb93e9SKartiki Pande sol_size, sol_rstr, sol_rstr_i = build_cartesian_restriction( 60*afeb93e9SKartiki Pande ceed, 61*afeb93e9SKartiki Pande dim, 62*afeb93e9SKartiki Pande nxyz, 63*afeb93e9SKartiki Pande sol_order, 64*afeb93e9SKartiki Pande 1, 65*afeb93e9SKartiki Pande num_qpts, 66*afeb93e9SKartiki Pande mode=RestrictionAndStrided, 67*afeb93e9SKartiki Pande ) 68*afeb93e9SKartiki Pande println("Number of mesh nodes : ", div(mesh_size, dim)) 69*afeb93e9SKartiki Pande println("Number of solution nodes : ", sol_size) 70*afeb93e9SKartiki Pande 71*afeb93e9SKartiki Pande # Create a CeedVector with the mesh coordinates. 72*afeb93e9SKartiki Pande mesh_coords = CeedVector(ceed, mesh_size) 73*afeb93e9SKartiki Pande set_cartesian_mesh_coords!(dim, nxyz, mesh_order, mesh_coords) 74*afeb93e9SKartiki Pande # Apply a transformation to the mesh. 75*afeb93e9SKartiki Pande exact_vol = transform_mesh_coords!(dim, mesh_size, mesh_coords) 76*afeb93e9SKartiki Pande 77*afeb93e9SKartiki Pande #Create the Q-function that builds the mass+diffusion operator ( i.e it computes the quadrature data) and set its context data. 78*afeb93e9SKartiki Pande @interior_qf build_qfunc = ( 79*afeb93e9SKartiki Pande ceed, 80*afeb93e9SKartiki Pande dim=dim, 81*afeb93e9SKartiki Pande (dx, :in, EVAL_GRAD, dim, dim), # ← THIS LINE: dx input 82*afeb93e9SKartiki Pande (weights, :in, EVAL_WEIGHT), # ← weights input 83*afeb93e9SKartiki Pande (qdata, :out, EVAL_NONE, num_q_comp), # ← qdata output 84*afeb93e9SKartiki Pande begin 85*afeb93e9SKartiki Pande # Compute determinant 86*afeb93e9SKartiki Pande det_J = det(dx) 87*afeb93e9SKartiki Pande 88*afeb93e9SKartiki Pande # Store mass component 89*afeb93e9SKartiki Pande qdata[1] = weights*det_J 90*afeb93e9SKartiki Pande 91*afeb93e9SKartiki Pande # Store diffusion components (J^T * J) 92*afeb93e9SKartiki Pande idx = 2 93*afeb93e9SKartiki Pande for i = 1:dim 94*afeb93e9SKartiki Pande for j = i:dim 95*afeb93e9SKartiki Pande qdata[idx] = dx[:, i]'*dx[:, j] 96*afeb93e9SKartiki Pande idx += 1 97*afeb93e9SKartiki Pande end 98*afeb93e9SKartiki Pande end 99*afeb93e9SKartiki Pande end, 100*afeb93e9SKartiki Pande ) 101*afeb93e9SKartiki Pande 102*afeb93e9SKartiki Pande # Create the operator that builds the quadrature data for the mass+diffusion operator. 103*afeb93e9SKartiki Pande build_oper = Operator( 104*afeb93e9SKartiki Pande ceed, 105*afeb93e9SKartiki Pande qf=build_qfunc, 106*afeb93e9SKartiki Pande fields=[ 107*afeb93e9SKartiki Pande (:dx, mesh_rstr, mesh_basis, CeedVectorActive()), 108*afeb93e9SKartiki Pande (:weights, ElemRestrictionNone(), mesh_basis, CeedVectorNone()), 109*afeb93e9SKartiki Pande (:qdata, qdata_rstr_i, BasisNone(), CeedVectorActive()), 110*afeb93e9SKartiki Pande ], 111*afeb93e9SKartiki Pande ) 112*afeb93e9SKartiki Pande 113*afeb93e9SKartiki Pande # Compute the quadrature data for the mass+diff operator. 114*afeb93e9SKartiki Pande elem_qpts = num_qpts^dim 115*afeb93e9SKartiki Pande num_elem = prod(nxyz) 116*afeb93e9SKartiki Pande qdata = CeedVector(ceed, num_elem*elem_qpts*num_q_comp) 117*afeb93e9SKartiki Pande print("Computing the quadrature data for the mass+diffusion operator ...") 118*afeb93e9SKartiki Pande flush(stdout) 119*afeb93e9SKartiki Pande apply!(build_oper, mesh_coords, qdata) 120*afeb93e9SKartiki Pande println(" done.") 121*afeb93e9SKartiki Pande 122*afeb93e9SKartiki Pande # Create the Q-function that defines the action of the mass+diffusion operator. 123*afeb93e9SKartiki Pande @interior_qf apply_qfunc = ( 124*afeb93e9SKartiki Pande ceed, 125*afeb93e9SKartiki Pande dim=dim, 126*afeb93e9SKartiki Pande (u, :in, EVAL_INTERP), 127*afeb93e9SKartiki Pande (du, :in, EVAL_GRAD, dim), 128*afeb93e9SKartiki Pande (qdata, :in, EVAL_NONE, num_q_comp), 129*afeb93e9SKartiki Pande (v, :out, EVAL_INTERP), 130*afeb93e9SKartiki Pande (dv, :out, EVAL_GRAD, dim), 131*afeb93e9SKartiki Pande begin 132*afeb93e9SKartiki Pande # Apply mass: v = qdata[1] * u 133*afeb93e9SKartiki Pande v .= qdata[1].*u 134*afeb93e9SKartiki Pande 135*afeb93e9SKartiki Pande # Apply diffusion: dv = (qdata[2:end]) * du 136*afeb93e9SKartiki Pande # The qdata contains the symmetric diffusion tensor (J^T*J) 137*afeb93e9SKartiki Pande # dv_i = sum_j (J^T*J)_{i,j} * du_j 138*afeb93e9SKartiki Pande 139*afeb93e9SKartiki Pande # For efficiency, rebuild the matrix from stored components 140*afeb93e9SKartiki Pande idx = 2 141*afeb93e9SKartiki Pande for i = 1:dim 142*afeb93e9SKartiki Pande dv_i = 0.0 143*afeb93e9SKartiki Pande for j = 1:dim 144*afeb93e9SKartiki Pande # Reconstruct symmetric matrix element 145*afeb93e9SKartiki Pande if j >= i 146*afeb93e9SKartiki Pande mat_idx = idx + div((j - 1)*j, 2) + (i - 1) 147*afeb93e9SKartiki Pande else 148*afeb93e9SKartiki Pande mat_idx = idx + div((i - 1)*i, 2) + (j - 1) 149*afeb93e9SKartiki Pande end 150*afeb93e9SKartiki Pande dv_i += qdata[mat_idx]*du[j] 151*afeb93e9SKartiki Pande end 152*afeb93e9SKartiki Pande dv[i] = dv_i 153*afeb93e9SKartiki Pande end 154*afeb93e9SKartiki Pande end, 155*afeb93e9SKartiki Pande ) 156*afeb93e9SKartiki Pande 157*afeb93e9SKartiki Pande # Create the mass+diffusion operator. 158*afeb93e9SKartiki Pande oper = Operator( 159*afeb93e9SKartiki Pande ceed, 160*afeb93e9SKartiki Pande qf=apply_qfunc, 161*afeb93e9SKartiki Pande fields=[ 162*afeb93e9SKartiki Pande (:u, sol_rstr, sol_basis, CeedVectorActive()), 163*afeb93e9SKartiki Pande (:du, sol_rstr, sol_basis, CeedVectorActive()), 164*afeb93e9SKartiki Pande (:qdata, qdata_rstr_i, BasisNone(), qdata), 165*afeb93e9SKartiki Pande (:v, sol_rstr, sol_basis, CeedVectorActive()), 166*afeb93e9SKartiki Pande (:dv, sol_rstr, sol_basis, CeedVectorActive()), 167*afeb93e9SKartiki Pande ], 168*afeb93e9SKartiki Pande ) 169*afeb93e9SKartiki Pande 170*afeb93e9SKartiki Pande # Compute the mesh volume using the mass+diffusion operator: vol = 1^T \cdot (M + K) \cdot 1 171*afeb93e9SKartiki Pande print("Computing the mesh volume using the formula: vol = 1^T * (M + K) * 1...") 172*afeb93e9SKartiki Pande flush(stdout) 173*afeb93e9SKartiki Pande # Create auxiliary solution-size vectors. 174*afeb93e9SKartiki Pande u = CeedVector(ceed, sol_size) 175*afeb93e9SKartiki Pande v = CeedVector(ceed, sol_size) 176*afeb93e9SKartiki Pande # Initialize 'u' with ones. 177*afeb93e9SKartiki Pande u[] = 1.0 178*afeb93e9SKartiki Pande # Apply the mass+diffusion operator: 'u' -> 'v'. 179*afeb93e9SKartiki Pande apply!(oper, u, v) 180*afeb93e9SKartiki Pande # Compute and print the sum of the entries of 'v' giving the mesh volume. 181*afeb93e9SKartiki Pande vol = witharray_read(sum, v, MEM_HOST) 182*afeb93e9SKartiki Pande 183*afeb93e9SKartiki Pande println(" done.") 184*afeb93e9SKartiki Pande @printf("Exact mesh volume : % .14g\n", exact_vol) 185*afeb93e9SKartiki Pande @printf("Computed mesh volume : % .14g\n", vol) 186*afeb93e9SKartiki Pande @printf("Volume error : % .14g\n", vol - exact_vol) 187*afeb93e9SKartiki Pandeend 188*afeb93e9SKartiki Pande 189*afeb93e9SKartiki Pande# Entry point 190*afeb93e9SKartiki Panderun_ex3( 191*afeb93e9SKartiki Pande ceed_spec="/cpu/self", 192*afeb93e9SKartiki Pande dim=3, 193*afeb93e9SKartiki Pande mesh_order=4, 194*afeb93e9SKartiki Pande sol_order=4, 195*afeb93e9SKartiki Pande num_qpts=4 + 2, 196*afeb93e9SKartiki Pande prob_size=-1, 197*afeb93e9SKartiki Pande) 198