xref: /libCEED/examples/rust/mesh/src/lib.rs (revision 9ba83ac0e4b1fca39d6fa6737a318a9f0cbc172d)
1*9ba83ac0SJeremy L Thompson // Copyright (c) 2017-2026, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3ded9b81dSJeremy L Thompson //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
5ded9b81dSJeremy L Thompson //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
7ded9b81dSJeremy L Thompson 
8eb07d68fSJeremy L Thompson use libceed::{Ceed, ElemRestriction, Vector};
978c2cefaSJeremy L Thompson use std::convert::TryInto;
10ded9b81dSJeremy L Thompson 
11ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
12ded9b81dSJeremy L Thompson // Determine problem size in each dimension from size and dimenison
13ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
14ded9b81dSJeremy L Thompson pub fn cartesian_mesh_size(dim: usize, solution_degree: usize, problem_size: i64) -> [usize; 3] {
15ded9b81dSJeremy L Thompson     // Use the approximate formula:
16ded9b81dSJeremy L Thompson     //    prob_size ~ num_elem * degree^dim
17ded9b81dSJeremy L Thompson     let mut num_elem = problem_size / solution_degree.pow(dim as u32) as i64;
18ded9b81dSJeremy L Thompson     let mut s = 0; // find s: num_elem / 2 < 2^s <= num_elem
19ded9b81dSJeremy L Thompson     while num_elem > 1 {
20ded9b81dSJeremy L Thompson         num_elem /= 2;
21ded9b81dSJeremy L Thompson         s += 1;
22ded9b81dSJeremy L Thompson     }
23ded9b81dSJeremy L Thompson 
24ded9b81dSJeremy L Thompson     // Size per dimension
25ded9b81dSJeremy L Thompson     let mut r = s % dim;
2678c2cefaSJeremy L Thompson     let xyz: [usize; 3] = (0..3)
2778c2cefaSJeremy L Thompson         .map(|_| -> usize {
28ded9b81dSJeremy L Thompson             let mut sd = s / dim;
29ded9b81dSJeremy L Thompson             if r > 0 {
30ded9b81dSJeremy L Thompson                 sd += 1;
31ded9b81dSJeremy L Thompson                 r -= 1;
32ded9b81dSJeremy L Thompson             }
3378c2cefaSJeremy L Thompson             1 << sd
3478c2cefaSJeremy L Thompson         })
3578c2cefaSJeremy L Thompson         .collect::<Vec<usize>>()
3678c2cefaSJeremy L Thompson         .try_into()
3778c2cefaSJeremy L Thompson         .unwrap();
3878c2cefaSJeremy L Thompson     xyz
39ded9b81dSJeremy L Thompson }
40ded9b81dSJeremy L Thompson 
41ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
42ded9b81dSJeremy L Thompson // Build element restriction objects for the mesh
43ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
44ded9b81dSJeremy L Thompson pub fn build_cartesian_restriction(
45ded9b81dSJeremy L Thompson     ceed: &Ceed,
46ded9b81dSJeremy L Thompson     dim: usize,
47ded9b81dSJeremy L Thompson     num_xyz: [usize; 3],
48ded9b81dSJeremy L Thompson     degree: usize,
49ded9b81dSJeremy L Thompson     num_comp: usize,
50ded9b81dSJeremy L Thompson     num_qpts: usize,
5189d15d5fSJeremy L Thompson ) -> libceed::Result<(ElemRestriction, ElemRestriction)> {
52ded9b81dSJeremy L Thompson     let p = degree + 1;
53ded9b81dSJeremy L Thompson     let num_nodes = p.pow(dim as u32); // number of nodes per element
54ded9b81dSJeremy L Thompson     let elem_qpts = num_qpts.pow(dim as u32); // number of quadrature pts per element
55ded9b81dSJeremy L Thompson 
56ded9b81dSJeremy L Thompson     // Problem dimensions
57ded9b81dSJeremy L Thompson     let mut num_d = [0; 3];
58ded9b81dSJeremy L Thompson     let mut num_elem = 1;
59ded9b81dSJeremy L Thompson     let mut scalar_size = 1;
60ded9b81dSJeremy L Thompson     for d in 0..dim {
61ded9b81dSJeremy L Thompson         num_elem *= num_xyz[d];
62ded9b81dSJeremy L Thompson         num_d[d] = num_xyz[d] * (p - 1) + 1;
63ded9b81dSJeremy L Thompson         scalar_size *= num_d[d];
64ded9b81dSJeremy L Thompson     }
65ded9b81dSJeremy L Thompson 
66ded9b81dSJeremy L Thompson     // elem:         0             1                 n-1
67ded9b81dSJeremy L Thompson     //        |---*-...-*---|---*-...-*---|- ... -|--...--|
68ded9b81dSJeremy L Thompson     // nodes: 0   1    p-1  p  p+1       2*p             n*p
69ded9b81dSJeremy L Thompson     let mut elem_nodes = vec![0; num_elem * num_nodes];
70ded9b81dSJeremy L Thompson     for e in 0..num_elem {
71ded9b81dSJeremy L Thompson         let mut e_xyz = [1; 3];
72ded9b81dSJeremy L Thompson         let mut re = e;
73ded9b81dSJeremy L Thompson         for d in 0..dim {
74ded9b81dSJeremy L Thompson             e_xyz[d] = re % num_xyz[d];
75ded9b81dSJeremy L Thompson             re /= num_xyz[d];
76ded9b81dSJeremy L Thompson         }
77ded9b81dSJeremy L Thompson         let loc_offset = e * num_nodes;
78ded9b81dSJeremy L Thompson         for loc_nodes in 0..num_nodes {
79ded9b81dSJeremy L Thompson             let mut global_nodes = 0;
80ded9b81dSJeremy L Thompson             let mut global_nodes_stride = 1;
81ded9b81dSJeremy L Thompson             let mut r_nodes = loc_nodes;
82ded9b81dSJeremy L Thompson             for d in 0..dim {
83ded9b81dSJeremy L Thompson                 global_nodes += (e_xyz[d] * (p - 1) + r_nodes % p) * global_nodes_stride;
84ded9b81dSJeremy L Thompson                 global_nodes_stride *= num_d[d];
85ded9b81dSJeremy L Thompson                 r_nodes /= p;
86ded9b81dSJeremy L Thompson             }
87ded9b81dSJeremy L Thompson             elem_nodes[loc_offset + loc_nodes] = global_nodes as i32;
88ded9b81dSJeremy L Thompson         }
89ded9b81dSJeremy L Thompson     }
90ded9b81dSJeremy L Thompson 
91ded9b81dSJeremy L Thompson     // Mesh/solution data restriction
92edb2538eSJeremy L Thompson     let rstr = ceed.elem_restriction(
93ded9b81dSJeremy L Thompson         num_elem,
94ded9b81dSJeremy L Thompson         num_nodes,
95ded9b81dSJeremy L Thompson         num_comp,
96ded9b81dSJeremy L Thompson         scalar_size,
97ded9b81dSJeremy L Thompson         num_comp * scalar_size,
98eb07d68fSJeremy L Thompson         libceed::MemType::Host,
99ded9b81dSJeremy L Thompson         &elem_nodes,
100e15f9bd0SJeremy L Thompson     )?;
101ded9b81dSJeremy L Thompson 
10278c2cefaSJeremy L Thompson     // Quadrature data restriction
103edb2538eSJeremy L Thompson     let rstr_qdata = ceed.strided_elem_restriction(
104ded9b81dSJeremy L Thompson         num_elem,
105ded9b81dSJeremy L Thompson         elem_qpts,
106ded9b81dSJeremy L Thompson         num_comp,
107ded9b81dSJeremy L Thompson         num_comp * elem_qpts * num_elem,
108eb07d68fSJeremy L Thompson         libceed::CEED_STRIDES_BACKEND,
109e15f9bd0SJeremy L Thompson     )?;
110edb2538eSJeremy L Thompson     Ok((rstr, rstr_qdata))
111ded9b81dSJeremy L Thompson }
112ded9b81dSJeremy L Thompson 
113ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
114ded9b81dSJeremy L Thompson // Set mesh coordinates
115ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
116ded9b81dSJeremy L Thompson pub fn cartesian_mesh_coords(
117ded9b81dSJeremy L Thompson     ceed: &Ceed,
118ded9b81dSJeremy L Thompson     dim: usize,
119ded9b81dSJeremy L Thompson     num_xyz: [usize; 3],
120ded9b81dSJeremy L Thompson     mesh_degree: usize,
121ded9b81dSJeremy L Thompson     mesh_size: usize,
12289d15d5fSJeremy L Thompson ) -> libceed::Result<Vector> {
123ded9b81dSJeremy L Thompson     let p = mesh_degree + 1;
124ded9b81dSJeremy L Thompson     let mut num_d = [0; 3];
125ded9b81dSJeremy L Thompson     let mut scalar_size = 1;
126ded9b81dSJeremy L Thompson     for d in 0..dim {
127ded9b81dSJeremy L Thompson         num_d[d] = num_xyz[d] * (p - 1) + 1;
128ded9b81dSJeremy L Thompson         scalar_size *= num_d[d];
129ded9b81dSJeremy L Thompson     }
130ded9b81dSJeremy L Thompson 
131ded9b81dSJeremy L Thompson     // Lobatto points
132eb07d68fSJeremy L Thompson     let lobatto_basis =
133eb07d68fSJeremy L Thompson         ceed.basis_tensor_H1_Lagrange(1, 1, 2, p, libceed::QuadMode::GaussLobatto)?;
134e15f9bd0SJeremy L Thompson     let nodes_corners = ceed.vector_from_slice(&[0.0, 1.0])?;
135e15f9bd0SJeremy L Thompson     let mut nodes_full = ceed.vector(p)?;
136ded9b81dSJeremy L Thompson     lobatto_basis.apply(
137ded9b81dSJeremy L Thompson         1,
138eb07d68fSJeremy L Thompson         libceed::TransposeMode::NoTranspose,
139eb07d68fSJeremy L Thompson         libceed::EvalMode::Interp,
140ded9b81dSJeremy L Thompson         &nodes_corners,
141ded9b81dSJeremy L Thompson         &mut nodes_full,
142e15f9bd0SJeremy L Thompson     )?;
143ded9b81dSJeremy L Thompson 
144ded9b81dSJeremy L Thompson     // Coordinates for mesh
145e15f9bd0SJeremy L Thompson     let mut mesh_coords = ceed.vector(mesh_size)?;
1469c774eddSJeremy L Thompson     mesh_coords.set_value(0.0)?;
147ded9b81dSJeremy L Thompson     {
148e78171edSJeremy L Thompson         let mut coords = mesh_coords.view_mut()?;
149e78171edSJeremy L Thompson         let nodes = nodes_full.view()?;
150ded9b81dSJeremy L Thompson         for gs_nodes in 0..scalar_size {
151ded9b81dSJeremy L Thompson             let mut r_nodes = gs_nodes;
152ded9b81dSJeremy L Thompson             for d in 0..dim {
153ded9b81dSJeremy L Thompson                 let d_1d = r_nodes % num_d[d];
154eb07d68fSJeremy L Thompson                 coords[gs_nodes + scalar_size * d] = ((d_1d / (p - 1)) as libceed::Scalar
155eb07d68fSJeremy L Thompson                     + nodes[d_1d % (p - 1)])
156eb07d68fSJeremy L Thompson                     / num_xyz[d] as libceed::Scalar;
157ded9b81dSJeremy L Thompson                 r_nodes /= num_d[d];
158ded9b81dSJeremy L Thompson             }
159ded9b81dSJeremy L Thompson         }
160ded9b81dSJeremy L Thompson     }
161e15f9bd0SJeremy L Thompson     Ok(mesh_coords)
162ded9b81dSJeremy L Thompson }
163ded9b81dSJeremy L Thompson 
164ded9b81dSJeremy L Thompson // ----------------------------------------------------------------------------
165