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