1*3eb59678SJeremy L Thompson // Copyright (c) 2017-2025, Lawrence Livermore National Security, LLC and other CEED contributors. 2*3eb59678SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3*3eb59678SJeremy L Thompson // 4*3eb59678SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 5*3eb59678SJeremy L Thompson // 6*3eb59678SJeremy L Thompson // This file is part of CEED: http://github.com/ceed 7*3eb59678SJeremy L Thompson // 8*3eb59678SJeremy L Thompson // libCEED Example 4 9*3eb59678SJeremy L Thompson // 10*3eb59678SJeremy L Thompson // This example illustrates a simple usage of libCEED to compute the surface 11*3eb59678SJeremy L Thompson // area of a 3D body using matrix-free application of a diffusion operator. 12*3eb59678SJeremy L Thompson // Arbitrary mesh and solution degrees in 1D, 2D and 3D are supported from the 13*3eb59678SJeremy L Thompson // same code. This calculation is executed in triplicate with a 3 component 14*3eb59678SJeremy L Thompson // vector system. 15*3eb59678SJeremy L Thompson // 16*3eb59678SJeremy L Thompson // The example has no dependencies, and is designed to be self-contained. For 17*3eb59678SJeremy L Thompson // additional examples that use external discretization libraries (MFEM, PETSc, 18*3eb59678SJeremy L Thompson // etc.) see the subdirectories in libceed/examples. 19*3eb59678SJeremy L Thompson // 20*3eb59678SJeremy L Thompson // All libCEED objects use a Ceed device object constructed based on a command 21*3eb59678SJeremy L Thompson // line argument (-ceed). 22*3eb59678SJeremy L Thompson 23*3eb59678SJeremy L Thompson use clap::Parser; 24*3eb59678SJeremy L Thompson use libceed::{ 25*3eb59678SJeremy L Thompson BasisOpt, Ceed, ElemRestrictionOpt, QFunctionInputs, QFunctionOpt, QFunctionOutputs, VectorOpt, 26*3eb59678SJeremy L Thompson }; 27*3eb59678SJeremy L Thompson mod opt; 28*3eb59678SJeremy L Thompson mod transform; 29*3eb59678SJeremy L Thompson 30*3eb59678SJeremy L Thompson // ---------------------------------------------------------------------------- 31*3eb59678SJeremy L Thompson // Example 4 32*3eb59678SJeremy L Thompson // ---------------------------------------------------------------------------- 33*3eb59678SJeremy L Thompson fn main() -> libceed::Result<()> { 34*3eb59678SJeremy L Thompson let options = opt::Opt::parse(); 35*3eb59678SJeremy L Thompson example_2_vector(options) 36*3eb59678SJeremy L Thompson } 37*3eb59678SJeremy L Thompson 38*3eb59678SJeremy L Thompson #[allow(clippy::erasing_op)] 39*3eb59678SJeremy L Thompson #[allow(clippy::identity_op)] 40*3eb59678SJeremy L Thompson fn example_2_vector(options: opt::Opt) -> libceed::Result<()> { 41*3eb59678SJeremy L Thompson // Process command line arguments 42*3eb59678SJeremy L Thompson let opt::Opt { 43*3eb59678SJeremy L Thompson ceed_spec, 44*3eb59678SJeremy L Thompson dim, 45*3eb59678SJeremy L Thompson mesh_degree, 46*3eb59678SJeremy L Thompson solution_degree, 47*3eb59678SJeremy L Thompson num_qpts, 48*3eb59678SJeremy L Thompson problem_size_requested, 49*3eb59678SJeremy L Thompson test, 50*3eb59678SJeremy L Thompson quiet, 51*3eb59678SJeremy L Thompson gallery, 52*3eb59678SJeremy L Thompson } = options; 53*3eb59678SJeremy L Thompson assert!((0..=3).contains(&dim)); 54*3eb59678SJeremy L Thompson assert!(mesh_degree >= 1); 55*3eb59678SJeremy L Thompson assert!(solution_degree >= 1); 56*3eb59678SJeremy L Thompson assert!(num_qpts >= 1); 57*3eb59678SJeremy L Thompson let ncomp_x = dim; 58*3eb59678SJeremy L Thompson let problem_size: i64 = if problem_size_requested < 0 { 59*3eb59678SJeremy L Thompson if test { 60*3eb59678SJeremy L Thompson 16 * 16 * (dim * dim) as i64 61*3eb59678SJeremy L Thompson } else { 62*3eb59678SJeremy L Thompson 256 * 1024 63*3eb59678SJeremy L Thompson } 64*3eb59678SJeremy L Thompson } else { 65*3eb59678SJeremy L Thompson problem_size_requested 66*3eb59678SJeremy L Thompson }; 67*3eb59678SJeremy L Thompson let ncomp_u = 3; 68*3eb59678SJeremy L Thompson 69*3eb59678SJeremy L Thompson // Summary output 70*3eb59678SJeremy L Thompson if !quiet { 71*3eb59678SJeremy L Thompson println!("Selected options: [command line option] : <current value>"); 72*3eb59678SJeremy L Thompson println!(" Ceed specification [-c] : {}", ceed_spec); 73*3eb59678SJeremy L Thompson println!(" Mesh dimension [-d] : {}", dim); 74*3eb59678SJeremy L Thompson println!(" Mesh degree [-m] : {}", mesh_degree); 75*3eb59678SJeremy L Thompson println!(" Solution degree [-p] : {}", solution_degree); 76*3eb59678SJeremy L Thompson println!(" Num. 1D quadr. pts [-q] : {}", num_qpts); 77*3eb59678SJeremy L Thompson println!(" Approx. # unknowns [-s] : {}", problem_size); 78*3eb59678SJeremy L Thompson println!( 79*3eb59678SJeremy L Thompson " QFunction source [-g] : {}", 80*3eb59678SJeremy L Thompson if gallery { "gallery" } else { "user closure" } 81*3eb59678SJeremy L Thompson ); 82*3eb59678SJeremy L Thompson } 83*3eb59678SJeremy L Thompson 84*3eb59678SJeremy L Thompson // Initalize ceed context 85*3eb59678SJeremy L Thompson let ceed = Ceed::init(&ceed_spec); 86*3eb59678SJeremy L Thompson 87*3eb59678SJeremy L Thompson // Mesh and solution bases 88*3eb59678SJeremy L Thompson let basis_mesh = ceed.basis_tensor_H1_Lagrange( 89*3eb59678SJeremy L Thompson dim, 90*3eb59678SJeremy L Thompson ncomp_x, 91*3eb59678SJeremy L Thompson mesh_degree + 1, 92*3eb59678SJeremy L Thompson num_qpts, 93*3eb59678SJeremy L Thompson libceed::QuadMode::Gauss, 94*3eb59678SJeremy L Thompson )?; 95*3eb59678SJeremy L Thompson let basis_solution = ceed.basis_tensor_H1_Lagrange( 96*3eb59678SJeremy L Thompson dim, 97*3eb59678SJeremy L Thompson ncomp_u, 98*3eb59678SJeremy L Thompson solution_degree + 1, 99*3eb59678SJeremy L Thompson num_qpts, 100*3eb59678SJeremy L Thompson libceed::QuadMode::Gauss, 101*3eb59678SJeremy L Thompson )?; 102*3eb59678SJeremy L Thompson 103*3eb59678SJeremy L Thompson // Determine mesh size from approximate problem size 104*3eb59678SJeremy L Thompson let num_xyz = mesh::cartesian_mesh_size(dim, solution_degree, problem_size); 105*3eb59678SJeremy L Thompson if !quiet { 106*3eb59678SJeremy L Thompson print!("\nMesh size : nx = {}", num_xyz[0]); 107*3eb59678SJeremy L Thompson if dim > 1 { 108*3eb59678SJeremy L Thompson print!(", ny = {}", num_xyz[1]); 109*3eb59678SJeremy L Thompson } 110*3eb59678SJeremy L Thompson if dim > 2 { 111*3eb59678SJeremy L Thompson print!(", nz = {}", num_xyz[2]); 112*3eb59678SJeremy L Thompson } 113*3eb59678SJeremy L Thompson println!(); 114*3eb59678SJeremy L Thompson } 115*3eb59678SJeremy L Thompson 116*3eb59678SJeremy L Thompson // Build ElemRestriction objects describing the mesh and solution discrete 117*3eb59678SJeremy L Thompson // representations 118*3eb59678SJeremy L Thompson let (rstr_mesh, _) = 119*3eb59678SJeremy L Thompson mesh::build_cartesian_restriction(&ceed, dim, num_xyz, mesh_degree, ncomp_x, num_qpts)?; 120*3eb59678SJeremy L Thompson let (_, rstr_qdata) = mesh::build_cartesian_restriction( 121*3eb59678SJeremy L Thompson &ceed, 122*3eb59678SJeremy L Thompson dim, 123*3eb59678SJeremy L Thompson num_xyz, 124*3eb59678SJeremy L Thompson solution_degree, 125*3eb59678SJeremy L Thompson dim * (dim + 1) / 2, 126*3eb59678SJeremy L Thompson num_qpts, 127*3eb59678SJeremy L Thompson )?; 128*3eb59678SJeremy L Thompson 129*3eb59678SJeremy L Thompson let (rstr_solution, _) = 130*3eb59678SJeremy L Thompson mesh::build_cartesian_restriction(&ceed, dim, num_xyz, solution_degree, ncomp_u, num_qpts)?; 131*3eb59678SJeremy L Thompson let mesh_size = rstr_mesh.lvector_size(); 132*3eb59678SJeremy L Thompson let solution_size = rstr_solution.lvector_size(); 133*3eb59678SJeremy L Thompson if !quiet { 134*3eb59678SJeremy L Thompson println!("Number of mesh nodes : {}", mesh_size / dim); 135*3eb59678SJeremy L Thompson println!("Number of solution nodes : {}", solution_size); 136*3eb59678SJeremy L Thompson } 137*3eb59678SJeremy L Thompson 138*3eb59678SJeremy L Thompson // Create a Vector with the mesh coordinates 139*3eb59678SJeremy L Thompson let mut mesh_coords = mesh::cartesian_mesh_coords(&ceed, dim, num_xyz, mesh_degree, mesh_size)?; 140*3eb59678SJeremy L Thompson 141*3eb59678SJeremy L Thompson // Apply a transformation to the mesh coordinates 142*3eb59678SJeremy L Thompson let exact_area = transform::transform_mesh_coordinates(dim, &mut mesh_coords)?; 143*3eb59678SJeremy L Thompson 144*3eb59678SJeremy L Thompson // QFunction that builds the quadrature data for the diff operator 145*3eb59678SJeremy L Thompson // -- QFunction from user closure 146*3eb59678SJeremy L Thompson let build_diff = move |[jacobian, weights, ..]: QFunctionInputs, 147*3eb59678SJeremy L Thompson [qdata, ..]: QFunctionOutputs| { 148*3eb59678SJeremy L Thompson // Build quadrature data 149*3eb59678SJeremy L Thompson match dim { 150*3eb59678SJeremy L Thompson 1 => qdata 151*3eb59678SJeremy L Thompson .iter_mut() 152*3eb59678SJeremy L Thompson .zip(jacobian.iter().zip(weights.iter())) 153*3eb59678SJeremy L Thompson .for_each(|(qdata, (j, weight))| *qdata = weight / j), 154*3eb59678SJeremy L Thompson 2 => { 155*3eb59678SJeremy L Thompson let q = qdata.len() / 3; 156*3eb59678SJeremy L Thompson for i in 0..q { 157*3eb59678SJeremy L Thompson let j11 = jacobian[i + q * 0]; 158*3eb59678SJeremy L Thompson let j21 = jacobian[i + q * 1]; 159*3eb59678SJeremy L Thompson let j12 = jacobian[i + q * 2]; 160*3eb59678SJeremy L Thompson let j22 = jacobian[i + q * 3]; 161*3eb59678SJeremy L Thompson let qw = weights[i] / (j11 * j22 - j21 * j12); 162*3eb59678SJeremy L Thompson qdata[i + q * 0] = qw * (j12 * j12 + j22 * j22); 163*3eb59678SJeremy L Thompson qdata[i + q * 1] = qw * (j11 * j11 + j21 * j21); 164*3eb59678SJeremy L Thompson qdata[i + q * 2] = -qw * (j11 * j12 + j21 * j22); 165*3eb59678SJeremy L Thompson } 166*3eb59678SJeremy L Thompson } 167*3eb59678SJeremy L Thompson 3 => { 168*3eb59678SJeremy L Thompson let q = qdata.len() / 6; 169*3eb59678SJeremy L Thompson for i in 0..q { 170*3eb59678SJeremy L Thompson let mut a = [0.0; 9]; 171*3eb59678SJeremy L Thompson for j in 0..3 { 172*3eb59678SJeremy L Thompson for k in 0..3 { 173*3eb59678SJeremy L Thompson a[k * 3 + j] = jacobian[i + q * ((j + 1) % 3 + 3 * ((k + 1) % 3))] 174*3eb59678SJeremy L Thompson * jacobian[i + q * ((j + 2) % 3 + 3 * ((k + 2) % 3))] 175*3eb59678SJeremy L Thompson - jacobian[i + q * ((j + 1) % 3 + 3 * ((k + 2) % 3))] 176*3eb59678SJeremy L Thompson * jacobian[i + q * ((j + 2) % 3 + 3 * ((k + 1) % 3))]; 177*3eb59678SJeremy L Thompson } 178*3eb59678SJeremy L Thompson } 179*3eb59678SJeremy L Thompson let qw = weights[i] 180*3eb59678SJeremy L Thompson / (jacobian[i + q * 0] * a[0 * 3 + 0] 181*3eb59678SJeremy L Thompson + jacobian[i + q * 1] * a[0 * 3 + 1] 182*3eb59678SJeremy L Thompson + jacobian[i + q * 2] * a[0 * 3 + 2]); 183*3eb59678SJeremy L Thompson qdata[i + q * 0] = qw 184*3eb59678SJeremy L Thompson * (a[0 * 3 + 0] * a[0 * 3 + 0] 185*3eb59678SJeremy L Thompson + a[0 * 3 + 1] * a[0 * 3 + 1] 186*3eb59678SJeremy L Thompson + a[0 * 3 + 2] * a[0 * 3 + 2]); 187*3eb59678SJeremy L Thompson qdata[i + q * 1] = qw 188*3eb59678SJeremy L Thompson * (a[1 * 3 + 0] * a[1 * 3 + 0] 189*3eb59678SJeremy L Thompson + a[1 * 3 + 1] * a[1 * 3 + 1] 190*3eb59678SJeremy L Thompson + a[1 * 3 + 2] * a[1 * 3 + 2]); 191*3eb59678SJeremy L Thompson qdata[i + q * 2] = qw 192*3eb59678SJeremy L Thompson * (a[2 * 3 + 0] * a[2 * 3 + 0] 193*3eb59678SJeremy L Thompson + a[2 * 3 + 1] * a[2 * 3 + 1] 194*3eb59678SJeremy L Thompson + a[2 * 3 + 2] * a[2 * 3 + 2]); 195*3eb59678SJeremy L Thompson qdata[i + q * 3] = qw 196*3eb59678SJeremy L Thompson * (a[1 * 3 + 0] * a[2 * 3 + 0] 197*3eb59678SJeremy L Thompson + a[1 * 3 + 1] * a[2 * 3 + 1] 198*3eb59678SJeremy L Thompson + a[1 * 3 + 2] * a[2 * 3 + 2]); 199*3eb59678SJeremy L Thompson qdata[i + q * 4] = qw 200*3eb59678SJeremy L Thompson * (a[0 * 3 + 0] * a[2 * 3 + 0] 201*3eb59678SJeremy L Thompson + a[0 * 3 + 1] * a[2 * 3 + 1] 202*3eb59678SJeremy L Thompson + a[0 * 3 + 2] * a[2 * 3 + 2]); 203*3eb59678SJeremy L Thompson qdata[i + q * 5] = qw 204*3eb59678SJeremy L Thompson * (a[0 * 3 + 0] * a[1 * 3 + 0] 205*3eb59678SJeremy L Thompson + a[0 * 3 + 1] * a[1 * 3 + 1] 206*3eb59678SJeremy L Thompson + a[0 * 3 + 2] * a[1 * 3 + 2]); 207*3eb59678SJeremy L Thompson } 208*3eb59678SJeremy L Thompson } 209*3eb59678SJeremy L Thompson _ => unreachable!(), 210*3eb59678SJeremy L Thompson }; 211*3eb59678SJeremy L Thompson 212*3eb59678SJeremy L Thompson // Return clean error code 213*3eb59678SJeremy L Thompson 0 214*3eb59678SJeremy L Thompson }; 215*3eb59678SJeremy L Thompson let qf_build_closure = ceed 216*3eb59678SJeremy L Thompson .q_function_interior(1, Box::new(build_diff))? 217*3eb59678SJeremy L Thompson .input("dx", ncomp_x * dim, libceed::EvalMode::Grad)? 218*3eb59678SJeremy L Thompson .input("weights", 1, libceed::EvalMode::Weight)? 219*3eb59678SJeremy L Thompson .output("qdata", dim * (dim + 1) / 2, libceed::EvalMode::None)?; 220*3eb59678SJeremy L Thompson // -- QFunction from gallery 221*3eb59678SJeremy L Thompson let qf_build_named = { 222*3eb59678SJeremy L Thompson let name = format!("Poisson{}DBuild", dim); 223*3eb59678SJeremy L Thompson ceed.q_function_interior_by_name(&name)? 224*3eb59678SJeremy L Thompson }; 225*3eb59678SJeremy L Thompson // -- QFunction for use with Operator 226*3eb59678SJeremy L Thompson let qf_build = if gallery { 227*3eb59678SJeremy L Thompson QFunctionOpt::SomeQFunctionByName(&qf_build_named) 228*3eb59678SJeremy L Thompson } else { 229*3eb59678SJeremy L Thompson QFunctionOpt::SomeQFunction(&qf_build_closure) 230*3eb59678SJeremy L Thompson }; 231*3eb59678SJeremy L Thompson 232*3eb59678SJeremy L Thompson // Operator that build the quadrature data for the diff operator 233*3eb59678SJeremy L Thompson let op_build = ceed 234*3eb59678SJeremy L Thompson .operator(qf_build, QFunctionOpt::None, QFunctionOpt::None)? 235*3eb59678SJeremy L Thompson .name("build qdata")? 236*3eb59678SJeremy L Thompson .field("dx", &rstr_mesh, &basis_mesh, VectorOpt::Active)? 237*3eb59678SJeremy L Thompson .field( 238*3eb59678SJeremy L Thompson "weights", 239*3eb59678SJeremy L Thompson ElemRestrictionOpt::None, 240*3eb59678SJeremy L Thompson &basis_mesh, 241*3eb59678SJeremy L Thompson VectorOpt::None, 242*3eb59678SJeremy L Thompson )? 243*3eb59678SJeremy L Thompson .field("qdata", &rstr_qdata, BasisOpt::None, VectorOpt::Active)? 244*3eb59678SJeremy L Thompson .check()?; 245*3eb59678SJeremy L Thompson 246*3eb59678SJeremy L Thompson // Compute the quadrature data for the diff operator 247*3eb59678SJeremy L Thompson let elem_qpts = num_qpts.pow(dim as u32); 248*3eb59678SJeremy L Thompson let num_elem: usize = num_xyz.iter().take(dim).product(); 249*3eb59678SJeremy L Thompson let mut qdata = ceed.vector(num_elem * elem_qpts * dim * (dim + 1) / 2)?; 250*3eb59678SJeremy L Thompson op_build.apply(&mesh_coords, &mut qdata)?; 251*3eb59678SJeremy L Thompson 252*3eb59678SJeremy L Thompson // QFunction that applies the diff operator 253*3eb59678SJeremy L Thompson // -- QFunction from user closure 254*3eb59678SJeremy L Thompson let apply_diff = move |[ug, qdata, ..]: QFunctionInputs, [vg, ..]: QFunctionOutputs| { 255*3eb59678SJeremy L Thompson // Apply diffusion operator 256*3eb59678SJeremy L Thompson match dim { 257*3eb59678SJeremy L Thompson 1 => { 258*3eb59678SJeremy L Thompson let q = qdata.len(); 259*3eb59678SJeremy L Thompson for c in 0..ncomp_u { 260*3eb59678SJeremy L Thompson vg.iter_mut() 261*3eb59678SJeremy L Thompson .skip(c * q) 262*3eb59678SJeremy L Thompson .zip(ug.iter().skip(c * q).zip(qdata.iter())) 263*3eb59678SJeremy L Thompson .for_each(|(vg, (ug, w))| *vg = ug * w) 264*3eb59678SJeremy L Thompson } 265*3eb59678SJeremy L Thompson } 266*3eb59678SJeremy L Thompson 2 => { 267*3eb59678SJeremy L Thompson let q = qdata.len() / 3; 268*3eb59678SJeremy L Thompson for i in 0..q { 269*3eb59678SJeremy L Thompson let dxdxdxdx_t = [ 270*3eb59678SJeremy L Thompson [qdata[i + 0 * q], qdata[i + 2 * q]], 271*3eb59678SJeremy L Thompson [qdata[i + 2 * q], qdata[i + 1 * q]], 272*3eb59678SJeremy L Thompson ]; 273*3eb59678SJeremy L Thompson for c in 0..ncomp_u { 274*3eb59678SJeremy L Thompson let du = [ug[i + (c + 0 * ncomp_u) * q], ug[i + (c + 1 * ncomp_u) * q]]; 275*3eb59678SJeremy L Thompson for j in 0..dim { 276*3eb59678SJeremy L Thompson vg[i + (c + j * ncomp_u) * q] = 277*3eb59678SJeremy L Thompson du[0] * dxdxdxdx_t[0][j] + du[1] * dxdxdxdx_t[1][j]; 278*3eb59678SJeremy L Thompson } 279*3eb59678SJeremy L Thompson } 280*3eb59678SJeremy L Thompson } 281*3eb59678SJeremy L Thompson } 282*3eb59678SJeremy L Thompson 3 => { 283*3eb59678SJeremy L Thompson let q = qdata.len() / 6; 284*3eb59678SJeremy L Thompson for i in 0..q { 285*3eb59678SJeremy L Thompson let dxdxdxdx_t = [ 286*3eb59678SJeremy L Thompson [qdata[i + 0 * q], qdata[i + 5 * q], qdata[i + 4 * q]], 287*3eb59678SJeremy L Thompson [qdata[i + 5 * q], qdata[i + 1 * q], qdata[i + 3 * q]], 288*3eb59678SJeremy L Thompson [qdata[i + 4 * q], qdata[i + 3 * q], qdata[i + 2 * q]], 289*3eb59678SJeremy L Thompson ]; 290*3eb59678SJeremy L Thompson for c in 0..ncomp_u { 291*3eb59678SJeremy L Thompson let du = [ 292*3eb59678SJeremy L Thompson ug[i + (c + 0 * ncomp_u) * q], 293*3eb59678SJeremy L Thompson ug[i + (c + 1 * ncomp_u) * q], 294*3eb59678SJeremy L Thompson ug[i + (c + 2 * ncomp_u) * q], 295*3eb59678SJeremy L Thompson ]; 296*3eb59678SJeremy L Thompson for j in 0..dim { 297*3eb59678SJeremy L Thompson vg[i + (c + j * ncomp_u) * q] = du[0] * dxdxdxdx_t[0][j] 298*3eb59678SJeremy L Thompson + du[1] * dxdxdxdx_t[1][j] 299*3eb59678SJeremy L Thompson + du[2] * dxdxdxdx_t[2][j]; 300*3eb59678SJeremy L Thompson } 301*3eb59678SJeremy L Thompson } 302*3eb59678SJeremy L Thompson } 303*3eb59678SJeremy L Thompson } 304*3eb59678SJeremy L Thompson _ => unreachable!(), 305*3eb59678SJeremy L Thompson }; 306*3eb59678SJeremy L Thompson 307*3eb59678SJeremy L Thompson // Return clean error code 308*3eb59678SJeremy L Thompson 0 309*3eb59678SJeremy L Thompson }; 310*3eb59678SJeremy L Thompson let qf_diff_closure = ceed 311*3eb59678SJeremy L Thompson .q_function_interior(1, Box::new(apply_diff))? 312*3eb59678SJeremy L Thompson .input("du", dim * ncomp_u, libceed::EvalMode::Grad)? 313*3eb59678SJeremy L Thompson .input("qdata", dim * (dim + 1) / 2, libceed::EvalMode::None)? 314*3eb59678SJeremy L Thompson .output("dv", dim * ncomp_u, libceed::EvalMode::Grad)?; 315*3eb59678SJeremy L Thompson // -- QFunction from gallery 316*3eb59678SJeremy L Thompson let qf_diff_named = { 317*3eb59678SJeremy L Thompson let name = format!("Vector3Poisson{}DApply", dim); 318*3eb59678SJeremy L Thompson ceed.q_function_interior_by_name(&name)? 319*3eb59678SJeremy L Thompson }; 320*3eb59678SJeremy L Thompson // -- QFunction for use with Operator 321*3eb59678SJeremy L Thompson let qf_diff = if gallery { 322*3eb59678SJeremy L Thompson QFunctionOpt::SomeQFunctionByName(&qf_diff_named) 323*3eb59678SJeremy L Thompson } else { 324*3eb59678SJeremy L Thompson QFunctionOpt::SomeQFunction(&qf_diff_closure) 325*3eb59678SJeremy L Thompson }; 326*3eb59678SJeremy L Thompson 327*3eb59678SJeremy L Thompson // Diff Operator 328*3eb59678SJeremy L Thompson let op_diff = ceed 329*3eb59678SJeremy L Thompson .operator(qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 330*3eb59678SJeremy L Thompson .name("Poisson")? 331*3eb59678SJeremy L Thompson .field("du", &rstr_solution, &basis_solution, VectorOpt::Active)? 332*3eb59678SJeremy L Thompson .field("qdata", &rstr_qdata, BasisOpt::None, &qdata)? 333*3eb59678SJeremy L Thompson .field("dv", &rstr_solution, &basis_solution, VectorOpt::Active)? 334*3eb59678SJeremy L Thompson .check()?; 335*3eb59678SJeremy L Thompson 336*3eb59678SJeremy L Thompson // Solution vectors 337*3eb59678SJeremy L Thompson let mut u = ceed.vector(solution_size)?; 338*3eb59678SJeremy L Thompson let mut v = ceed.vector(solution_size)?; 339*3eb59678SJeremy L Thompson 340*3eb59678SJeremy L Thompson // Initialize u with sum of node coordinates 341*3eb59678SJeremy L Thompson let coords = mesh_coords.view()?; 342*3eb59678SJeremy L Thompson u.set_value(0.0)?; 343*3eb59678SJeremy L Thompson for c in 0..ncomp_u { 344*3eb59678SJeremy L Thompson let q = solution_size / ncomp_u; 345*3eb59678SJeremy L Thompson u.view_mut()? 346*3eb59678SJeremy L Thompson .iter_mut() 347*3eb59678SJeremy L Thompson .skip(c * q) 348*3eb59678SJeremy L Thompson .take(q) 349*3eb59678SJeremy L Thompson .enumerate() 350*3eb59678SJeremy L Thompson .for_each(|(i, u)| { 351*3eb59678SJeremy L Thompson *u = (0..dim).map(|d| coords[i + d * q]).sum::<libceed::Scalar>() 352*3eb59678SJeremy L Thompson * (c + 1) as libceed::Scalar; 353*3eb59678SJeremy L Thompson }); 354*3eb59678SJeremy L Thompson } 355*3eb59678SJeremy L Thompson 356*3eb59678SJeremy L Thompson // Apply the diff operator 357*3eb59678SJeremy L Thompson op_diff.apply(&u, &mut v)?; 358*3eb59678SJeremy L Thompson 359*3eb59678SJeremy L Thompson // Compute the mesh surface area 360*3eb59678SJeremy L Thompson let area: libceed::Scalar = v 361*3eb59678SJeremy L Thompson .view()? 362*3eb59678SJeremy L Thompson .iter() 363*3eb59678SJeremy L Thompson .map(|v| (*v).abs()) 364*3eb59678SJeremy L Thompson .sum::<libceed::Scalar>() 365*3eb59678SJeremy L Thompson / ((ncomp_u * (ncomp_u + 1)) / 2) as libceed::Scalar; 366*3eb59678SJeremy L Thompson 367*3eb59678SJeremy L Thompson // Output results 368*3eb59678SJeremy L Thompson if !quiet { 369*3eb59678SJeremy L Thompson println!("Exact mesh surface area : {:.12}", exact_area); 370*3eb59678SJeremy L Thompson println!("Computed mesh surface_area : {:.12}", area); 371*3eb59678SJeremy L Thompson println!("Surface area error : {:.12e}", area - exact_area); 372*3eb59678SJeremy L Thompson } 373*3eb59678SJeremy L Thompson let tolerance = match dim { 374*3eb59678SJeremy L Thompson 1 => 1E-5, 375*3eb59678SJeremy L Thompson _ => 1E-1, 376*3eb59678SJeremy L Thompson }; 377*3eb59678SJeremy L Thompson let error = (area - exact_area).abs(); 378*3eb59678SJeremy L Thompson if error > tolerance { 379*3eb59678SJeremy L Thompson println!("Volume error too large: {:.12e}", error); 380*3eb59678SJeremy L Thompson return Err(libceed::Error { 381*3eb59678SJeremy L Thompson message: format!( 382*3eb59678SJeremy L Thompson "Volume error too large - expected: {:.12e}, actual: {:.12e}", 383*3eb59678SJeremy L Thompson tolerance, error 384*3eb59678SJeremy L Thompson ), 385*3eb59678SJeremy L Thompson }); 386*3eb59678SJeremy L Thompson } 387*3eb59678SJeremy L Thompson Ok(()) 388*3eb59678SJeremy L Thompson } 389*3eb59678SJeremy L Thompson 390*3eb59678SJeremy L Thompson // ---------------------------------------------------------------------------- 391*3eb59678SJeremy L Thompson // Tests 392*3eb59678SJeremy L Thompson // ---------------------------------------------------------------------------- 393*3eb59678SJeremy L Thompson #[cfg(test)] 394*3eb59678SJeremy L Thompson mod tests { 395*3eb59678SJeremy L Thompson use super::*; 396*3eb59678SJeremy L Thompson 397*3eb59678SJeremy L Thompson #[test] 398*3eb59678SJeremy L Thompson fn example_2_vector_1d() { 399*3eb59678SJeremy L Thompson let options = opt::Opt { 400*3eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 401*3eb59678SJeremy L Thompson dim: 1, 402*3eb59678SJeremy L Thompson mesh_degree: 4, 403*3eb59678SJeremy L Thompson solution_degree: 4, 404*3eb59678SJeremy L Thompson num_qpts: 6, 405*3eb59678SJeremy L Thompson problem_size_requested: -1, 406*3eb59678SJeremy L Thompson test: true, 407*3eb59678SJeremy L Thompson quiet: true, 408*3eb59678SJeremy L Thompson gallery: false, 409*3eb59678SJeremy L Thompson }; 410*3eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 411*3eb59678SJeremy L Thompson } 412*3eb59678SJeremy L Thompson 413*3eb59678SJeremy L Thompson #[test] 414*3eb59678SJeremy L Thompson fn example_2_vector_2d() { 415*3eb59678SJeremy L Thompson let options = opt::Opt { 416*3eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 417*3eb59678SJeremy L Thompson dim: 2, 418*3eb59678SJeremy L Thompson mesh_degree: 4, 419*3eb59678SJeremy L Thompson solution_degree: 4, 420*3eb59678SJeremy L Thompson num_qpts: 6, 421*3eb59678SJeremy L Thompson problem_size_requested: -1, 422*3eb59678SJeremy L Thompson test: true, 423*3eb59678SJeremy L Thompson quiet: true, 424*3eb59678SJeremy L Thompson gallery: false, 425*3eb59678SJeremy L Thompson }; 426*3eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 427*3eb59678SJeremy L Thompson } 428*3eb59678SJeremy L Thompson 429*3eb59678SJeremy L Thompson #[test] 430*3eb59678SJeremy L Thompson fn example_2_vector_3d() { 431*3eb59678SJeremy L Thompson let options = opt::Opt { 432*3eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 433*3eb59678SJeremy L Thompson dim: 3, 434*3eb59678SJeremy L Thompson mesh_degree: 4, 435*3eb59678SJeremy L Thompson solution_degree: 4, 436*3eb59678SJeremy L Thompson num_qpts: 6, 437*3eb59678SJeremy L Thompson problem_size_requested: -1, 438*3eb59678SJeremy L Thompson test: true, 439*3eb59678SJeremy L Thompson quiet: false, 440*3eb59678SJeremy L Thompson gallery: false, 441*3eb59678SJeremy L Thompson }; 442*3eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 443*3eb59678SJeremy L Thompson } 444*3eb59678SJeremy L Thompson 445*3eb59678SJeremy L Thompson #[test] 446*3eb59678SJeremy L Thompson fn example_2_vector_1d_gallery() { 447*3eb59678SJeremy L Thompson let options = opt::Opt { 448*3eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 449*3eb59678SJeremy L Thompson dim: 1, 450*3eb59678SJeremy L Thompson mesh_degree: 4, 451*3eb59678SJeremy L Thompson solution_degree: 4, 452*3eb59678SJeremy L Thompson num_qpts: 6, 453*3eb59678SJeremy L Thompson problem_size_requested: -1, 454*3eb59678SJeremy L Thompson test: true, 455*3eb59678SJeremy L Thompson quiet: true, 456*3eb59678SJeremy L Thompson gallery: true, 457*3eb59678SJeremy L Thompson }; 458*3eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 459*3eb59678SJeremy L Thompson } 460*3eb59678SJeremy L Thompson 461*3eb59678SJeremy L Thompson #[test] 462*3eb59678SJeremy L Thompson fn example_2_vector_2d_gallery() { 463*3eb59678SJeremy L Thompson let options = opt::Opt { 464*3eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 465*3eb59678SJeremy L Thompson dim: 2, 466*3eb59678SJeremy L Thompson mesh_degree: 4, 467*3eb59678SJeremy L Thompson solution_degree: 4, 468*3eb59678SJeremy L Thompson num_qpts: 6, 469*3eb59678SJeremy L Thompson problem_size_requested: -1, 470*3eb59678SJeremy L Thompson test: true, 471*3eb59678SJeremy L Thompson quiet: true, 472*3eb59678SJeremy L Thompson gallery: true, 473*3eb59678SJeremy L Thompson }; 474*3eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 475*3eb59678SJeremy L Thompson } 476*3eb59678SJeremy L Thompson 477*3eb59678SJeremy L Thompson #[test] 478*3eb59678SJeremy L Thompson fn example_2_vector_3d_gallery() { 479*3eb59678SJeremy L Thompson let options = opt::Opt { 480*3eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 481*3eb59678SJeremy L Thompson dim: 3, 482*3eb59678SJeremy L Thompson mesh_degree: 4, 483*3eb59678SJeremy L Thompson solution_degree: 4, 484*3eb59678SJeremy L Thompson num_qpts: 6, 485*3eb59678SJeremy L Thompson problem_size_requested: -1, 486*3eb59678SJeremy L Thompson test: true, 487*3eb59678SJeremy L Thompson quiet: true, 488*3eb59678SJeremy L Thompson gallery: true, 489*3eb59678SJeremy L Thompson }; 490*3eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 491*3eb59678SJeremy L Thompson } 492*3eb59678SJeremy L Thompson } 493*3eb59678SJeremy L Thompson 494*3eb59678SJeremy L Thompson // ---------------------------------------------------------------------------- 495