1*9ba83ac0SJeremy L Thompson // Copyright (c) 2017-2026, Lawrence Livermore National Security, LLC and other CEED contributors. 23eb59678SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 33eb59678SJeremy L Thompson // 43eb59678SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 53eb59678SJeremy L Thompson // 63eb59678SJeremy L Thompson // This file is part of CEED: http://github.com/ceed 73eb59678SJeremy L Thompson // 83eb59678SJeremy L Thompson // libCEED Example 4 93eb59678SJeremy L Thompson // 103eb59678SJeremy L Thompson // This example illustrates a simple usage of libCEED to compute the surface 113eb59678SJeremy L Thompson // area of a 3D body using matrix-free application of a diffusion operator. 123eb59678SJeremy L Thompson // Arbitrary mesh and solution degrees in 1D, 2D and 3D are supported from the 133eb59678SJeremy L Thompson // same code. This calculation is executed in triplicate with a 3 component 143eb59678SJeremy L Thompson // vector system. 153eb59678SJeremy L Thompson // 163eb59678SJeremy L Thompson // The example has no dependencies, and is designed to be self-contained. For 173eb59678SJeremy L Thompson // additional examples that use external discretization libraries (MFEM, PETSc, 183eb59678SJeremy L Thompson // etc.) see the subdirectories in libceed/examples. 193eb59678SJeremy L Thompson // 203eb59678SJeremy L Thompson // All libCEED objects use a Ceed device object constructed based on a command 213eb59678SJeremy L Thompson // line argument (-ceed). 223eb59678SJeremy L Thompson 233eb59678SJeremy L Thompson use clap::Parser; 243eb59678SJeremy L Thompson use libceed::{ 253eb59678SJeremy L Thompson BasisOpt, Ceed, ElemRestrictionOpt, QFunctionInputs, QFunctionOpt, QFunctionOutputs, VectorOpt, 263eb59678SJeremy L Thompson }; 273eb59678SJeremy L Thompson mod opt; 283eb59678SJeremy L Thompson mod transform; 293eb59678SJeremy L Thompson 303eb59678SJeremy L Thompson // ---------------------------------------------------------------------------- 313eb59678SJeremy L Thompson // Example 4 323eb59678SJeremy L Thompson // ---------------------------------------------------------------------------- 333eb59678SJeremy L Thompson fn main() -> libceed::Result<()> { 343eb59678SJeremy L Thompson let options = opt::Opt::parse(); 353eb59678SJeremy L Thompson example_2_vector(options) 363eb59678SJeremy L Thompson } 373eb59678SJeremy L Thompson 383eb59678SJeremy L Thompson #[allow(clippy::erasing_op)] 393eb59678SJeremy L Thompson #[allow(clippy::identity_op)] 403eb59678SJeremy L Thompson fn example_2_vector(options: opt::Opt) -> libceed::Result<()> { 413eb59678SJeremy L Thompson // Process command line arguments 423eb59678SJeremy L Thompson let opt::Opt { 433eb59678SJeremy L Thompson ceed_spec, 443eb59678SJeremy L Thompson dim, 453eb59678SJeremy L Thompson mesh_degree, 463eb59678SJeremy L Thompson solution_degree, 473eb59678SJeremy L Thompson num_qpts, 483eb59678SJeremy L Thompson problem_size_requested, 493eb59678SJeremy L Thompson test, 503eb59678SJeremy L Thompson quiet, 513eb59678SJeremy L Thompson gallery, 523eb59678SJeremy L Thompson } = options; 533eb59678SJeremy L Thompson assert!((0..=3).contains(&dim)); 543eb59678SJeremy L Thompson assert!(mesh_degree >= 1); 553eb59678SJeremy L Thompson assert!(solution_degree >= 1); 563eb59678SJeremy L Thompson assert!(num_qpts >= 1); 573eb59678SJeremy L Thompson let ncomp_x = dim; 583eb59678SJeremy L Thompson let problem_size: i64 = if problem_size_requested < 0 { 593eb59678SJeremy L Thompson if test { 603eb59678SJeremy L Thompson 16 * 16 * (dim * dim) as i64 613eb59678SJeremy L Thompson } else { 623eb59678SJeremy L Thompson 256 * 1024 633eb59678SJeremy L Thompson } 643eb59678SJeremy L Thompson } else { 653eb59678SJeremy L Thompson problem_size_requested 663eb59678SJeremy L Thompson }; 673eb59678SJeremy L Thompson let ncomp_u = 3; 683eb59678SJeremy L Thompson 693eb59678SJeremy L Thompson // Summary output 703eb59678SJeremy L Thompson if !quiet { 713eb59678SJeremy L Thompson println!("Selected options: [command line option] : <current value>"); 723eb59678SJeremy L Thompson println!(" Ceed specification [-c] : {}", ceed_spec); 733eb59678SJeremy L Thompson println!(" Mesh dimension [-d] : {}", dim); 743eb59678SJeremy L Thompson println!(" Mesh degree [-m] : {}", mesh_degree); 753eb59678SJeremy L Thompson println!(" Solution degree [-p] : {}", solution_degree); 763eb59678SJeremy L Thompson println!(" Num. 1D quadr. pts [-q] : {}", num_qpts); 773eb59678SJeremy L Thompson println!(" Approx. # unknowns [-s] : {}", problem_size); 783eb59678SJeremy L Thompson println!( 793eb59678SJeremy L Thompson " QFunction source [-g] : {}", 803eb59678SJeremy L Thompson if gallery { "gallery" } else { "user closure" } 813eb59678SJeremy L Thompson ); 823eb59678SJeremy L Thompson } 833eb59678SJeremy L Thompson 843eb59678SJeremy L Thompson // Initalize ceed context 853eb59678SJeremy L Thompson let ceed = Ceed::init(&ceed_spec); 863eb59678SJeremy L Thompson 873eb59678SJeremy L Thompson // Mesh and solution bases 883eb59678SJeremy L Thompson let basis_mesh = ceed.basis_tensor_H1_Lagrange( 893eb59678SJeremy L Thompson dim, 903eb59678SJeremy L Thompson ncomp_x, 913eb59678SJeremy L Thompson mesh_degree + 1, 923eb59678SJeremy L Thompson num_qpts, 933eb59678SJeremy L Thompson libceed::QuadMode::Gauss, 943eb59678SJeremy L Thompson )?; 953eb59678SJeremy L Thompson let basis_solution = ceed.basis_tensor_H1_Lagrange( 963eb59678SJeremy L Thompson dim, 973eb59678SJeremy L Thompson ncomp_u, 983eb59678SJeremy L Thompson solution_degree + 1, 993eb59678SJeremy L Thompson num_qpts, 1003eb59678SJeremy L Thompson libceed::QuadMode::Gauss, 1013eb59678SJeremy L Thompson )?; 1023eb59678SJeremy L Thompson 1033eb59678SJeremy L Thompson // Determine mesh size from approximate problem size 1043eb59678SJeremy L Thompson let num_xyz = mesh::cartesian_mesh_size(dim, solution_degree, problem_size); 1053eb59678SJeremy L Thompson if !quiet { 1063eb59678SJeremy L Thompson print!("\nMesh size : nx = {}", num_xyz[0]); 1073eb59678SJeremy L Thompson if dim > 1 { 1083eb59678SJeremy L Thompson print!(", ny = {}", num_xyz[1]); 1093eb59678SJeremy L Thompson } 1103eb59678SJeremy L Thompson if dim > 2 { 1113eb59678SJeremy L Thompson print!(", nz = {}", num_xyz[2]); 1123eb59678SJeremy L Thompson } 1133eb59678SJeremy L Thompson println!(); 1143eb59678SJeremy L Thompson } 1153eb59678SJeremy L Thompson 1163eb59678SJeremy L Thompson // Build ElemRestriction objects describing the mesh and solution discrete 1173eb59678SJeremy L Thompson // representations 1183eb59678SJeremy L Thompson let (rstr_mesh, _) = 1193eb59678SJeremy L Thompson mesh::build_cartesian_restriction(&ceed, dim, num_xyz, mesh_degree, ncomp_x, num_qpts)?; 1203eb59678SJeremy L Thompson let (_, rstr_qdata) = mesh::build_cartesian_restriction( 1213eb59678SJeremy L Thompson &ceed, 1223eb59678SJeremy L Thompson dim, 1233eb59678SJeremy L Thompson num_xyz, 1243eb59678SJeremy L Thompson solution_degree, 1253eb59678SJeremy L Thompson dim * (dim + 1) / 2, 1263eb59678SJeremy L Thompson num_qpts, 1273eb59678SJeremy L Thompson )?; 1283eb59678SJeremy L Thompson 1293eb59678SJeremy L Thompson let (rstr_solution, _) = 1303eb59678SJeremy L Thompson mesh::build_cartesian_restriction(&ceed, dim, num_xyz, solution_degree, ncomp_u, num_qpts)?; 1313eb59678SJeremy L Thompson let mesh_size = rstr_mesh.lvector_size(); 1323eb59678SJeremy L Thompson let solution_size = rstr_solution.lvector_size(); 1333eb59678SJeremy L Thompson if !quiet { 1343eb59678SJeremy L Thompson println!("Number of mesh nodes : {}", mesh_size / dim); 1353eb59678SJeremy L Thompson println!("Number of solution nodes : {}", solution_size); 1363eb59678SJeremy L Thompson } 1373eb59678SJeremy L Thompson 1383eb59678SJeremy L Thompson // Create a Vector with the mesh coordinates 1393eb59678SJeremy L Thompson let mut mesh_coords = mesh::cartesian_mesh_coords(&ceed, dim, num_xyz, mesh_degree, mesh_size)?; 1403eb59678SJeremy L Thompson 1413eb59678SJeremy L Thompson // Apply a transformation to the mesh coordinates 1423eb59678SJeremy L Thompson let exact_area = transform::transform_mesh_coordinates(dim, &mut mesh_coords)?; 1433eb59678SJeremy L Thompson 1443eb59678SJeremy L Thompson // QFunction that builds the quadrature data for the diff operator 1453eb59678SJeremy L Thompson // -- QFunction from user closure 1463eb59678SJeremy L Thompson let build_diff = move |[jacobian, weights, ..]: QFunctionInputs, 1473eb59678SJeremy L Thompson [qdata, ..]: QFunctionOutputs| { 1483eb59678SJeremy L Thompson // Build quadrature data 1493eb59678SJeremy L Thompson match dim { 1503eb59678SJeremy L Thompson 1 => qdata 1513eb59678SJeremy L Thompson .iter_mut() 1523eb59678SJeremy L Thompson .zip(jacobian.iter().zip(weights.iter())) 1533eb59678SJeremy L Thompson .for_each(|(qdata, (j, weight))| *qdata = weight / j), 1543eb59678SJeremy L Thompson 2 => { 1553eb59678SJeremy L Thompson let q = qdata.len() / 3; 1563eb59678SJeremy L Thompson for i in 0..q { 1573eb59678SJeremy L Thompson let j11 = jacobian[i + q * 0]; 1583eb59678SJeremy L Thompson let j21 = jacobian[i + q * 1]; 1593eb59678SJeremy L Thompson let j12 = jacobian[i + q * 2]; 1603eb59678SJeremy L Thompson let j22 = jacobian[i + q * 3]; 1613eb59678SJeremy L Thompson let qw = weights[i] / (j11 * j22 - j21 * j12); 1623eb59678SJeremy L Thompson qdata[i + q * 0] = qw * (j12 * j12 + j22 * j22); 1633eb59678SJeremy L Thompson qdata[i + q * 1] = qw * (j11 * j11 + j21 * j21); 1643eb59678SJeremy L Thompson qdata[i + q * 2] = -qw * (j11 * j12 + j21 * j22); 1653eb59678SJeremy L Thompson } 1663eb59678SJeremy L Thompson } 1673eb59678SJeremy L Thompson 3 => { 1683eb59678SJeremy L Thompson let q = qdata.len() / 6; 1693eb59678SJeremy L Thompson for i in 0..q { 1703eb59678SJeremy L Thompson let mut a = [0.0; 9]; 1713eb59678SJeremy L Thompson for j in 0..3 { 1723eb59678SJeremy L Thompson for k in 0..3 { 1733eb59678SJeremy L Thompson a[k * 3 + j] = jacobian[i + q * ((j + 1) % 3 + 3 * ((k + 1) % 3))] 1743eb59678SJeremy L Thompson * jacobian[i + q * ((j + 2) % 3 + 3 * ((k + 2) % 3))] 1753eb59678SJeremy L Thompson - jacobian[i + q * ((j + 1) % 3 + 3 * ((k + 2) % 3))] 1763eb59678SJeremy L Thompson * jacobian[i + q * ((j + 2) % 3 + 3 * ((k + 1) % 3))]; 1773eb59678SJeremy L Thompson } 1783eb59678SJeremy L Thompson } 1793eb59678SJeremy L Thompson let qw = weights[i] 1803eb59678SJeremy L Thompson / (jacobian[i + q * 0] * a[0 * 3 + 0] 1813eb59678SJeremy L Thompson + jacobian[i + q * 1] * a[0 * 3 + 1] 1823eb59678SJeremy L Thompson + jacobian[i + q * 2] * a[0 * 3 + 2]); 1833eb59678SJeremy L Thompson qdata[i + q * 0] = qw 1843eb59678SJeremy L Thompson * (a[0 * 3 + 0] * a[0 * 3 + 0] 1853eb59678SJeremy L Thompson + a[0 * 3 + 1] * a[0 * 3 + 1] 1863eb59678SJeremy L Thompson + a[0 * 3 + 2] * a[0 * 3 + 2]); 1873eb59678SJeremy L Thompson qdata[i + q * 1] = qw 1883eb59678SJeremy L Thompson * (a[1 * 3 + 0] * a[1 * 3 + 0] 1893eb59678SJeremy L Thompson + a[1 * 3 + 1] * a[1 * 3 + 1] 1903eb59678SJeremy L Thompson + a[1 * 3 + 2] * a[1 * 3 + 2]); 1913eb59678SJeremy L Thompson qdata[i + q * 2] = qw 1923eb59678SJeremy L Thompson * (a[2 * 3 + 0] * a[2 * 3 + 0] 1933eb59678SJeremy L Thompson + a[2 * 3 + 1] * a[2 * 3 + 1] 1943eb59678SJeremy L Thompson + a[2 * 3 + 2] * a[2 * 3 + 2]); 1953eb59678SJeremy L Thompson qdata[i + q * 3] = qw 1963eb59678SJeremy L Thompson * (a[1 * 3 + 0] * a[2 * 3 + 0] 1973eb59678SJeremy L Thompson + a[1 * 3 + 1] * a[2 * 3 + 1] 1983eb59678SJeremy L Thompson + a[1 * 3 + 2] * a[2 * 3 + 2]); 1993eb59678SJeremy L Thompson qdata[i + q * 4] = qw 2003eb59678SJeremy L Thompson * (a[0 * 3 + 0] * a[2 * 3 + 0] 2013eb59678SJeremy L Thompson + a[0 * 3 + 1] * a[2 * 3 + 1] 2023eb59678SJeremy L Thompson + a[0 * 3 + 2] * a[2 * 3 + 2]); 2033eb59678SJeremy L Thompson qdata[i + q * 5] = qw 2043eb59678SJeremy L Thompson * (a[0 * 3 + 0] * a[1 * 3 + 0] 2053eb59678SJeremy L Thompson + a[0 * 3 + 1] * a[1 * 3 + 1] 2063eb59678SJeremy L Thompson + a[0 * 3 + 2] * a[1 * 3 + 2]); 2073eb59678SJeremy L Thompson } 2083eb59678SJeremy L Thompson } 2093eb59678SJeremy L Thompson _ => unreachable!(), 2103eb59678SJeremy L Thompson }; 2113eb59678SJeremy L Thompson 2123eb59678SJeremy L Thompson // Return clean error code 2133eb59678SJeremy L Thompson 0 2143eb59678SJeremy L Thompson }; 2153eb59678SJeremy L Thompson let qf_build_closure = ceed 2163eb59678SJeremy L Thompson .q_function_interior(1, Box::new(build_diff))? 2173eb59678SJeremy L Thompson .input("dx", ncomp_x * dim, libceed::EvalMode::Grad)? 2183eb59678SJeremy L Thompson .input("weights", 1, libceed::EvalMode::Weight)? 2193eb59678SJeremy L Thompson .output("qdata", dim * (dim + 1) / 2, libceed::EvalMode::None)?; 2203eb59678SJeremy L Thompson // -- QFunction from gallery 2213eb59678SJeremy L Thompson let qf_build_named = { 2223eb59678SJeremy L Thompson let name = format!("Poisson{}DBuild", dim); 2233eb59678SJeremy L Thompson ceed.q_function_interior_by_name(&name)? 2243eb59678SJeremy L Thompson }; 2253eb59678SJeremy L Thompson // -- QFunction for use with Operator 2263eb59678SJeremy L Thompson let qf_build = if gallery { 2273eb59678SJeremy L Thompson QFunctionOpt::SomeQFunctionByName(&qf_build_named) 2283eb59678SJeremy L Thompson } else { 2293eb59678SJeremy L Thompson QFunctionOpt::SomeQFunction(&qf_build_closure) 2303eb59678SJeremy L Thompson }; 2313eb59678SJeremy L Thompson 2323eb59678SJeremy L Thompson // Operator that build the quadrature data for the diff operator 2333eb59678SJeremy L Thompson let op_build = ceed 2343eb59678SJeremy L Thompson .operator(qf_build, QFunctionOpt::None, QFunctionOpt::None)? 2353eb59678SJeremy L Thompson .name("build qdata")? 2363eb59678SJeremy L Thompson .field("dx", &rstr_mesh, &basis_mesh, VectorOpt::Active)? 2373eb59678SJeremy L Thompson .field( 2383eb59678SJeremy L Thompson "weights", 2393eb59678SJeremy L Thompson ElemRestrictionOpt::None, 2403eb59678SJeremy L Thompson &basis_mesh, 2413eb59678SJeremy L Thompson VectorOpt::None, 2423eb59678SJeremy L Thompson )? 2433eb59678SJeremy L Thompson .field("qdata", &rstr_qdata, BasisOpt::None, VectorOpt::Active)? 2443eb59678SJeremy L Thompson .check()?; 2453eb59678SJeremy L Thompson 2463eb59678SJeremy L Thompson // Compute the quadrature data for the diff operator 2473eb59678SJeremy L Thompson let elem_qpts = num_qpts.pow(dim as u32); 2483eb59678SJeremy L Thompson let num_elem: usize = num_xyz.iter().take(dim).product(); 2493eb59678SJeremy L Thompson let mut qdata = ceed.vector(num_elem * elem_qpts * dim * (dim + 1) / 2)?; 2503eb59678SJeremy L Thompson op_build.apply(&mesh_coords, &mut qdata)?; 2513eb59678SJeremy L Thompson 2523eb59678SJeremy L Thompson // QFunction that applies the diff operator 2533eb59678SJeremy L Thompson // -- QFunction from user closure 2543eb59678SJeremy L Thompson let apply_diff = move |[ug, qdata, ..]: QFunctionInputs, [vg, ..]: QFunctionOutputs| { 2553eb59678SJeremy L Thompson // Apply diffusion operator 2563eb59678SJeremy L Thompson match dim { 2573eb59678SJeremy L Thompson 1 => { 2583eb59678SJeremy L Thompson let q = qdata.len(); 2593eb59678SJeremy L Thompson for c in 0..ncomp_u { 2603eb59678SJeremy L Thompson vg.iter_mut() 2613eb59678SJeremy L Thompson .skip(c * q) 2623eb59678SJeremy L Thompson .zip(ug.iter().skip(c * q).zip(qdata.iter())) 2633eb59678SJeremy L Thompson .for_each(|(vg, (ug, w))| *vg = ug * w) 2643eb59678SJeremy L Thompson } 2653eb59678SJeremy L Thompson } 2663eb59678SJeremy L Thompson 2 => { 2673eb59678SJeremy L Thompson let q = qdata.len() / 3; 2683eb59678SJeremy L Thompson for i in 0..q { 2693eb59678SJeremy L Thompson let dxdxdxdx_t = [ 2703eb59678SJeremy L Thompson [qdata[i + 0 * q], qdata[i + 2 * q]], 2713eb59678SJeremy L Thompson [qdata[i + 2 * q], qdata[i + 1 * q]], 2723eb59678SJeremy L Thompson ]; 2733eb59678SJeremy L Thompson for c in 0..ncomp_u { 2743eb59678SJeremy L Thompson let du = [ug[i + (c + 0 * ncomp_u) * q], ug[i + (c + 1 * ncomp_u) * q]]; 2753eb59678SJeremy L Thompson for j in 0..dim { 2763eb59678SJeremy L Thompson vg[i + (c + j * ncomp_u) * q] = 2773eb59678SJeremy L Thompson du[0] * dxdxdxdx_t[0][j] + du[1] * dxdxdxdx_t[1][j]; 2783eb59678SJeremy L Thompson } 2793eb59678SJeremy L Thompson } 2803eb59678SJeremy L Thompson } 2813eb59678SJeremy L Thompson } 2823eb59678SJeremy L Thompson 3 => { 2833eb59678SJeremy L Thompson let q = qdata.len() / 6; 2843eb59678SJeremy L Thompson for i in 0..q { 2853eb59678SJeremy L Thompson let dxdxdxdx_t = [ 2863eb59678SJeremy L Thompson [qdata[i + 0 * q], qdata[i + 5 * q], qdata[i + 4 * q]], 2873eb59678SJeremy L Thompson [qdata[i + 5 * q], qdata[i + 1 * q], qdata[i + 3 * q]], 2883eb59678SJeremy L Thompson [qdata[i + 4 * q], qdata[i + 3 * q], qdata[i + 2 * q]], 2893eb59678SJeremy L Thompson ]; 2903eb59678SJeremy L Thompson for c in 0..ncomp_u { 2913eb59678SJeremy L Thompson let du = [ 2923eb59678SJeremy L Thompson ug[i + (c + 0 * ncomp_u) * q], 2933eb59678SJeremy L Thompson ug[i + (c + 1 * ncomp_u) * q], 2943eb59678SJeremy L Thompson ug[i + (c + 2 * ncomp_u) * q], 2953eb59678SJeremy L Thompson ]; 2963eb59678SJeremy L Thompson for j in 0..dim { 2973eb59678SJeremy L Thompson vg[i + (c + j * ncomp_u) * q] = du[0] * dxdxdxdx_t[0][j] 2983eb59678SJeremy L Thompson + du[1] * dxdxdxdx_t[1][j] 2993eb59678SJeremy L Thompson + du[2] * dxdxdxdx_t[2][j]; 3003eb59678SJeremy L Thompson } 3013eb59678SJeremy L Thompson } 3023eb59678SJeremy L Thompson } 3033eb59678SJeremy L Thompson } 3043eb59678SJeremy L Thompson _ => unreachable!(), 3053eb59678SJeremy L Thompson }; 3063eb59678SJeremy L Thompson 3073eb59678SJeremy L Thompson // Return clean error code 3083eb59678SJeremy L Thompson 0 3093eb59678SJeremy L Thompson }; 3103eb59678SJeremy L Thompson let qf_diff_closure = ceed 3113eb59678SJeremy L Thompson .q_function_interior(1, Box::new(apply_diff))? 3123eb59678SJeremy L Thompson .input("du", dim * ncomp_u, libceed::EvalMode::Grad)? 3133eb59678SJeremy L Thompson .input("qdata", dim * (dim + 1) / 2, libceed::EvalMode::None)? 3143eb59678SJeremy L Thompson .output("dv", dim * ncomp_u, libceed::EvalMode::Grad)?; 3153eb59678SJeremy L Thompson // -- QFunction from gallery 3163eb59678SJeremy L Thompson let qf_diff_named = { 3173eb59678SJeremy L Thompson let name = format!("Vector3Poisson{}DApply", dim); 3183eb59678SJeremy L Thompson ceed.q_function_interior_by_name(&name)? 3193eb59678SJeremy L Thompson }; 3203eb59678SJeremy L Thompson // -- QFunction for use with Operator 3213eb59678SJeremy L Thompson let qf_diff = if gallery { 3223eb59678SJeremy L Thompson QFunctionOpt::SomeQFunctionByName(&qf_diff_named) 3233eb59678SJeremy L Thompson } else { 3243eb59678SJeremy L Thompson QFunctionOpt::SomeQFunction(&qf_diff_closure) 3253eb59678SJeremy L Thompson }; 3263eb59678SJeremy L Thompson 3273eb59678SJeremy L Thompson // Diff Operator 3283eb59678SJeremy L Thompson let op_diff = ceed 3293eb59678SJeremy L Thompson .operator(qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 3303eb59678SJeremy L Thompson .name("Poisson")? 3313eb59678SJeremy L Thompson .field("du", &rstr_solution, &basis_solution, VectorOpt::Active)? 3323eb59678SJeremy L Thompson .field("qdata", &rstr_qdata, BasisOpt::None, &qdata)? 3333eb59678SJeremy L Thompson .field("dv", &rstr_solution, &basis_solution, VectorOpt::Active)? 3343eb59678SJeremy L Thompson .check()?; 3353eb59678SJeremy L Thompson 3363eb59678SJeremy L Thompson // Solution vectors 3373eb59678SJeremy L Thompson let mut u = ceed.vector(solution_size)?; 3383eb59678SJeremy L Thompson let mut v = ceed.vector(solution_size)?; 3393eb59678SJeremy L Thompson 3403eb59678SJeremy L Thompson // Initialize u with sum of node coordinates 3413eb59678SJeremy L Thompson let coords = mesh_coords.view()?; 3423eb59678SJeremy L Thompson u.set_value(0.0)?; 3433eb59678SJeremy L Thompson for c in 0..ncomp_u { 3443eb59678SJeremy L Thompson let q = solution_size / ncomp_u; 3453eb59678SJeremy L Thompson u.view_mut()? 3463eb59678SJeremy L Thompson .iter_mut() 3473eb59678SJeremy L Thompson .skip(c * q) 3483eb59678SJeremy L Thompson .take(q) 3493eb59678SJeremy L Thompson .enumerate() 3503eb59678SJeremy L Thompson .for_each(|(i, u)| { 3513eb59678SJeremy L Thompson *u = (0..dim).map(|d| coords[i + d * q]).sum::<libceed::Scalar>() 3523eb59678SJeremy L Thompson * (c + 1) as libceed::Scalar; 3533eb59678SJeremy L Thompson }); 3543eb59678SJeremy L Thompson } 3553eb59678SJeremy L Thompson 3563eb59678SJeremy L Thompson // Apply the diff operator 3573eb59678SJeremy L Thompson op_diff.apply(&u, &mut v)?; 3583eb59678SJeremy L Thompson 3593eb59678SJeremy L Thompson // Compute the mesh surface area 3603eb59678SJeremy L Thompson let area: libceed::Scalar = v 3613eb59678SJeremy L Thompson .view()? 3623eb59678SJeremy L Thompson .iter() 3633eb59678SJeremy L Thompson .map(|v| (*v).abs()) 3643eb59678SJeremy L Thompson .sum::<libceed::Scalar>() 3653eb59678SJeremy L Thompson / ((ncomp_u * (ncomp_u + 1)) / 2) as libceed::Scalar; 3663eb59678SJeremy L Thompson 3673eb59678SJeremy L Thompson // Output results 3683eb59678SJeremy L Thompson if !quiet { 3693eb59678SJeremy L Thompson println!("Exact mesh surface area : {:.12}", exact_area); 3703eb59678SJeremy L Thompson println!("Computed mesh surface_area : {:.12}", area); 3713eb59678SJeremy L Thompson println!("Surface area error : {:.12e}", area - exact_area); 3723eb59678SJeremy L Thompson } 3733eb59678SJeremy L Thompson let tolerance = match dim { 3743eb59678SJeremy L Thompson 1 => 1E-5, 3753eb59678SJeremy L Thompson _ => 1E-1, 3763eb59678SJeremy L Thompson }; 3773eb59678SJeremy L Thompson let error = (area - exact_area).abs(); 3783eb59678SJeremy L Thompson if error > tolerance { 3793eb59678SJeremy L Thompson println!("Volume error too large: {:.12e}", error); 3803eb59678SJeremy L Thompson return Err(libceed::Error { 3813eb59678SJeremy L Thompson message: format!( 3823eb59678SJeremy L Thompson "Volume error too large - expected: {:.12e}, actual: {:.12e}", 3833eb59678SJeremy L Thompson tolerance, error 3843eb59678SJeremy L Thompson ), 3853eb59678SJeremy L Thompson }); 3863eb59678SJeremy L Thompson } 3873eb59678SJeremy L Thompson Ok(()) 3883eb59678SJeremy L Thompson } 3893eb59678SJeremy L Thompson 3903eb59678SJeremy L Thompson // ---------------------------------------------------------------------------- 3913eb59678SJeremy L Thompson // Tests 3923eb59678SJeremy L Thompson // ---------------------------------------------------------------------------- 3933eb59678SJeremy L Thompson #[cfg(test)] 3943eb59678SJeremy L Thompson mod tests { 3953eb59678SJeremy L Thompson use super::*; 3963eb59678SJeremy L Thompson 3973eb59678SJeremy L Thompson #[test] 3983eb59678SJeremy L Thompson fn example_2_vector_1d() { 3993eb59678SJeremy L Thompson let options = opt::Opt { 4003eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 4013eb59678SJeremy L Thompson dim: 1, 4023eb59678SJeremy L Thompson mesh_degree: 4, 4033eb59678SJeremy L Thompson solution_degree: 4, 4043eb59678SJeremy L Thompson num_qpts: 6, 4053eb59678SJeremy L Thompson problem_size_requested: -1, 4063eb59678SJeremy L Thompson test: true, 4073eb59678SJeremy L Thompson quiet: true, 4083eb59678SJeremy L Thompson gallery: false, 4093eb59678SJeremy L Thompson }; 4103eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 4113eb59678SJeremy L Thompson } 4123eb59678SJeremy L Thompson 4133eb59678SJeremy L Thompson #[test] 4143eb59678SJeremy L Thompson fn example_2_vector_2d() { 4153eb59678SJeremy L Thompson let options = opt::Opt { 4163eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 4173eb59678SJeremy L Thompson dim: 2, 4183eb59678SJeremy L Thompson mesh_degree: 4, 4193eb59678SJeremy L Thompson solution_degree: 4, 4203eb59678SJeremy L Thompson num_qpts: 6, 4213eb59678SJeremy L Thompson problem_size_requested: -1, 4223eb59678SJeremy L Thompson test: true, 4233eb59678SJeremy L Thompson quiet: true, 4243eb59678SJeremy L Thompson gallery: false, 4253eb59678SJeremy L Thompson }; 4263eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 4273eb59678SJeremy L Thompson } 4283eb59678SJeremy L Thompson 4293eb59678SJeremy L Thompson #[test] 4303eb59678SJeremy L Thompson fn example_2_vector_3d() { 4313eb59678SJeremy L Thompson let options = opt::Opt { 4323eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 4333eb59678SJeremy L Thompson dim: 3, 4343eb59678SJeremy L Thompson mesh_degree: 4, 4353eb59678SJeremy L Thompson solution_degree: 4, 4363eb59678SJeremy L Thompson num_qpts: 6, 4373eb59678SJeremy L Thompson problem_size_requested: -1, 4383eb59678SJeremy L Thompson test: true, 4393eb59678SJeremy L Thompson quiet: false, 4403eb59678SJeremy L Thompson gallery: false, 4413eb59678SJeremy L Thompson }; 4423eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 4433eb59678SJeremy L Thompson } 4443eb59678SJeremy L Thompson 4453eb59678SJeremy L Thompson #[test] 4463eb59678SJeremy L Thompson fn example_2_vector_1d_gallery() { 4473eb59678SJeremy L Thompson let options = opt::Opt { 4483eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 4493eb59678SJeremy L Thompson dim: 1, 4503eb59678SJeremy L Thompson mesh_degree: 4, 4513eb59678SJeremy L Thompson solution_degree: 4, 4523eb59678SJeremy L Thompson num_qpts: 6, 4533eb59678SJeremy L Thompson problem_size_requested: -1, 4543eb59678SJeremy L Thompson test: true, 4553eb59678SJeremy L Thompson quiet: true, 4563eb59678SJeremy L Thompson gallery: true, 4573eb59678SJeremy L Thompson }; 4583eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 4593eb59678SJeremy L Thompson } 4603eb59678SJeremy L Thompson 4613eb59678SJeremy L Thompson #[test] 4623eb59678SJeremy L Thompson fn example_2_vector_2d_gallery() { 4633eb59678SJeremy L Thompson let options = opt::Opt { 4643eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 4653eb59678SJeremy L Thompson dim: 2, 4663eb59678SJeremy L Thompson mesh_degree: 4, 4673eb59678SJeremy L Thompson solution_degree: 4, 4683eb59678SJeremy L Thompson num_qpts: 6, 4693eb59678SJeremy L Thompson problem_size_requested: -1, 4703eb59678SJeremy L Thompson test: true, 4713eb59678SJeremy L Thompson quiet: true, 4723eb59678SJeremy L Thompson gallery: true, 4733eb59678SJeremy L Thompson }; 4743eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 4753eb59678SJeremy L Thompson } 4763eb59678SJeremy L Thompson 4773eb59678SJeremy L Thompson #[test] 4783eb59678SJeremy L Thompson fn example_2_vector_3d_gallery() { 4793eb59678SJeremy L Thompson let options = opt::Opt { 4803eb59678SJeremy L Thompson ceed_spec: "/cpu/self/ref/serial".to_string(), 4813eb59678SJeremy L Thompson dim: 3, 4823eb59678SJeremy L Thompson mesh_degree: 4, 4833eb59678SJeremy L Thompson solution_degree: 4, 4843eb59678SJeremy L Thompson num_qpts: 6, 4853eb59678SJeremy L Thompson problem_size_requested: -1, 4863eb59678SJeremy L Thompson test: true, 4873eb59678SJeremy L Thompson quiet: true, 4883eb59678SJeremy L Thompson gallery: true, 4893eb59678SJeremy L Thompson }; 4903eb59678SJeremy L Thompson assert!(example_2_vector(options).is_ok()); 4913eb59678SJeremy L Thompson } 4923eb59678SJeremy L Thompson } 4933eb59678SJeremy L Thompson 4943eb59678SJeremy L Thompson // ---------------------------------------------------------------------------- 495