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