xref: /libCEED/examples/rust/mesh/src/lib.rs (revision e78171ed8dd041a0e6ed78a254aed7d6401b27d0)
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 use libceed::{prelude::*, Ceed};
18ded9b81dSJeremy L Thompson 
19ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
20ded9b81dSJeremy L Thompson // Determine problem size in each dimension from size and dimenison
21ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
22ded9b81dSJeremy L Thompson pub fn cartesian_mesh_size(dim: usize, solution_degree: usize, problem_size: i64) -> [usize; 3] {
23ded9b81dSJeremy L Thompson     // Use the approximate formula:
24ded9b81dSJeremy L Thompson     //    prob_size ~ num_elem * degree^dim
25ded9b81dSJeremy L Thompson     let mut num_elem = problem_size / solution_degree.pow(dim as u32) as i64;
26ded9b81dSJeremy L Thompson     let mut s = 0; // find s: num_elem / 2 < 2^s <= num_elem
27ded9b81dSJeremy L Thompson     while num_elem > 1 {
28ded9b81dSJeremy L Thompson         num_elem /= 2;
29ded9b81dSJeremy L Thompson         s += 1;
30ded9b81dSJeremy L Thompson     }
31ded9b81dSJeremy L Thompson 
32ded9b81dSJeremy L Thompson     // Size per dimension
33ded9b81dSJeremy L Thompson     let mut r = s % dim;
34ded9b81dSJeremy L Thompson     let mut num_xyz = [0; 3];
35ded9b81dSJeremy L Thompson     for d in 0..dim {
36ded9b81dSJeremy L Thompson         let mut sd = s / dim;
37ded9b81dSJeremy L Thompson         if r > 0 {
38ded9b81dSJeremy L Thompson             sd += 1;
39ded9b81dSJeremy L Thompson             r -= 1;
40ded9b81dSJeremy L Thompson         }
41ded9b81dSJeremy L Thompson         num_xyz[d] = 1 << sd;
42ded9b81dSJeremy L Thompson     }
43ded9b81dSJeremy L Thompson     num_xyz
44ded9b81dSJeremy L Thompson }
45ded9b81dSJeremy L Thompson 
46ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
47ded9b81dSJeremy L Thompson // Build element restriction objects for the mesh
48ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
49ded9b81dSJeremy L Thompson pub fn build_cartesian_restriction(
50ded9b81dSJeremy L Thompson     ceed: &Ceed,
51ded9b81dSJeremy L Thompson     dim: usize,
52ded9b81dSJeremy L Thompson     num_xyz: [usize; 3],
53ded9b81dSJeremy L Thompson     degree: usize,
54ded9b81dSJeremy L Thompson     num_comp: usize,
55ded9b81dSJeremy L Thompson     num_qpts: usize,
5689d15d5fSJeremy L Thompson ) -> libceed::Result<(ElemRestriction, ElemRestriction)> {
57ded9b81dSJeremy L Thompson     let p = degree + 1;
58ded9b81dSJeremy L Thompson     let num_nodes = p.pow(dim as u32); // number of nodes per element
59ded9b81dSJeremy L Thompson     let elem_qpts = num_qpts.pow(dim as u32); // number of quadrature pts per element
60ded9b81dSJeremy L Thompson 
61ded9b81dSJeremy L Thompson     // Problem dimensions
62ded9b81dSJeremy L Thompson     let mut num_d = [0; 3];
63ded9b81dSJeremy L Thompson     let mut num_elem = 1;
64ded9b81dSJeremy L Thompson     let mut scalar_size = 1;
65ded9b81dSJeremy L Thompson     for d in 0..dim {
66ded9b81dSJeremy L Thompson         num_elem *= num_xyz[d];
67ded9b81dSJeremy L Thompson         num_d[d] = num_xyz[d] * (p - 1) + 1;
68ded9b81dSJeremy L Thompson         scalar_size *= num_d[d];
69ded9b81dSJeremy L Thompson     }
70ded9b81dSJeremy L Thompson 
71ded9b81dSJeremy L Thompson     // elem:         0             1                 n-1
72ded9b81dSJeremy L Thompson     //        |---*-...-*---|---*-...-*---|- ... -|--...--|
73ded9b81dSJeremy L Thompson     // nodes: 0   1    p-1  p  p+1       2*p             n*p
74ded9b81dSJeremy L Thompson     let mut elem_nodes = vec![0; num_elem * num_nodes];
75ded9b81dSJeremy L Thompson     for e in 0..num_elem {
76ded9b81dSJeremy L Thompson         let mut e_xyz = [1; 3];
77ded9b81dSJeremy L Thompson         let mut re = e;
78ded9b81dSJeremy L Thompson         for d in 0..dim {
79ded9b81dSJeremy L Thompson             e_xyz[d] = re % num_xyz[d];
80ded9b81dSJeremy L Thompson             re /= num_xyz[d];
81ded9b81dSJeremy L Thompson         }
82ded9b81dSJeremy L Thompson         let loc_offset = e * num_nodes;
83ded9b81dSJeremy L Thompson         for loc_nodes in 0..num_nodes {
84ded9b81dSJeremy L Thompson             let mut global_nodes = 0;
85ded9b81dSJeremy L Thompson             let mut global_nodes_stride = 1;
86ded9b81dSJeremy L Thompson             let mut r_nodes = loc_nodes;
87ded9b81dSJeremy L Thompson             for d in 0..dim {
88ded9b81dSJeremy L Thompson                 global_nodes += (e_xyz[d] * (p - 1) + r_nodes % p) * global_nodes_stride;
89ded9b81dSJeremy L Thompson                 global_nodes_stride *= num_d[d];
90ded9b81dSJeremy L Thompson                 r_nodes /= p;
91ded9b81dSJeremy L Thompson             }
92ded9b81dSJeremy L Thompson             elem_nodes[loc_offset + loc_nodes] = global_nodes as i32;
93ded9b81dSJeremy L Thompson         }
94ded9b81dSJeremy L Thompson     }
95ded9b81dSJeremy L Thompson 
96ded9b81dSJeremy L Thompson     // Mesh/solution data restriction
97ded9b81dSJeremy L Thompson     let restr = ceed.elem_restriction(
98ded9b81dSJeremy L Thompson         num_elem,
99ded9b81dSJeremy L Thompson         num_nodes,
100ded9b81dSJeremy L Thompson         num_comp,
101ded9b81dSJeremy L Thompson         scalar_size,
102ded9b81dSJeremy L Thompson         num_comp * scalar_size,
103ded9b81dSJeremy L Thompson         MemType::Host,
104ded9b81dSJeremy L Thompson         &elem_nodes,
105e15f9bd0SJeremy L Thompson     )?;
106ded9b81dSJeremy L Thompson 
107ded9b81dSJeremy L Thompson     // Quadratue data restriction
108ded9b81dSJeremy L Thompson     let restr_qdata = ceed.strided_elem_restriction(
109ded9b81dSJeremy L Thompson         num_elem,
110ded9b81dSJeremy L Thompson         elem_qpts,
111ded9b81dSJeremy L Thompson         num_comp,
112ded9b81dSJeremy L Thompson         num_comp * elem_qpts * num_elem,
113ded9b81dSJeremy L Thompson         CEED_STRIDES_BACKEND,
114e15f9bd0SJeremy L Thompson     )?;
115e15f9bd0SJeremy L Thompson     Ok((restr, restr_qdata))
116ded9b81dSJeremy L Thompson }
117ded9b81dSJeremy L Thompson 
118ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
119ded9b81dSJeremy L Thompson // Set mesh coordinates
120ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
121ded9b81dSJeremy L Thompson pub fn cartesian_mesh_coords(
122ded9b81dSJeremy L Thompson     ceed: &Ceed,
123ded9b81dSJeremy L Thompson     dim: usize,
124ded9b81dSJeremy L Thompson     num_xyz: [usize; 3],
125ded9b81dSJeremy L Thompson     mesh_degree: usize,
126ded9b81dSJeremy L Thompson     mesh_size: usize,
12789d15d5fSJeremy L Thompson ) -> libceed::Result<Vector> {
128ded9b81dSJeremy L Thompson     let p = mesh_degree + 1;
129ded9b81dSJeremy L Thompson     let mut num_d = [0; 3];
130ded9b81dSJeremy L Thompson     let mut scalar_size = 1;
131ded9b81dSJeremy L Thompson     for d in 0..dim {
132ded9b81dSJeremy L Thompson         num_d[d] = num_xyz[d] * (p - 1) + 1;
133ded9b81dSJeremy L Thompson         scalar_size *= num_d[d];
134ded9b81dSJeremy L Thompson     }
135ded9b81dSJeremy L Thompson 
136ded9b81dSJeremy L Thompson     // Lobatto points
137e15f9bd0SJeremy L Thompson     let lobatto_basis = ceed
138e15f9bd0SJeremy L Thompson         .basis_tensor_H1_Lagrange(1, 1, 2, p, QuadMode::GaussLobatto)
139e15f9bd0SJeremy L Thompson         .unwrap();
140e15f9bd0SJeremy L Thompson     let nodes_corners = ceed.vector_from_slice(&[0.0, 1.0])?;
141e15f9bd0SJeremy L Thompson     let mut nodes_full = ceed.vector(p)?;
142ded9b81dSJeremy L Thompson     lobatto_basis.apply(
143ded9b81dSJeremy L Thompson         1,
144ded9b81dSJeremy L Thompson         TransposeMode::NoTranspose,
145ded9b81dSJeremy L Thompson         EvalMode::Interp,
146ded9b81dSJeremy L Thompson         &nodes_corners,
147ded9b81dSJeremy L Thompson         &mut nodes_full,
148e15f9bd0SJeremy L Thompson     )?;
149ded9b81dSJeremy L Thompson 
150ded9b81dSJeremy L Thompson     // Coordinates for mesh
151e15f9bd0SJeremy L Thompson     let mut mesh_coords = ceed.vector(mesh_size)?;
152ded9b81dSJeremy L Thompson     {
153*e78171edSJeremy L Thompson         let mut coords = mesh_coords.view_mut()?;
154*e78171edSJeremy L Thompson         let nodes = nodes_full.view()?;
155ded9b81dSJeremy L Thompson         for gs_nodes in 0..scalar_size {
156ded9b81dSJeremy L Thompson             let mut r_nodes = gs_nodes;
157ded9b81dSJeremy L Thompson             for d in 0..dim {
158ded9b81dSJeremy L Thompson                 let d_1d = r_nodes % num_d[d];
159ded9b81dSJeremy L Thompson                 coords[gs_nodes + scalar_size * d] =
16080a9ef05SNatalie Beams                     ((d_1d / (p - 1)) as Scalar + nodes[d_1d % (p - 1)]) / num_xyz[d] as Scalar;
161ded9b81dSJeremy L Thompson                 r_nodes /= num_d[d];
162ded9b81dSJeremy L Thompson             }
163ded9b81dSJeremy L Thompson         }
164ded9b81dSJeremy L Thompson     }
165e15f9bd0SJeremy L Thompson     Ok(mesh_coords)
166ded9b81dSJeremy L Thompson }
167ded9b81dSJeremy L Thompson 
168ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
169