xref: /libCEED/rust/libceed/src/qfunction.rs (revision 257916f8766357eb38205c54507de8baf75f531a)
13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, 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.
39df49d7eSJed Brown //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
59df49d7eSJed Brown //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
79df49d7eSJed Brown 
89df49d7eSJed Brown //! A Ceed QFunction represents the spatial terms of the point-wise functions
99df49d7eSJed Brown //! describing the physics at the quadrature points.
109df49d7eSJed Brown 
119df49d7eSJed Brown use std::pin::Pin;
129df49d7eSJed Brown 
139df49d7eSJed Brown use crate::prelude::*;
149df49d7eSJed Brown 
1580a9ef05SNatalie Beams pub type QFunctionInputs<'a> = [&'a [crate::Scalar]; MAX_QFUNCTION_FIELDS];
1680a9ef05SNatalie Beams pub type QFunctionOutputs<'a> = [&'a mut [crate::Scalar]; MAX_QFUNCTION_FIELDS];
179df49d7eSJed Brown 
189df49d7eSJed Brown // -----------------------------------------------------------------------------
197ed177dbSJed Brown // QFunction Field context wrapper
2008778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
2108778c6fSJeremy L Thompson #[derive(Debug)]
2208778c6fSJeremy L Thompson pub struct QFunctionField<'a> {
2308778c6fSJeremy L Thompson     ptr: bind_ceed::CeedQFunctionField,
2408778c6fSJeremy L Thompson     _lifeline: PhantomData<&'a ()>,
2508778c6fSJeremy L Thompson }
2608778c6fSJeremy L Thompson 
2708778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
2808778c6fSJeremy L Thompson // Implementations
2908778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
3008778c6fSJeremy L Thompson impl<'a> QFunctionField<'a> {
3108778c6fSJeremy L Thompson     /// Get the name of a QFunctionField
3208778c6fSJeremy L Thompson     ///
3308778c6fSJeremy L Thompson     /// ```
3408778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
354d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
3608778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
3708778c6fSJeremy L Thompson     /// const Q: usize = 8;
3808778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass2DBuild")?;
3908778c6fSJeremy L Thompson     ///
4008778c6fSJeremy L Thompson     /// let inputs = qf.inputs()?;
4108778c6fSJeremy L Thompson     ///
4208778c6fSJeremy L Thompson     /// assert_eq!(inputs[0].name(), "dx", "Incorrect input name");
4308778c6fSJeremy L Thompson     /// assert_eq!(inputs[1].name(), "weights", "Incorrect input name");
4408778c6fSJeremy L Thompson     /// # Ok(())
4508778c6fSJeremy L Thompson     /// # }
4608778c6fSJeremy L Thompson     /// ```
4708778c6fSJeremy L Thompson     pub fn name(&self) -> &str {
4808778c6fSJeremy L Thompson         let mut name_ptr: *mut std::os::raw::c_char = std::ptr::null_mut();
4908778c6fSJeremy L Thompson         unsafe {
5008778c6fSJeremy L Thompson             bind_ceed::CeedQFunctionFieldGetName(self.ptr, &mut name_ptr);
5108778c6fSJeremy L Thompson         }
5208778c6fSJeremy L Thompson         unsafe { CStr::from_ptr(name_ptr) }.to_str().unwrap()
5308778c6fSJeremy L Thompson     }
5408778c6fSJeremy L Thompson 
5508778c6fSJeremy L Thompson     /// Get the size of a QFunctionField
5608778c6fSJeremy L Thompson     ///
5708778c6fSJeremy L Thompson     /// ```
5808778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
594d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
6008778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
6108778c6fSJeremy L Thompson     /// const Q: usize = 8;
6208778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass2DBuild")?;
6308778c6fSJeremy L Thompson     ///
6408778c6fSJeremy L Thompson     /// let inputs = qf.inputs()?;
6508778c6fSJeremy L Thompson     ///
6608778c6fSJeremy L Thompson     /// assert_eq!(inputs[0].size(), 4, "Incorrect input size");
6708778c6fSJeremy L Thompson     /// assert_eq!(inputs[1].size(), 1, "Incorrect input size");
6808778c6fSJeremy L Thompson     /// # Ok(())
6908778c6fSJeremy L Thompson     /// # }
7008778c6fSJeremy L Thompson     /// ```
7108778c6fSJeremy L Thompson     pub fn size(&self) -> usize {
7208778c6fSJeremy L Thompson         let mut size = 0;
7308778c6fSJeremy L Thompson         unsafe {
7408778c6fSJeremy L Thompson             bind_ceed::CeedQFunctionFieldGetSize(self.ptr, &mut size);
7508778c6fSJeremy L Thompson         }
7608778c6fSJeremy L Thompson         usize::try_from(size).unwrap()
7708778c6fSJeremy L Thompson     }
7808778c6fSJeremy L Thompson 
7908778c6fSJeremy L Thompson     /// Get the evaluation mode of a QFunctionField
8008778c6fSJeremy L Thompson     ///
8108778c6fSJeremy L Thompson     /// ```
8208778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
834d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
8408778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
8508778c6fSJeremy L Thompson     /// const Q: usize = 8;
8608778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass2DBuild")?;
8708778c6fSJeremy L Thompson     ///
8808778c6fSJeremy L Thompson     /// let inputs = qf.inputs()?;
8908778c6fSJeremy L Thompson     ///
9008778c6fSJeremy L Thompson     /// assert_eq!(
9108778c6fSJeremy L Thompson     ///     inputs[0].eval_mode(),
9208778c6fSJeremy L Thompson     ///     EvalMode::Grad,
9308778c6fSJeremy L Thompson     ///     "Incorrect input evaluation mode"
9408778c6fSJeremy L Thompson     /// );
9508778c6fSJeremy L Thompson     /// assert_eq!(
9608778c6fSJeremy L Thompson     ///     inputs[1].eval_mode(),
9708778c6fSJeremy L Thompson     ///     EvalMode::Weight,
9808778c6fSJeremy L Thompson     ///     "Incorrect input evaluation mode"
9908778c6fSJeremy L Thompson     /// );
10008778c6fSJeremy L Thompson     /// # Ok(())
10108778c6fSJeremy L Thompson     /// # }
10208778c6fSJeremy L Thompson     /// ```
10308778c6fSJeremy L Thompson     pub fn eval_mode(&self) -> crate::EvalMode {
10408778c6fSJeremy L Thompson         let mut mode = 0;
10508778c6fSJeremy L Thompson         unsafe {
10608778c6fSJeremy L Thompson             bind_ceed::CeedQFunctionFieldGetEvalMode(self.ptr, &mut mode);
10708778c6fSJeremy L Thompson         }
10808778c6fSJeremy L Thompson         crate::EvalMode::from_u32(mode as u32)
10908778c6fSJeremy L Thompson     }
11008778c6fSJeremy L Thompson }
11108778c6fSJeremy L Thompson 
11208778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
1137ed177dbSJed Brown // QFunction option
1149df49d7eSJed Brown // -----------------------------------------------------------------------------
1159df49d7eSJed Brown pub enum QFunctionOpt<'a> {
1169df49d7eSJed Brown     SomeQFunction(&'a QFunction<'a>),
1179df49d7eSJed Brown     SomeQFunctionByName(&'a QFunctionByName<'a>),
1189df49d7eSJed Brown     None,
1199df49d7eSJed Brown }
1209df49d7eSJed Brown 
1219df49d7eSJed Brown /// Construct a QFunctionOpt reference from a QFunction reference
1229df49d7eSJed Brown impl<'a> From<&'a QFunction<'_>> for QFunctionOpt<'a> {
1239df49d7eSJed Brown     fn from(qfunc: &'a QFunction) -> Self {
1249df49d7eSJed Brown         debug_assert!(qfunc.qf_core.ptr != unsafe { bind_ceed::CEED_QFUNCTION_NONE });
1259df49d7eSJed Brown         Self::SomeQFunction(qfunc)
1269df49d7eSJed Brown     }
1279df49d7eSJed Brown }
1289df49d7eSJed Brown 
1299df49d7eSJed Brown /// Construct a QFunctionOpt reference from a QFunction by Name reference
1309df49d7eSJed Brown impl<'a> From<&'a QFunctionByName<'_>> for QFunctionOpt<'a> {
1319df49d7eSJed Brown     fn from(qfunc: &'a QFunctionByName) -> Self {
1329df49d7eSJed Brown         debug_assert!(qfunc.qf_core.ptr != unsafe { bind_ceed::CEED_QFUNCTION_NONE });
1339df49d7eSJed Brown         Self::SomeQFunctionByName(qfunc)
1349df49d7eSJed Brown     }
1359df49d7eSJed Brown }
1369df49d7eSJed Brown 
1379df49d7eSJed Brown impl<'a> QFunctionOpt<'a> {
1389df49d7eSJed Brown     /// Transform a Rust libCEED QFunctionOpt into C libCEED CeedQFunction
1399df49d7eSJed Brown     pub(crate) fn to_raw(self) -> bind_ceed::CeedQFunction {
1409df49d7eSJed Brown         match self {
1419df49d7eSJed Brown             Self::SomeQFunction(qfunc) => qfunc.qf_core.ptr,
1429df49d7eSJed Brown             Self::SomeQFunctionByName(qfunc) => qfunc.qf_core.ptr,
1439df49d7eSJed Brown             Self::None => unsafe { bind_ceed::CEED_QFUNCTION_NONE },
1449df49d7eSJed Brown         }
1459df49d7eSJed Brown     }
146e03682afSJeremy L Thompson 
147e03682afSJeremy L Thompson     /// Check if a QFunctionOpt is Some
148e03682afSJeremy L Thompson     ///
149e03682afSJeremy L Thompson     /// ```
150e03682afSJeremy L Thompson     /// # use libceed::prelude::*;
1514d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
152e03682afSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
153e03682afSJeremy L Thompson     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
154e03682afSJeremy L Thompson     ///     // Iterate over quadrature points
155e03682afSJeremy L Thompson     ///     v.iter_mut()
156e03682afSJeremy L Thompson     ///         .zip(u.iter().zip(weights.iter()))
157e03682afSJeremy L Thompson     ///         .for_each(|(v, (u, w))| *v = u * w);
158e03682afSJeremy L Thompson     ///
159e03682afSJeremy L Thompson     ///     // Return clean error code
160e03682afSJeremy L Thompson     ///     0
161e03682afSJeremy L Thompson     /// };
162e03682afSJeremy L Thompson     ///
163e03682afSJeremy L Thompson     /// let qf = ceed
164e03682afSJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
165e03682afSJeremy L Thompson     ///     .input("u", 1, EvalMode::Interp)?
166e03682afSJeremy L Thompson     ///     .input("weights", 1, EvalMode::Weight)?
167e03682afSJeremy L Thompson     ///     .output("v", 1, EvalMode::Interp)?;
168e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
169e03682afSJeremy L Thompson     /// assert!(qf_opt.is_some(), "Incorrect QFunctionOpt");
170e03682afSJeremy L Thompson     ///
171e03682afSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
172e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
173e03682afSJeremy L Thompson     /// assert!(qf_opt.is_some(), "Incorrect QFunctionOpt");
174e03682afSJeremy L Thompson     ///
175e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::None;
176e03682afSJeremy L Thompson     /// assert!(!qf_opt.is_some(), "Incorrect QFunctionOpt");
177e03682afSJeremy L Thompson     /// # Ok(())
178e03682afSJeremy L Thompson     /// # }
179e03682afSJeremy L Thompson     /// ```
180e03682afSJeremy L Thompson     pub fn is_some(&self) -> bool {
181e03682afSJeremy L Thompson         match self {
182e03682afSJeremy L Thompson             Self::SomeQFunction(_) => true,
183e03682afSJeremy L Thompson             Self::SomeQFunctionByName(_) => true,
184e03682afSJeremy L Thompson             Self::None => false,
185e03682afSJeremy L Thompson         }
186e03682afSJeremy L Thompson     }
187e03682afSJeremy L Thompson 
188e03682afSJeremy L Thompson     /// Check if a QFunctionOpt is SomeQFunction
189e03682afSJeremy L Thompson     ///
190e03682afSJeremy L Thompson     /// ```
191e03682afSJeremy L Thompson     /// # use libceed::prelude::*;
1924d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
193e03682afSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
194e03682afSJeremy L Thompson     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
195e03682afSJeremy L Thompson     ///     // Iterate over quadrature points
196e03682afSJeremy L Thompson     ///     v.iter_mut()
197e03682afSJeremy L Thompson     ///         .zip(u.iter().zip(weights.iter()))
198e03682afSJeremy L Thompson     ///         .for_each(|(v, (u, w))| *v = u * w);
199e03682afSJeremy L Thompson     ///
200e03682afSJeremy L Thompson     ///     // Return clean error code
201e03682afSJeremy L Thompson     ///     0
202e03682afSJeremy L Thompson     /// };
203e03682afSJeremy L Thompson     ///
204e03682afSJeremy L Thompson     /// let qf = ceed
205e03682afSJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
206e03682afSJeremy L Thompson     ///     .input("u", 1, EvalMode::Interp)?
207e03682afSJeremy L Thompson     ///     .input("weights", 1, EvalMode::Weight)?
208e03682afSJeremy L Thompson     ///     .output("v", 1, EvalMode::Interp)?;
209e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
210e03682afSJeremy L Thompson     /// assert!(qf_opt.is_some_q_function(), "Incorrect QFunctionOpt");
211e03682afSJeremy L Thompson     ///
212e03682afSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
213e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
214e03682afSJeremy L Thompson     /// assert!(!qf_opt.is_some_q_function(), "Incorrect QFunctionOpt");
215e03682afSJeremy L Thompson     ///
216e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::None;
217e03682afSJeremy L Thompson     /// assert!(!qf_opt.is_some_q_function(), "Incorrect QFunctionOpt");
218e03682afSJeremy L Thompson     /// # Ok(())
219e03682afSJeremy L Thompson     /// # }
220e03682afSJeremy L Thompson     /// ```
221e03682afSJeremy L Thompson     pub fn is_some_q_function(&self) -> bool {
222e03682afSJeremy L Thompson         match self {
223e03682afSJeremy L Thompson             Self::SomeQFunction(_) => true,
224e03682afSJeremy L Thompson             Self::SomeQFunctionByName(_) => false,
225e03682afSJeremy L Thompson             Self::None => false,
226e03682afSJeremy L Thompson         }
227e03682afSJeremy L Thompson     }
228e03682afSJeremy L Thompson 
229e03682afSJeremy L Thompson     /// Check if a QFunctionOpt is SomeQFunctionByName
230e03682afSJeremy L Thompson     ///
231e03682afSJeremy L Thompson     /// ```
232e03682afSJeremy L Thompson     /// # use libceed::prelude::*;
2334d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
234e03682afSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
235e03682afSJeremy L Thompson     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
236e03682afSJeremy L Thompson     ///     // Iterate over quadrature points
237e03682afSJeremy L Thompson     ///     v.iter_mut()
238e03682afSJeremy L Thompson     ///         .zip(u.iter().zip(weights.iter()))
239e03682afSJeremy L Thompson     ///         .for_each(|(v, (u, w))| *v = u * w);
240e03682afSJeremy L Thompson     ///
241e03682afSJeremy L Thompson     ///     // Return clean error code
242e03682afSJeremy L Thompson     ///     0
243e03682afSJeremy L Thompson     /// };
244e03682afSJeremy L Thompson     ///
245e03682afSJeremy L Thompson     /// let qf = ceed
246e03682afSJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
247e03682afSJeremy L Thompson     ///     .input("u", 1, EvalMode::Interp)?
248e03682afSJeremy L Thompson     ///     .input("weights", 1, EvalMode::Weight)?
249e03682afSJeremy L Thompson     ///     .output("v", 1, EvalMode::Interp)?;
250e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
251e03682afSJeremy L Thompson     /// assert!(
252e03682afSJeremy L Thompson     ///     !qf_opt.is_some_q_function_by_name(),
253e03682afSJeremy L Thompson     ///     "Incorrect QFunctionOpt"
254e03682afSJeremy L Thompson     /// );
255e03682afSJeremy L Thompson     ///
256e03682afSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
257e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
258e03682afSJeremy L Thompson     /// assert!(
259e03682afSJeremy L Thompson     ///     qf_opt.is_some_q_function_by_name(),
260e03682afSJeremy L Thompson     ///     "Incorrect QFunctionOpt"
261e03682afSJeremy L Thompson     /// );
262e03682afSJeremy L Thompson     ///
263e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::None;
264e03682afSJeremy L Thompson     /// assert!(
265e03682afSJeremy L Thompson     ///     !qf_opt.is_some_q_function_by_name(),
266e03682afSJeremy L Thompson     ///     "Incorrect QFunctionOpt"
267e03682afSJeremy L Thompson     /// );
268e03682afSJeremy L Thompson     /// # Ok(())
269e03682afSJeremy L Thompson     /// # }
270e03682afSJeremy L Thompson     /// ```
271e03682afSJeremy L Thompson     pub fn is_some_q_function_by_name(&self) -> bool {
272e03682afSJeremy L Thompson         match self {
273e03682afSJeremy L Thompson             Self::SomeQFunction(_) => false,
274e03682afSJeremy L Thompson             Self::SomeQFunctionByName(_) => true,
275e03682afSJeremy L Thompson             Self::None => false,
276e03682afSJeremy L Thompson         }
277e03682afSJeremy L Thompson     }
278e03682afSJeremy L Thompson 
279e03682afSJeremy L Thompson     /// Check if a QFunctionOpt is None
280e03682afSJeremy L Thompson     ///
281e03682afSJeremy L Thompson     /// ```
282e03682afSJeremy L Thompson     /// # use libceed::prelude::*;
2834d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
284e03682afSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
285e03682afSJeremy L Thompson     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
286e03682afSJeremy L Thompson     ///     // Iterate over quadrature points
287e03682afSJeremy L Thompson     ///     v.iter_mut()
288e03682afSJeremy L Thompson     ///         .zip(u.iter().zip(weights.iter()))
289e03682afSJeremy L Thompson     ///         .for_each(|(v, (u, w))| *v = u * w);
290e03682afSJeremy L Thompson     ///
291e03682afSJeremy L Thompson     ///     // Return clean error code
292e03682afSJeremy L Thompson     ///     0
293e03682afSJeremy L Thompson     /// };
294e03682afSJeremy L Thompson     ///
295e03682afSJeremy L Thompson     /// let qf = ceed
296e03682afSJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
297e03682afSJeremy L Thompson     ///     .input("u", 1, EvalMode::Interp)?
298e03682afSJeremy L Thompson     ///     .input("weights", 1, EvalMode::Weight)?
299e03682afSJeremy L Thompson     ///     .output("v", 1, EvalMode::Interp)?;
300e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
301e03682afSJeremy L Thompson     /// assert!(!qf_opt.is_none(), "Incorrect QFunctionOpt");
302e03682afSJeremy L Thompson     ///
303e03682afSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
304e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
305e03682afSJeremy L Thompson     /// assert!(!qf_opt.is_none(), "Incorrect QFunctionOpt");
306e03682afSJeremy L Thompson     ///
307e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::None;
308e03682afSJeremy L Thompson     /// assert!(qf_opt.is_none(), "Incorrect QFunctionOpt");
309e03682afSJeremy L Thompson     /// # Ok(())
310e03682afSJeremy L Thompson     /// # }
311e03682afSJeremy L Thompson     /// ```
312e03682afSJeremy L Thompson     pub fn is_none(&self) -> bool {
313e03682afSJeremy L Thompson         match self {
314e03682afSJeremy L Thompson             Self::SomeQFunction(_) => false,
315e03682afSJeremy L Thompson             Self::SomeQFunctionByName(_) => false,
316e03682afSJeremy L Thompson             Self::None => true,
317e03682afSJeremy L Thompson         }
318e03682afSJeremy L Thompson     }
3199df49d7eSJed Brown }
3209df49d7eSJed Brown 
3219df49d7eSJed Brown // -----------------------------------------------------------------------------
3227ed177dbSJed Brown // QFunction context wrapper
3239df49d7eSJed Brown // -----------------------------------------------------------------------------
324c68be7a2SJeremy L Thompson #[derive(Debug)]
3259df49d7eSJed Brown pub(crate) struct QFunctionCore<'a> {
3269df49d7eSJed Brown     ptr: bind_ceed::CeedQFunction,
3271142270cSJeremy L Thompson     _lifeline: PhantomData<&'a ()>,
3289df49d7eSJed Brown }
3299df49d7eSJed Brown 
3309df49d7eSJed Brown struct QFunctionTrampolineData {
3319df49d7eSJed Brown     number_inputs: usize,
3329df49d7eSJed Brown     number_outputs: usize,
3339df49d7eSJed Brown     input_sizes: [usize; MAX_QFUNCTION_FIELDS],
3349df49d7eSJed Brown     output_sizes: [usize; MAX_QFUNCTION_FIELDS],
3359df49d7eSJed Brown     user_f: Box<QFunctionUserClosure>,
3369df49d7eSJed Brown }
3379df49d7eSJed Brown 
3389df49d7eSJed Brown pub struct QFunction<'a> {
3399df49d7eSJed Brown     qf_core: QFunctionCore<'a>,
3409df49d7eSJed Brown     qf_ctx_ptr: bind_ceed::CeedQFunctionContext,
3419df49d7eSJed Brown     trampoline_data: Pin<Box<QFunctionTrampolineData>>,
3429df49d7eSJed Brown }
3439df49d7eSJed Brown 
344c68be7a2SJeremy L Thompson #[derive(Debug)]
3459df49d7eSJed Brown pub struct QFunctionByName<'a> {
3469df49d7eSJed Brown     qf_core: QFunctionCore<'a>,
3479df49d7eSJed Brown }
3489df49d7eSJed Brown 
3499df49d7eSJed Brown // -----------------------------------------------------------------------------
3509df49d7eSJed Brown // Destructor
3519df49d7eSJed Brown // -----------------------------------------------------------------------------
3529df49d7eSJed Brown impl<'a> Drop for QFunctionCore<'a> {
3539df49d7eSJed Brown     fn drop(&mut self) {
3549df49d7eSJed Brown         unsafe {
3559df49d7eSJed Brown             if self.ptr != bind_ceed::CEED_QFUNCTION_NONE {
3569df49d7eSJed Brown                 bind_ceed::CeedQFunctionDestroy(&mut self.ptr);
3579df49d7eSJed Brown             }
3589df49d7eSJed Brown         }
3599df49d7eSJed Brown     }
3609df49d7eSJed Brown }
3619df49d7eSJed Brown 
3629df49d7eSJed Brown impl<'a> Drop for QFunction<'a> {
3639df49d7eSJed Brown     fn drop(&mut self) {
3649df49d7eSJed Brown         unsafe {
3659df49d7eSJed Brown             bind_ceed::CeedQFunctionContextDestroy(&mut self.qf_ctx_ptr);
3669df49d7eSJed Brown         }
3679df49d7eSJed Brown     }
3689df49d7eSJed Brown }
3699df49d7eSJed Brown 
3709df49d7eSJed Brown // -----------------------------------------------------------------------------
3719df49d7eSJed Brown // Display
3729df49d7eSJed Brown // -----------------------------------------------------------------------------
3739df49d7eSJed Brown impl<'a> fmt::Display for QFunctionCore<'a> {
3749df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3759df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
3769df49d7eSJed Brown         let mut sizeloc = crate::MAX_BUFFER_LENGTH;
3779df49d7eSJed Brown         let cstring = unsafe {
3789df49d7eSJed Brown             let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc);
3799df49d7eSJed Brown             bind_ceed::CeedQFunctionView(self.ptr, file);
3809df49d7eSJed Brown             bind_ceed::fclose(file);
3819df49d7eSJed Brown             CString::from_raw(ptr)
3829df49d7eSJed Brown         };
3839df49d7eSJed Brown         cstring.to_string_lossy().fmt(f)
3849df49d7eSJed Brown     }
3859df49d7eSJed Brown }
3869df49d7eSJed Brown /// View a QFunction
3879df49d7eSJed Brown ///
3889df49d7eSJed Brown /// ```
3899df49d7eSJed Brown /// # use libceed::prelude::*;
3904d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
3919df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
3929df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
3939df49d7eSJed Brown ///     // Iterate over quadrature points
3949df49d7eSJed Brown ///     v.iter_mut()
3959df49d7eSJed Brown ///         .zip(u.iter().zip(weights.iter()))
3969df49d7eSJed Brown ///         .for_each(|(v, (u, w))| *v = u * w);
3979df49d7eSJed Brown ///
3989df49d7eSJed Brown ///     // Return clean error code
3999df49d7eSJed Brown ///     0
4009df49d7eSJed Brown /// };
4019df49d7eSJed Brown ///
4029df49d7eSJed Brown /// let qf = ceed
403c68be7a2SJeremy L Thompson ///     .q_function_interior(1, Box::new(user_f))?
404c68be7a2SJeremy L Thompson ///     .input("u", 1, EvalMode::Interp)?
405c68be7a2SJeremy L Thompson ///     .input("weights", 1, EvalMode::Weight)?
406c68be7a2SJeremy L Thompson ///     .output("v", 1, EvalMode::Interp)?;
4079df49d7eSJed Brown ///
4089df49d7eSJed Brown /// println!("{}", qf);
409c68be7a2SJeremy L Thompson /// # Ok(())
410c68be7a2SJeremy L Thompson /// # }
4119df49d7eSJed Brown /// ```
4129df49d7eSJed Brown impl<'a> fmt::Display for QFunction<'a> {
4139df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4149df49d7eSJed Brown         self.qf_core.fmt(f)
4159df49d7eSJed Brown     }
4169df49d7eSJed Brown }
4179df49d7eSJed Brown 
4189df49d7eSJed Brown /// View a QFunction by Name
4199df49d7eSJed Brown ///
4209df49d7eSJed Brown /// ```
4219df49d7eSJed Brown /// # use libceed::prelude::*;
4224d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
4239df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
424c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
4259df49d7eSJed Brown /// println!("{}", qf);
426c68be7a2SJeremy L Thompson /// # Ok(())
427c68be7a2SJeremy L Thompson /// # }
4289df49d7eSJed Brown /// ```
4299df49d7eSJed Brown impl<'a> fmt::Display for QFunctionByName<'a> {
4309df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4319df49d7eSJed Brown         self.qf_core.fmt(f)
4329df49d7eSJed Brown     }
4339df49d7eSJed Brown }
4349df49d7eSJed Brown 
4359df49d7eSJed Brown // -----------------------------------------------------------------------------
4369df49d7eSJed Brown // Core functionality
4379df49d7eSJed Brown // -----------------------------------------------------------------------------
4389df49d7eSJed Brown impl<'a> QFunctionCore<'a> {
4391142270cSJeremy L Thompson     // Error handling
4401142270cSJeremy L Thompson     #[doc(hidden)]
4411142270cSJeremy L Thompson     fn check_error(&self, ierr: i32) -> crate::Result<i32> {
4421142270cSJeremy L Thompson         let mut ptr = std::ptr::null_mut();
4431142270cSJeremy L Thompson         unsafe {
4441142270cSJeremy L Thompson             bind_ceed::CeedQFunctionGetCeed(self.ptr, &mut ptr);
4451142270cSJeremy L Thompson         }
4461142270cSJeremy L Thompson         crate::check_error(ptr, ierr)
4471142270cSJeremy L Thompson     }
4481142270cSJeremy L Thompson 
4499df49d7eSJed Brown     // Common implementation
4509df49d7eSJed Brown     pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> {
4519df49d7eSJed Brown         let mut u_c = [std::ptr::null_mut(); MAX_QFUNCTION_FIELDS];
4529df49d7eSJed Brown         for i in 0..std::cmp::min(MAX_QFUNCTION_FIELDS, u.len()) {
4539df49d7eSJed Brown             u_c[i] = u[i].ptr;
4549df49d7eSJed Brown         }
4559df49d7eSJed Brown         let mut v_c = [std::ptr::null_mut(); MAX_QFUNCTION_FIELDS];
4569df49d7eSJed Brown         for i in 0..std::cmp::min(MAX_QFUNCTION_FIELDS, v.len()) {
4579df49d7eSJed Brown             v_c[i] = v[i].ptr;
4589df49d7eSJed Brown         }
4599df49d7eSJed Brown         let Q = i32::try_from(Q).unwrap();
4609df49d7eSJed Brown         let ierr = unsafe {
4619df49d7eSJed Brown             bind_ceed::CeedQFunctionApply(self.ptr, Q, u_c.as_mut_ptr(), v_c.as_mut_ptr())
4629df49d7eSJed Brown         };
4631142270cSJeremy L Thompson         self.check_error(ierr)
4649df49d7eSJed Brown     }
46508778c6fSJeremy L Thompson 
46608778c6fSJeremy L Thompson     pub fn inputs(&self) -> crate::Result<&[crate::QFunctionField]> {
46708778c6fSJeremy L Thompson         // Get array of raw C pointers for inputs
46808778c6fSJeremy L Thompson         let mut num_inputs = 0;
46908778c6fSJeremy L Thompson         let mut inputs_ptr = std::ptr::null_mut();
47008778c6fSJeremy L Thompson         let ierr = unsafe {
47108778c6fSJeremy L Thompson             bind_ceed::CeedQFunctionGetFields(
47208778c6fSJeremy L Thompson                 self.ptr,
47308778c6fSJeremy L Thompson                 &mut num_inputs,
47408778c6fSJeremy L Thompson                 &mut inputs_ptr,
47508778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut bind_ceed::CeedInt,
47608778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut *mut bind_ceed::CeedQFunctionField,
47708778c6fSJeremy L Thompson             )
47808778c6fSJeremy L Thompson         };
47908778c6fSJeremy L Thompson         self.check_error(ierr)?;
48008778c6fSJeremy L Thompson         // Convert raw C pointers to fixed length slice
48108778c6fSJeremy L Thompson         let inputs_slice = unsafe {
48208778c6fSJeremy L Thompson             std::slice::from_raw_parts(
48308778c6fSJeremy L Thompson                 inputs_ptr as *const crate::QFunctionField,
48408778c6fSJeremy L Thompson                 num_inputs as usize,
48508778c6fSJeremy L Thompson             )
48608778c6fSJeremy L Thompson         };
48708778c6fSJeremy L Thompson         Ok(inputs_slice)
48808778c6fSJeremy L Thompson     }
48908778c6fSJeremy L Thompson 
49008778c6fSJeremy L Thompson     pub fn outputs(&self) -> crate::Result<&[crate::QFunctionField]> {
49108778c6fSJeremy L Thompson         // Get array of raw C pointers for outputs
49208778c6fSJeremy L Thompson         let mut num_outputs = 0;
49308778c6fSJeremy L Thompson         let mut outputs_ptr = std::ptr::null_mut();
49408778c6fSJeremy L Thompson         let ierr = unsafe {
49508778c6fSJeremy L Thompson             bind_ceed::CeedQFunctionGetFields(
49608778c6fSJeremy L Thompson                 self.ptr,
49708778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut bind_ceed::CeedInt,
49808778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut *mut bind_ceed::CeedQFunctionField,
49908778c6fSJeremy L Thompson                 &mut num_outputs,
50008778c6fSJeremy L Thompson                 &mut outputs_ptr,
50108778c6fSJeremy L Thompson             )
50208778c6fSJeremy L Thompson         };
50308778c6fSJeremy L Thompson         self.check_error(ierr)?;
50408778c6fSJeremy L Thompson         // Convert raw C pointers to fixed length slice
50508778c6fSJeremy L Thompson         let outputs_slice = unsafe {
50608778c6fSJeremy L Thompson             std::slice::from_raw_parts(
50708778c6fSJeremy L Thompson                 outputs_ptr as *const crate::QFunctionField,
50808778c6fSJeremy L Thompson                 num_outputs as usize,
50908778c6fSJeremy L Thompson             )
51008778c6fSJeremy L Thompson         };
51108778c6fSJeremy L Thompson         Ok(outputs_slice)
51208778c6fSJeremy L Thompson     }
5139df49d7eSJed Brown }
5149df49d7eSJed Brown 
5159df49d7eSJed Brown // -----------------------------------------------------------------------------
5169df49d7eSJed Brown // User QFunction Closure
5179df49d7eSJed Brown // -----------------------------------------------------------------------------
51880a9ef05SNatalie Beams pub type QFunctionUserClosure = dyn FnMut(
51980a9ef05SNatalie Beams     [&[crate::Scalar]; MAX_QFUNCTION_FIELDS],
52080a9ef05SNatalie Beams     [&mut [crate::Scalar]; MAX_QFUNCTION_FIELDS],
52180a9ef05SNatalie Beams ) -> i32;
5229df49d7eSJed Brown 
5239df49d7eSJed Brown macro_rules! mut_max_fields {
5249df49d7eSJed Brown     ($e:expr) => {
5259df49d7eSJed Brown         [
5269df49d7eSJed Brown             $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e,
5279df49d7eSJed Brown         ]
5289df49d7eSJed Brown     };
5299df49d7eSJed Brown }
5309df49d7eSJed Brown unsafe extern "C" fn trampoline(
5319df49d7eSJed Brown     ctx: *mut ::std::os::raw::c_void,
5329df49d7eSJed Brown     q: bind_ceed::CeedInt,
5339df49d7eSJed Brown     inputs: *const *const bind_ceed::CeedScalar,
5349df49d7eSJed Brown     outputs: *const *mut bind_ceed::CeedScalar,
5359df49d7eSJed Brown ) -> ::std::os::raw::c_int {
5369df49d7eSJed Brown     let trampoline_data: Pin<&mut QFunctionTrampolineData> = std::mem::transmute(ctx);
5379df49d7eSJed Brown 
5389df49d7eSJed Brown     // Inputs
5399df49d7eSJed Brown     let inputs_slice: &[*const bind_ceed::CeedScalar] =
5409df49d7eSJed Brown         std::slice::from_raw_parts(inputs, MAX_QFUNCTION_FIELDS);
54180a9ef05SNatalie Beams     let mut inputs_array: [&[crate::Scalar]; MAX_QFUNCTION_FIELDS] = [&[0.0]; MAX_QFUNCTION_FIELDS];
5429df49d7eSJed Brown     inputs_slice
5439df49d7eSJed Brown         .iter()
5449df49d7eSJed Brown         .enumerate()
5459df49d7eSJed Brown         .map(|(i, &x)| {
54680a9ef05SNatalie Beams             std::slice::from_raw_parts(x, trampoline_data.input_sizes[i] * q as usize)
54780a9ef05SNatalie Beams                 as &[crate::Scalar]
5489df49d7eSJed Brown         })
5499df49d7eSJed Brown         .zip(inputs_array.iter_mut())
5509df49d7eSJed Brown         .for_each(|(x, a)| *a = x);
5519df49d7eSJed Brown 
5529df49d7eSJed Brown     // Outputs
5539df49d7eSJed Brown     let outputs_slice: &[*mut bind_ceed::CeedScalar] =
5549df49d7eSJed Brown         std::slice::from_raw_parts(outputs, MAX_QFUNCTION_FIELDS);
55580a9ef05SNatalie Beams     let mut outputs_array: [&mut [crate::Scalar]; MAX_QFUNCTION_FIELDS] =
55680a9ef05SNatalie Beams         mut_max_fields!(&mut [0.0]);
5579df49d7eSJed Brown     outputs_slice
5589df49d7eSJed Brown         .iter()
5599df49d7eSJed Brown         .enumerate()
5609df49d7eSJed Brown         .map(|(i, &x)| {
5619df49d7eSJed Brown             std::slice::from_raw_parts_mut(x, trampoline_data.output_sizes[i] * q as usize)
56280a9ef05SNatalie Beams                 as &mut [crate::Scalar]
5639df49d7eSJed Brown         })
5649df49d7eSJed Brown         .zip(outputs_array.iter_mut())
5659df49d7eSJed Brown         .for_each(|(x, a)| *a = x);
5669df49d7eSJed Brown 
5679df49d7eSJed Brown     // User closure
5689df49d7eSJed Brown     (trampoline_data.get_unchecked_mut().user_f)(inputs_array, outputs_array)
5699df49d7eSJed Brown }
5709df49d7eSJed Brown 
571a71fcd9fSJeremy L Thompson unsafe extern "C" fn destroy_trampoline(ctx: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int {
572a71fcd9fSJeremy L Thompson     let trampoline_data: Pin<&mut QFunctionTrampolineData> = std::mem::transmute(ctx);
573a71fcd9fSJeremy L Thompson     drop(trampoline_data);
574a71fcd9fSJeremy L Thompson     0 // Clean error code
575a71fcd9fSJeremy L Thompson }
576a71fcd9fSJeremy L Thompson 
5779df49d7eSJed Brown // -----------------------------------------------------------------------------
5789df49d7eSJed Brown // QFunction
5799df49d7eSJed Brown // -----------------------------------------------------------------------------
5809df49d7eSJed Brown impl<'a> QFunction<'a> {
5819df49d7eSJed Brown     // Constructor
5829df49d7eSJed Brown     pub fn create(
583594ef120SJeremy L Thompson         ceed: &crate::Ceed,
5849df49d7eSJed Brown         vlength: usize,
5859df49d7eSJed Brown         user_f: Box<QFunctionUserClosure>,
5869df49d7eSJed Brown     ) -> crate::Result<Self> {
5879df49d7eSJed Brown         let source_c = CString::new("").expect("CString::new failed");
5889df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
5899df49d7eSJed Brown 
5909df49d7eSJed Brown         // Context for closure
5919df49d7eSJed Brown         let number_inputs = 0;
5929df49d7eSJed Brown         let number_outputs = 0;
5939df49d7eSJed Brown         let input_sizes = [0; MAX_QFUNCTION_FIELDS];
5949df49d7eSJed Brown         let output_sizes = [0; MAX_QFUNCTION_FIELDS];
5959df49d7eSJed Brown         let trampoline_data = unsafe {
5969df49d7eSJed Brown             Pin::new_unchecked(Box::new(QFunctionTrampolineData {
5979df49d7eSJed Brown                 number_inputs,
5989df49d7eSJed Brown                 number_outputs,
5999df49d7eSJed Brown                 input_sizes,
6009df49d7eSJed Brown                 output_sizes,
6019df49d7eSJed Brown                 user_f,
6029df49d7eSJed Brown             }))
6039df49d7eSJed Brown         };
6049df49d7eSJed Brown 
6059df49d7eSJed Brown         // Create QFunction
6069df49d7eSJed Brown         let vlength = i32::try_from(vlength).unwrap();
6079df49d7eSJed Brown         let mut ierr = unsafe {
6089df49d7eSJed Brown             bind_ceed::CeedQFunctionCreateInterior(
6099df49d7eSJed Brown                 ceed.ptr,
6109df49d7eSJed Brown                 vlength,
6119df49d7eSJed Brown                 Some(trampoline),
6129df49d7eSJed Brown                 source_c.as_ptr(),
6139df49d7eSJed Brown                 &mut ptr,
6149df49d7eSJed Brown             )
6159df49d7eSJed Brown         };
6169df49d7eSJed Brown         ceed.check_error(ierr)?;
6179df49d7eSJed Brown 
6189df49d7eSJed Brown         // Set closure
6199df49d7eSJed Brown         let mut qf_ctx_ptr = std::ptr::null_mut();
6209df49d7eSJed Brown         ierr = unsafe { bind_ceed::CeedQFunctionContextCreate(ceed.ptr, &mut qf_ctx_ptr) };
6219df49d7eSJed Brown         ceed.check_error(ierr)?;
6229df49d7eSJed Brown         ierr = unsafe {
6239df49d7eSJed Brown             bind_ceed::CeedQFunctionContextSetData(
6249df49d7eSJed Brown                 qf_ctx_ptr,
6259df49d7eSJed Brown                 crate::MemType::Host as bind_ceed::CeedMemType,
6269df49d7eSJed Brown                 crate::CopyMode::UsePointer as bind_ceed::CeedCopyMode,
627*257916f8SJed Brown                 std::mem::size_of::<QFunctionTrampolineData>(),
6289df49d7eSJed Brown                 std::mem::transmute(trampoline_data.as_ref()),
6299df49d7eSJed Brown             )
6309df49d7eSJed Brown         };
6319df49d7eSJed Brown         ceed.check_error(ierr)?;
632a71fcd9fSJeremy L Thompson         ierr = unsafe {
633a71fcd9fSJeremy L Thompson             bind_ceed::CeedQFunctionContextSetDataDestroy(
634a71fcd9fSJeremy L Thompson                 qf_ctx_ptr,
635a71fcd9fSJeremy L Thompson                 crate::MemType::Host as bind_ceed::CeedMemType,
636a71fcd9fSJeremy L Thompson                 Some(destroy_trampoline),
637a71fcd9fSJeremy L Thompson             )
638a71fcd9fSJeremy L Thompson         };
639a71fcd9fSJeremy L Thompson         ceed.check_error(ierr)?;
6409df49d7eSJed Brown         ierr = unsafe { bind_ceed::CeedQFunctionSetContext(ptr, qf_ctx_ptr) };
6419df49d7eSJed Brown         ceed.check_error(ierr)?;
6429df49d7eSJed Brown         Ok(Self {
6431142270cSJeremy L Thompson             qf_core: QFunctionCore {
6441142270cSJeremy L Thompson                 ptr,
6451142270cSJeremy L Thompson                 _lifeline: PhantomData,
6461142270cSJeremy L Thompson             },
6479df49d7eSJed Brown             qf_ctx_ptr,
6489df49d7eSJed Brown             trampoline_data,
6499df49d7eSJed Brown         })
6509df49d7eSJed Brown     }
6519df49d7eSJed Brown 
6529df49d7eSJed Brown     /// Apply the action of a QFunction
6539df49d7eSJed Brown     ///
6549df49d7eSJed Brown     /// * `Q`      - The number of quadrature points
6559df49d7eSJed Brown     /// * `input`  - Array of input Vectors
6569df49d7eSJed Brown     /// * `output` - Array of output Vectors
6579df49d7eSJed Brown     ///
6589df49d7eSJed Brown     /// ```
6599df49d7eSJed Brown     /// # use libceed::prelude::*;
6604d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
6619df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
6629df49d7eSJed Brown     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
6639df49d7eSJed Brown     ///     // Iterate over quadrature points
6649df49d7eSJed Brown     ///     v.iter_mut()
6659df49d7eSJed Brown     ///         .zip(u.iter().zip(weights.iter()))
6669df49d7eSJed Brown     ///         .for_each(|(v, (u, w))| *v = u * w);
6679df49d7eSJed Brown     ///
6689df49d7eSJed Brown     ///     // Return clean error code
6699df49d7eSJed Brown     ///     0
6709df49d7eSJed Brown     /// };
6719df49d7eSJed Brown     ///
6729df49d7eSJed Brown     /// let qf = ceed
673c68be7a2SJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
674c68be7a2SJeremy L Thompson     ///     .input("u", 1, EvalMode::Interp)?
675c68be7a2SJeremy L Thompson     ///     .input("weights", 1, EvalMode::Weight)?
676c68be7a2SJeremy L Thompson     ///     .output("v", 1, EvalMode::Interp)?;
6779df49d7eSJed Brown     ///
6789df49d7eSJed Brown     /// const Q: usize = 8;
6799df49d7eSJed Brown     /// let mut w = [0.; Q];
6809df49d7eSJed Brown     /// let mut u = [0.; Q];
6819df49d7eSJed Brown     /// let mut v = [0.; Q];
6829df49d7eSJed Brown     ///
6839df49d7eSJed Brown     /// for i in 0..Q {
68480a9ef05SNatalie Beams     ///     let x = 2. * (i as Scalar) / ((Q as Scalar) - 1.) - 1.;
6859df49d7eSJed Brown     ///     u[i] = 2. + 3. * x + 5. * x * x;
6869df49d7eSJed Brown     ///     w[i] = 1. - x * x;
6879df49d7eSJed Brown     ///     v[i] = u[i] * w[i];
6889df49d7eSJed Brown     /// }
6899df49d7eSJed Brown     ///
690c68be7a2SJeremy L Thompson     /// let uu = ceed.vector_from_slice(&u)?;
691c68be7a2SJeremy L Thompson     /// let ww = ceed.vector_from_slice(&w)?;
692c68be7a2SJeremy L Thompson     /// let mut vv = ceed.vector(Q)?;
6939df49d7eSJed Brown     /// vv.set_value(0.0);
6949df49d7eSJed Brown     /// {
6959df49d7eSJed Brown     ///     let input = vec![uu, ww];
6969df49d7eSJed Brown     ///     let mut output = vec![vv];
697c68be7a2SJeremy L Thompson     ///     qf.apply(Q, &input, &output)?;
6989df49d7eSJed Brown     ///     vv = output.remove(0);
6999df49d7eSJed Brown     /// }
7009df49d7eSJed Brown     ///
701e78171edSJeremy L Thompson     /// vv.view()?
7029df49d7eSJed Brown     ///     .iter()
7039df49d7eSJed Brown     ///     .zip(v.iter())
7049df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
7059df49d7eSJed Brown     ///         assert_eq!(
7069df49d7eSJed Brown     ///             *computed, *actual,
7079df49d7eSJed Brown     ///             "Incorrect value in QFunction application"
7089df49d7eSJed Brown     ///         );
7099df49d7eSJed Brown     ///     });
710c68be7a2SJeremy L Thompson     /// # Ok(())
711c68be7a2SJeremy L Thompson     /// # }
7129df49d7eSJed Brown     /// ```
7139df49d7eSJed Brown     pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> {
7149df49d7eSJed Brown         self.qf_core.apply(Q, u, v)
7159df49d7eSJed Brown     }
7169df49d7eSJed Brown 
7179df49d7eSJed Brown     /// Add a QFunction input
7189df49d7eSJed Brown     ///
7199df49d7eSJed Brown     /// * `fieldname` - Name of QFunction field
7209df49d7eSJed Brown     /// * `size`      - Size of QFunction field, `(ncomp * dim)` for `Grad` or
7219df49d7eSJed Brown     ///                   `(ncomp * 1)` for `None`, `Interp`, and `Weight`
7229df49d7eSJed Brown     /// * `emode`     - `EvalMode::None` to use values directly, `EvalMode::Interp`
7239df49d7eSJed Brown     ///                   to use interpolated values, `EvalMode::Grad` to use
7249df49d7eSJed Brown     ///                   gradients, `EvalMode::Weight` to use quadrature weights
7259df49d7eSJed Brown     ///
7269df49d7eSJed Brown     /// ```
7279df49d7eSJed Brown     /// # use libceed::prelude::*;
7284d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
7299df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
7309df49d7eSJed Brown     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
7319df49d7eSJed Brown     ///     // Iterate over quadrature points
7329df49d7eSJed Brown     ///     v.iter_mut()
7339df49d7eSJed Brown     ///         .zip(u.iter().zip(weights.iter()))
7349df49d7eSJed Brown     ///         .for_each(|(v, (u, w))| *v = u * w);
7359df49d7eSJed Brown     ///
7369df49d7eSJed Brown     ///     // Return clean error code
7379df49d7eSJed Brown     ///     0
7389df49d7eSJed Brown     /// };
7399df49d7eSJed Brown     ///
740c68be7a2SJeremy L Thompson     /// let mut qf = ceed.q_function_interior(1, Box::new(user_f))?;
7419df49d7eSJed Brown     ///
742c68be7a2SJeremy L Thompson     /// qf = qf.input("u", 1, EvalMode::Interp)?;
743c68be7a2SJeremy L Thompson     /// qf = qf.input("weights", 1, EvalMode::Weight)?;
744c68be7a2SJeremy L Thompson     /// # Ok(())
745c68be7a2SJeremy L Thompson     /// # }
7469df49d7eSJed Brown     /// ```
7479df49d7eSJed Brown     pub fn input(
7489df49d7eSJed Brown         mut self,
7499df49d7eSJed Brown         fieldname: &str,
7509df49d7eSJed Brown         size: usize,
7519df49d7eSJed Brown         emode: crate::EvalMode,
7529df49d7eSJed Brown     ) -> crate::Result<Self> {
7539df49d7eSJed Brown         let name_c = CString::new(fieldname).expect("CString::new failed");
7549df49d7eSJed Brown         let idx = self.trampoline_data.number_inputs;
7559df49d7eSJed Brown         self.trampoline_data.input_sizes[idx] = size;
7569df49d7eSJed Brown         self.trampoline_data.number_inputs += 1;
7579df49d7eSJed Brown         let (size, emode) = (
7589df49d7eSJed Brown             i32::try_from(size).unwrap(),
7599df49d7eSJed Brown             emode as bind_ceed::CeedEvalMode,
7609df49d7eSJed Brown         );
7619df49d7eSJed Brown         let ierr = unsafe {
7629df49d7eSJed Brown             bind_ceed::CeedQFunctionAddInput(self.qf_core.ptr, name_c.as_ptr(), size, emode)
7639df49d7eSJed Brown         };
7641142270cSJeremy L Thompson         self.qf_core.check_error(ierr)?;
7659df49d7eSJed Brown         Ok(self)
7669df49d7eSJed Brown     }
7679df49d7eSJed Brown 
7689df49d7eSJed Brown     /// Add a QFunction output
7699df49d7eSJed Brown     ///
7709df49d7eSJed Brown     /// * `fieldname` - Name of QFunction field
7719df49d7eSJed Brown     /// * `size`      - Size of QFunction field, `(ncomp * dim)` for `Grad` or
7729df49d7eSJed Brown     ///                   `(ncomp * 1)` for `None` and `Interp`
7739df49d7eSJed Brown     /// * `emode`     - `EvalMode::None` to use values directly, `EvalMode::Interp`
7749df49d7eSJed Brown     ///                   to use interpolated values, `EvalMode::Grad` to use
7759df49d7eSJed Brown     ///                   gradients
7769df49d7eSJed Brown     ///
7779df49d7eSJed Brown     /// ```
7789df49d7eSJed Brown     /// # use libceed::prelude::*;
7794d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
7809df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
7819df49d7eSJed Brown     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
7829df49d7eSJed Brown     ///     // Iterate over quadrature points
7839df49d7eSJed Brown     ///     v.iter_mut()
7849df49d7eSJed Brown     ///         .zip(u.iter().zip(weights.iter()))
7859df49d7eSJed Brown     ///         .for_each(|(v, (u, w))| *v = u * w);
7869df49d7eSJed Brown     ///
7879df49d7eSJed Brown     ///     // Return clean error code
7889df49d7eSJed Brown     ///     0
7899df49d7eSJed Brown     /// };
7909df49d7eSJed Brown     ///
791c68be7a2SJeremy L Thompson     /// let mut qf = ceed.q_function_interior(1, Box::new(user_f))?;
7929df49d7eSJed Brown     ///
793c68be7a2SJeremy L Thompson     /// qf.output("v", 1, EvalMode::Interp)?;
794c68be7a2SJeremy L Thompson     /// # Ok(())
795c68be7a2SJeremy L Thompson     /// # }
7969df49d7eSJed Brown     /// ```
7979df49d7eSJed Brown     pub fn output(
7989df49d7eSJed Brown         mut self,
7999df49d7eSJed Brown         fieldname: &str,
8009df49d7eSJed Brown         size: usize,
8019df49d7eSJed Brown         emode: crate::EvalMode,
8029df49d7eSJed Brown     ) -> crate::Result<Self> {
8039df49d7eSJed Brown         let name_c = CString::new(fieldname).expect("CString::new failed");
8049df49d7eSJed Brown         let idx = self.trampoline_data.number_outputs;
8059df49d7eSJed Brown         self.trampoline_data.output_sizes[idx] = size;
8069df49d7eSJed Brown         self.trampoline_data.number_outputs += 1;
8079df49d7eSJed Brown         let (size, emode) = (
8089df49d7eSJed Brown             i32::try_from(size).unwrap(),
8099df49d7eSJed Brown             emode as bind_ceed::CeedEvalMode,
8109df49d7eSJed Brown         );
8119df49d7eSJed Brown         let ierr = unsafe {
8129df49d7eSJed Brown             bind_ceed::CeedQFunctionAddOutput(self.qf_core.ptr, name_c.as_ptr(), size, emode)
8139df49d7eSJed Brown         };
8141142270cSJeremy L Thompson         self.qf_core.check_error(ierr)?;
8159df49d7eSJed Brown         Ok(self)
8169df49d7eSJed Brown     }
81708778c6fSJeremy L Thompson 
81808778c6fSJeremy L Thompson     /// Get a slice of QFunction inputs
81908778c6fSJeremy L Thompson     ///
82008778c6fSJeremy L Thompson     /// ```
82108778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
8224d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
82308778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
82408778c6fSJeremy L Thompson     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
82508778c6fSJeremy L Thompson     ///     // Iterate over quadrature points
82608778c6fSJeremy L Thompson     ///     v.iter_mut()
82708778c6fSJeremy L Thompson     ///         .zip(u.iter().zip(weights.iter()))
82808778c6fSJeremy L Thompson     ///         .for_each(|(v, (u, w))| *v = u * w);
82908778c6fSJeremy L Thompson     ///
83008778c6fSJeremy L Thompson     ///     // Return clean error code
83108778c6fSJeremy L Thompson     ///     0
83208778c6fSJeremy L Thompson     /// };
83308778c6fSJeremy L Thompson     ///
83408778c6fSJeremy L Thompson     /// let mut qf = ceed
83508778c6fSJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
83608778c6fSJeremy L Thompson     ///     .input("u", 1, EvalMode::Interp)?
83708778c6fSJeremy L Thompson     ///     .input("weights", 1, EvalMode::Weight)?;
83808778c6fSJeremy L Thompson     ///
83908778c6fSJeremy L Thompson     /// let inputs = qf.inputs()?;
84008778c6fSJeremy L Thompson     ///
84108778c6fSJeremy L Thompson     /// assert_eq!(inputs.len(), 2, "Incorrect inputs array");
84208778c6fSJeremy L Thompson     /// # Ok(())
84308778c6fSJeremy L Thompson     /// # }
84408778c6fSJeremy L Thompson     /// ```
84508778c6fSJeremy L Thompson     pub fn inputs(&self) -> crate::Result<&[crate::QFunctionField]> {
84608778c6fSJeremy L Thompson         self.qf_core.inputs()
84708778c6fSJeremy L Thompson     }
84808778c6fSJeremy L Thompson 
84908778c6fSJeremy L Thompson     /// Get a slice of QFunction outputs
85008778c6fSJeremy L Thompson     ///
85108778c6fSJeremy L Thompson     /// ```
85208778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
8534d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
85408778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
85508778c6fSJeremy L Thompson     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
85608778c6fSJeremy L Thompson     ///     // Iterate over quadrature points
85708778c6fSJeremy L Thompson     ///     v.iter_mut()
85808778c6fSJeremy L Thompson     ///         .zip(u.iter().zip(weights.iter()))
85908778c6fSJeremy L Thompson     ///         .for_each(|(v, (u, w))| *v = u * w);
86008778c6fSJeremy L Thompson     ///
86108778c6fSJeremy L Thompson     ///     // Return clean error code
86208778c6fSJeremy L Thompson     ///     0
86308778c6fSJeremy L Thompson     /// };
86408778c6fSJeremy L Thompson     ///
86508778c6fSJeremy L Thompson     /// let mut qf = ceed
86608778c6fSJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
86708778c6fSJeremy L Thompson     ///     .output("v", 1, EvalMode::Interp)?;
86808778c6fSJeremy L Thompson     ///
86908778c6fSJeremy L Thompson     /// let outputs = qf.outputs()?;
87008778c6fSJeremy L Thompson     ///
87108778c6fSJeremy L Thompson     /// assert_eq!(outputs.len(), 1, "Incorrect outputs array");
87208778c6fSJeremy L Thompson     /// # Ok(())
87308778c6fSJeremy L Thompson     /// # }
87408778c6fSJeremy L Thompson     /// ```
87508778c6fSJeremy L Thompson     pub fn outputs(&self) -> crate::Result<&[crate::QFunctionField]> {
87608778c6fSJeremy L Thompson         self.qf_core.outputs()
87708778c6fSJeremy L Thompson     }
8789df49d7eSJed Brown }
8799df49d7eSJed Brown 
8809df49d7eSJed Brown // -----------------------------------------------------------------------------
8819df49d7eSJed Brown // QFunction
8829df49d7eSJed Brown // -----------------------------------------------------------------------------
8839df49d7eSJed Brown impl<'a> QFunctionByName<'a> {
8849df49d7eSJed Brown     // Constructor
885594ef120SJeremy L Thompson     pub fn create(ceed: &crate::Ceed, name: &str) -> crate::Result<Self> {
8869df49d7eSJed Brown         let name_c = CString::new(name).expect("CString::new failed");
8879df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
8889df49d7eSJed Brown         let ierr = unsafe {
8899df49d7eSJed Brown             bind_ceed::CeedQFunctionCreateInteriorByName(ceed.ptr, name_c.as_ptr(), &mut ptr)
8909df49d7eSJed Brown         };
8919df49d7eSJed Brown         ceed.check_error(ierr)?;
8929df49d7eSJed Brown         Ok(Self {
8931142270cSJeremy L Thompson             qf_core: QFunctionCore {
8941142270cSJeremy L Thompson                 ptr,
8951142270cSJeremy L Thompson                 _lifeline: PhantomData,
8961142270cSJeremy L Thompson             },
8979df49d7eSJed Brown         })
8989df49d7eSJed Brown     }
8999df49d7eSJed Brown 
9009df49d7eSJed Brown     /// Apply the action of a QFunction
9019df49d7eSJed Brown     ///
9029df49d7eSJed Brown     /// * `Q`      - The number of quadrature points
9039df49d7eSJed Brown     /// * `input`  - Array of input Vectors
9049df49d7eSJed Brown     /// * `output` - Array of output Vectors
9059df49d7eSJed Brown     ///
9069df49d7eSJed Brown     /// ```
9079df49d7eSJed Brown     /// # use libceed::prelude::*;
9084d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
9099df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
9109df49d7eSJed Brown     /// const Q: usize = 8;
911c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
912c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
9139df49d7eSJed Brown     ///
9149df49d7eSJed Brown     /// let mut j = [0.; Q];
9159df49d7eSJed Brown     /// let mut w = [0.; Q];
9169df49d7eSJed Brown     /// let mut u = [0.; Q];
9179df49d7eSJed Brown     /// let mut v = [0.; Q];
9189df49d7eSJed Brown     ///
9199df49d7eSJed Brown     /// for i in 0..Q {
92080a9ef05SNatalie Beams     ///     let x = 2. * (i as Scalar) / ((Q as Scalar) - 1.) - 1.;
9219df49d7eSJed Brown     ///     j[i] = 1.;
9229df49d7eSJed Brown     ///     w[i] = 1. - x * x;
9239df49d7eSJed Brown     ///     u[i] = 2. + 3. * x + 5. * x * x;
9249df49d7eSJed Brown     ///     v[i] = w[i] * u[i];
9259df49d7eSJed Brown     /// }
9269df49d7eSJed Brown     ///
927c68be7a2SJeremy L Thompson     /// let jj = ceed.vector_from_slice(&j)?;
928c68be7a2SJeremy L Thompson     /// let ww = ceed.vector_from_slice(&w)?;
929c68be7a2SJeremy L Thompson     /// let uu = ceed.vector_from_slice(&u)?;
930c68be7a2SJeremy L Thompson     /// let mut vv = ceed.vector(Q)?;
9319df49d7eSJed Brown     /// vv.set_value(0.0);
932c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(Q)?;
9339df49d7eSJed Brown     /// qdata.set_value(0.0);
9349df49d7eSJed Brown     ///
9359df49d7eSJed Brown     /// {
9369df49d7eSJed Brown     ///     let mut input = vec![jj, ww];
9379df49d7eSJed Brown     ///     let mut output = vec![qdata];
938c68be7a2SJeremy L Thompson     ///     qf_build.apply(Q, &input, &output)?;
9399df49d7eSJed Brown     ///     qdata = output.remove(0);
9409df49d7eSJed Brown     /// }
9419df49d7eSJed Brown     ///
9429df49d7eSJed Brown     /// {
9439df49d7eSJed Brown     ///     let mut input = vec![qdata, uu];
9449df49d7eSJed Brown     ///     let mut output = vec![vv];
945c68be7a2SJeremy L Thompson     ///     qf_mass.apply(Q, &input, &output)?;
9469df49d7eSJed Brown     ///     vv = output.remove(0);
9479df49d7eSJed Brown     /// }
9489df49d7eSJed Brown     ///
949e78171edSJeremy L Thompson     /// vv.view()?
9509df49d7eSJed Brown     ///     .iter()
9519df49d7eSJed Brown     ///     .zip(v.iter())
9529df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
9539df49d7eSJed Brown     ///         assert_eq!(
9549df49d7eSJed Brown     ///             *computed, *actual,
9559df49d7eSJed Brown     ///             "Incorrect value in QFunction application"
9569df49d7eSJed Brown     ///         );
9579df49d7eSJed Brown     ///     });
958c68be7a2SJeremy L Thompson     /// # Ok(())
959c68be7a2SJeremy L Thompson     /// # }
9609df49d7eSJed Brown     /// ```
9619df49d7eSJed Brown     pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> {
9629df49d7eSJed Brown         self.qf_core.apply(Q, u, v)
9639df49d7eSJed Brown     }
96408778c6fSJeremy L Thompson 
96508778c6fSJeremy L Thompson     /// Get a slice of QFunction inputs
96608778c6fSJeremy L Thompson     ///
96708778c6fSJeremy L Thompson     /// ```
96808778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
9694d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
97008778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
97108778c6fSJeremy L Thompson     /// const Q: usize = 8;
97208778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
97308778c6fSJeremy L Thompson     ///
97408778c6fSJeremy L Thompson     /// let inputs = qf.inputs()?;
97508778c6fSJeremy L Thompson     ///
97608778c6fSJeremy L Thompson     /// assert_eq!(inputs.len(), 2, "Incorrect inputs array");
97708778c6fSJeremy L Thompson     /// # Ok(())
97808778c6fSJeremy L Thompson     /// # }
97908778c6fSJeremy L Thompson     /// ```
98008778c6fSJeremy L Thompson     pub fn inputs(&self) -> crate::Result<&[crate::QFunctionField]> {
98108778c6fSJeremy L Thompson         self.qf_core.inputs()
98208778c6fSJeremy L Thompson     }
98308778c6fSJeremy L Thompson 
98408778c6fSJeremy L Thompson     /// Get a slice of QFunction outputs
98508778c6fSJeremy L Thompson     ///
98608778c6fSJeremy L Thompson     /// ```
98708778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
9884d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
98908778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
99008778c6fSJeremy L Thompson     /// const Q: usize = 8;
99108778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
99208778c6fSJeremy L Thompson     ///
99308778c6fSJeremy L Thompson     /// let outputs = qf.outputs()?;
99408778c6fSJeremy L Thompson     ///
99508778c6fSJeremy L Thompson     /// assert_eq!(outputs.len(), 1, "Incorrect outputs array");
99608778c6fSJeremy L Thompson     /// # Ok(())
99708778c6fSJeremy L Thompson     /// # }
99808778c6fSJeremy L Thompson     /// ```
99908778c6fSJeremy L Thompson     pub fn outputs(&self) -> crate::Result<&[crate::QFunctionField]> {
100008778c6fSJeremy L Thompson         self.qf_core.outputs()
100108778c6fSJeremy L Thompson     }
10029df49d7eSJed Brown }
10039df49d7eSJed Brown 
10049df49d7eSJed Brown // -----------------------------------------------------------------------------
1005