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.
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
13eb07d68fSJeremy L Thompson use crate::{prelude::*, vector::Vector, MAX_QFUNCTION_FIELDS};
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 /// ```
name(&self) -> &str4708778c6fSJeremy 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 {
506f8994e9SJeremy L Thompson bind_ceed::CeedQFunctionFieldGetName(
516f8994e9SJeremy L Thompson self.ptr,
526f8994e9SJeremy L Thompson &mut name_ptr as *const _ as *mut *const _,
536f8994e9SJeremy L Thompson );
5408778c6fSJeremy L Thompson }
5508778c6fSJeremy L Thompson unsafe { CStr::from_ptr(name_ptr) }.to_str().unwrap()
5608778c6fSJeremy L Thompson }
5708778c6fSJeremy L Thompson
5808778c6fSJeremy L Thompson /// Get the size of a QFunctionField
5908778c6fSJeremy L Thompson ///
6008778c6fSJeremy L Thompson /// ```
6108778c6fSJeremy L Thompson /// # use libceed::prelude::*;
624d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
6308778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init();
6408778c6fSJeremy L Thompson /// const Q: usize = 8;
6508778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass2DBuild")?;
6608778c6fSJeremy L Thompson ///
6708778c6fSJeremy L Thompson /// let inputs = qf.inputs()?;
6808778c6fSJeremy L Thompson ///
6908778c6fSJeremy L Thompson /// assert_eq!(inputs[0].size(), 4, "Incorrect input size");
7008778c6fSJeremy L Thompson /// assert_eq!(inputs[1].size(), 1, "Incorrect input size");
7108778c6fSJeremy L Thompson /// # Ok(())
7208778c6fSJeremy L Thompson /// # }
7308778c6fSJeremy L Thompson /// ```
size(&self) -> usize7408778c6fSJeremy L Thompson pub fn size(&self) -> usize {
7508778c6fSJeremy L Thompson let mut size = 0;
7608778c6fSJeremy L Thompson unsafe {
7708778c6fSJeremy L Thompson bind_ceed::CeedQFunctionFieldGetSize(self.ptr, &mut size);
7808778c6fSJeremy L Thompson }
7908778c6fSJeremy L Thompson usize::try_from(size).unwrap()
8008778c6fSJeremy L Thompson }
8108778c6fSJeremy L Thompson
8208778c6fSJeremy L Thompson /// Get the evaluation mode of a QFunctionField
8308778c6fSJeremy L Thompson ///
8408778c6fSJeremy L Thompson /// ```
85eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode};
864d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
8708778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init();
8808778c6fSJeremy L Thompson /// const Q: usize = 8;
8908778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass2DBuild")?;
9008778c6fSJeremy L Thompson ///
9108778c6fSJeremy L Thompson /// let inputs = qf.inputs()?;
9208778c6fSJeremy L Thompson ///
9308778c6fSJeremy L Thompson /// assert_eq!(
9408778c6fSJeremy L Thompson /// inputs[0].eval_mode(),
9508778c6fSJeremy L Thompson /// EvalMode::Grad,
9608778c6fSJeremy L Thompson /// "Incorrect input evaluation mode"
9708778c6fSJeremy L Thompson /// );
9808778c6fSJeremy L Thompson /// assert_eq!(
9908778c6fSJeremy L Thompson /// inputs[1].eval_mode(),
10008778c6fSJeremy L Thompson /// EvalMode::Weight,
10108778c6fSJeremy L Thompson /// "Incorrect input evaluation mode"
10208778c6fSJeremy L Thompson /// );
10308778c6fSJeremy L Thompson /// # Ok(())
10408778c6fSJeremy L Thompson /// # }
10508778c6fSJeremy L Thompson /// ```
eval_mode(&self) -> crate::EvalMode10608778c6fSJeremy L Thompson pub fn eval_mode(&self) -> crate::EvalMode {
10708778c6fSJeremy L Thompson let mut mode = 0;
10808778c6fSJeremy L Thompson unsafe {
10908778c6fSJeremy L Thompson bind_ceed::CeedQFunctionFieldGetEvalMode(self.ptr, &mut mode);
11008778c6fSJeremy L Thompson }
111bf55b007SJeremy L Thompson crate::EvalMode::from_u32(mode)
11208778c6fSJeremy L Thompson }
11308778c6fSJeremy L Thompson }
11408778c6fSJeremy L Thompson
11508778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
1167ed177dbSJed Brown // QFunction option
1179df49d7eSJed Brown // -----------------------------------------------------------------------------
1189df49d7eSJed Brown pub enum QFunctionOpt<'a> {
1199df49d7eSJed Brown SomeQFunction(&'a QFunction<'a>),
1209df49d7eSJed Brown SomeQFunctionByName(&'a QFunctionByName<'a>),
1219df49d7eSJed Brown None,
1229df49d7eSJed Brown }
1239df49d7eSJed Brown
1249df49d7eSJed Brown /// Construct a QFunctionOpt reference from a QFunction reference
1259df49d7eSJed Brown impl<'a> From<&'a QFunction<'_>> for QFunctionOpt<'a> {
from(qfunc: &'a QFunction) -> Self1269df49d7eSJed Brown fn from(qfunc: &'a QFunction) -> Self {
1279df49d7eSJed Brown debug_assert!(qfunc.qf_core.ptr != unsafe { bind_ceed::CEED_QFUNCTION_NONE });
1289df49d7eSJed Brown Self::SomeQFunction(qfunc)
1299df49d7eSJed Brown }
1309df49d7eSJed Brown }
1319df49d7eSJed Brown
1329df49d7eSJed Brown /// Construct a QFunctionOpt reference from a QFunction by Name reference
1339df49d7eSJed Brown impl<'a> From<&'a QFunctionByName<'_>> for QFunctionOpt<'a> {
from(qfunc: &'a QFunctionByName) -> Self1349df49d7eSJed Brown fn from(qfunc: &'a QFunctionByName) -> Self {
1359df49d7eSJed Brown debug_assert!(qfunc.qf_core.ptr != unsafe { bind_ceed::CEED_QFUNCTION_NONE });
1369df49d7eSJed Brown Self::SomeQFunctionByName(qfunc)
1379df49d7eSJed Brown }
1389df49d7eSJed Brown }
1399df49d7eSJed Brown
1409df49d7eSJed Brown impl<'a> QFunctionOpt<'a> {
1419df49d7eSJed Brown /// Transform a Rust libCEED QFunctionOpt into C libCEED CeedQFunction
to_raw(&self) -> bind_ceed::CeedQFunction14278c2cefaSJeremy L Thompson pub(crate) fn to_raw(&self) -> bind_ceed::CeedQFunction {
1439df49d7eSJed Brown match self {
1449df49d7eSJed Brown Self::SomeQFunction(qfunc) => qfunc.qf_core.ptr,
1459df49d7eSJed Brown Self::SomeQFunctionByName(qfunc) => qfunc.qf_core.ptr,
1469df49d7eSJed Brown Self::None => unsafe { bind_ceed::CEED_QFUNCTION_NONE },
1479df49d7eSJed Brown }
1489df49d7eSJed Brown }
149e03682afSJeremy L Thompson
150e03682afSJeremy L Thompson /// Check if a QFunctionOpt is Some
151e03682afSJeremy L Thompson ///
152e03682afSJeremy L Thompson /// ```
153eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOpt, QFunctionOutputs};
1544d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
155e03682afSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init();
156e03682afSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
157e03682afSJeremy L Thompson /// // Iterate over quadrature points
158e03682afSJeremy L Thompson /// v.iter_mut()
159e03682afSJeremy L Thompson /// .zip(u.iter().zip(weights.iter()))
160e03682afSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w);
161e03682afSJeremy L Thompson ///
162e03682afSJeremy L Thompson /// // Return clean error code
163e03682afSJeremy L Thompson /// 0
164e03682afSJeremy L Thompson /// };
165e03682afSJeremy L Thompson ///
166e03682afSJeremy L Thompson /// let qf = ceed
167e03682afSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))?
168e03682afSJeremy L Thompson /// .input("u", 1, EvalMode::Interp)?
169e03682afSJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)?
170e03682afSJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?;
171e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf);
172e03682afSJeremy L Thompson /// assert!(qf_opt.is_some(), "Incorrect QFunctionOpt");
173e03682afSJeremy L Thompson ///
174e03682afSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
175e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf);
176e03682afSJeremy L Thompson /// assert!(qf_opt.is_some(), "Incorrect QFunctionOpt");
177e03682afSJeremy L Thompson ///
178e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::None;
179e03682afSJeremy L Thompson /// assert!(!qf_opt.is_some(), "Incorrect QFunctionOpt");
180e03682afSJeremy L Thompson /// # Ok(())
181e03682afSJeremy L Thompson /// # }
182e03682afSJeremy L Thompson /// ```
is_some(&self) -> bool183e03682afSJeremy L Thompson pub fn is_some(&self) -> bool {
184e03682afSJeremy L Thompson match self {
185e03682afSJeremy L Thompson Self::SomeQFunction(_) => true,
186e03682afSJeremy L Thompson Self::SomeQFunctionByName(_) => true,
187e03682afSJeremy L Thompson Self::None => false,
188e03682afSJeremy L Thompson }
189e03682afSJeremy L Thompson }
190e03682afSJeremy L Thompson
191e03682afSJeremy L Thompson /// Check if a QFunctionOpt is SomeQFunction
192e03682afSJeremy L Thompson ///
193e03682afSJeremy L Thompson /// ```
194eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOpt, QFunctionOutputs};
1954d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
196e03682afSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init();
197e03682afSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
198e03682afSJeremy L Thompson /// // Iterate over quadrature points
199e03682afSJeremy L Thompson /// v.iter_mut()
200e03682afSJeremy L Thompson /// .zip(u.iter().zip(weights.iter()))
201e03682afSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w);
202e03682afSJeremy L Thompson ///
203e03682afSJeremy L Thompson /// // Return clean error code
204e03682afSJeremy L Thompson /// 0
205e03682afSJeremy L Thompson /// };
206e03682afSJeremy L Thompson ///
207e03682afSJeremy L Thompson /// let qf = ceed
208e03682afSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))?
209e03682afSJeremy L Thompson /// .input("u", 1, EvalMode::Interp)?
210e03682afSJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)?
211e03682afSJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?;
212e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf);
213e03682afSJeremy L Thompson /// assert!(qf_opt.is_some_q_function(), "Incorrect QFunctionOpt");
214e03682afSJeremy L Thompson ///
215e03682afSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
216e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf);
217e03682afSJeremy L Thompson /// assert!(!qf_opt.is_some_q_function(), "Incorrect QFunctionOpt");
218e03682afSJeremy L Thompson ///
219e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::None;
220e03682afSJeremy L Thompson /// assert!(!qf_opt.is_some_q_function(), "Incorrect QFunctionOpt");
221e03682afSJeremy L Thompson /// # Ok(())
222e03682afSJeremy L Thompson /// # }
223e03682afSJeremy L Thompson /// ```
is_some_q_function(&self) -> bool224e03682afSJeremy L Thompson pub fn is_some_q_function(&self) -> bool {
225e03682afSJeremy L Thompson match self {
226e03682afSJeremy L Thompson Self::SomeQFunction(_) => true,
227e03682afSJeremy L Thompson Self::SomeQFunctionByName(_) => false,
228e03682afSJeremy L Thompson Self::None => false,
229e03682afSJeremy L Thompson }
230e03682afSJeremy L Thompson }
231e03682afSJeremy L Thompson
232e03682afSJeremy L Thompson /// Check if a QFunctionOpt is SomeQFunctionByName
233e03682afSJeremy L Thompson ///
234e03682afSJeremy L Thompson /// ```
235eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOpt, QFunctionOutputs};
2364d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
237e03682afSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init();
238e03682afSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
239e03682afSJeremy L Thompson /// // Iterate over quadrature points
240e03682afSJeremy L Thompson /// v.iter_mut()
241e03682afSJeremy L Thompson /// .zip(u.iter().zip(weights.iter()))
242e03682afSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w);
243e03682afSJeremy L Thompson ///
244e03682afSJeremy L Thompson /// // Return clean error code
245e03682afSJeremy L Thompson /// 0
246e03682afSJeremy L Thompson /// };
247e03682afSJeremy L Thompson ///
248e03682afSJeremy L Thompson /// let qf = ceed
249e03682afSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))?
250e03682afSJeremy L Thompson /// .input("u", 1, EvalMode::Interp)?
251e03682afSJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)?
252e03682afSJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?;
253e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf);
254e03682afSJeremy L Thompson /// assert!(
255e03682afSJeremy L Thompson /// !qf_opt.is_some_q_function_by_name(),
256e03682afSJeremy L Thompson /// "Incorrect QFunctionOpt"
257e03682afSJeremy L Thompson /// );
258e03682afSJeremy L Thompson ///
259e03682afSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
260e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf);
261e03682afSJeremy L Thompson /// assert!(
262e03682afSJeremy L Thompson /// qf_opt.is_some_q_function_by_name(),
263e03682afSJeremy L Thompson /// "Incorrect QFunctionOpt"
264e03682afSJeremy L Thompson /// );
265e03682afSJeremy L Thompson ///
266e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::None;
267e03682afSJeremy L Thompson /// assert!(
268e03682afSJeremy L Thompson /// !qf_opt.is_some_q_function_by_name(),
269e03682afSJeremy L Thompson /// "Incorrect QFunctionOpt"
270e03682afSJeremy L Thompson /// );
271e03682afSJeremy L Thompson /// # Ok(())
272e03682afSJeremy L Thompson /// # }
273e03682afSJeremy L Thompson /// ```
is_some_q_function_by_name(&self) -> bool274e03682afSJeremy L Thompson pub fn is_some_q_function_by_name(&self) -> bool {
275e03682afSJeremy L Thompson match self {
276e03682afSJeremy L Thompson Self::SomeQFunction(_) => false,
277e03682afSJeremy L Thompson Self::SomeQFunctionByName(_) => true,
278e03682afSJeremy L Thompson Self::None => false,
279e03682afSJeremy L Thompson }
280e03682afSJeremy L Thompson }
281e03682afSJeremy L Thompson
282e03682afSJeremy L Thompson /// Check if a QFunctionOpt is None
283e03682afSJeremy L Thompson ///
284e03682afSJeremy L Thompson /// ```
285eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOpt, QFunctionOutputs};
2864d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
287e03682afSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init();
288e03682afSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
289e03682afSJeremy L Thompson /// // Iterate over quadrature points
290e03682afSJeremy L Thompson /// v.iter_mut()
291e03682afSJeremy L Thompson /// .zip(u.iter().zip(weights.iter()))
292e03682afSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w);
293e03682afSJeremy L Thompson ///
294e03682afSJeremy L Thompson /// // Return clean error code
295e03682afSJeremy L Thompson /// 0
296e03682afSJeremy L Thompson /// };
297e03682afSJeremy L Thompson ///
298e03682afSJeremy L Thompson /// let qf = ceed
299e03682afSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))?
300e03682afSJeremy L Thompson /// .input("u", 1, EvalMode::Interp)?
301e03682afSJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)?
302e03682afSJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?;
303e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf);
304e03682afSJeremy L Thompson /// assert!(!qf_opt.is_none(), "Incorrect QFunctionOpt");
305e03682afSJeremy L Thompson ///
306e03682afSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
307e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf);
308e03682afSJeremy L Thompson /// assert!(!qf_opt.is_none(), "Incorrect QFunctionOpt");
309e03682afSJeremy L Thompson ///
310e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::None;
311e03682afSJeremy L Thompson /// assert!(qf_opt.is_none(), "Incorrect QFunctionOpt");
312e03682afSJeremy L Thompson /// # Ok(())
313e03682afSJeremy L Thompson /// # }
314e03682afSJeremy L Thompson /// ```
is_none(&self) -> bool315e03682afSJeremy L Thompson pub fn is_none(&self) -> bool {
316e03682afSJeremy L Thompson match self {
317e03682afSJeremy L Thompson Self::SomeQFunction(_) => false,
318e03682afSJeremy L Thompson Self::SomeQFunctionByName(_) => false,
319e03682afSJeremy L Thompson Self::None => true,
320e03682afSJeremy L Thompson }
321e03682afSJeremy L Thompson }
3229df49d7eSJed Brown }
3239df49d7eSJed Brown
3249df49d7eSJed Brown // -----------------------------------------------------------------------------
3257ed177dbSJed Brown // QFunction context wrapper
3269df49d7eSJed Brown // -----------------------------------------------------------------------------
327c68be7a2SJeremy L Thompson #[derive(Debug)]
3289df49d7eSJed Brown pub(crate) struct QFunctionCore<'a> {
3299df49d7eSJed Brown ptr: bind_ceed::CeedQFunction,
3301142270cSJeremy L Thompson _lifeline: PhantomData<&'a ()>,
3319df49d7eSJed Brown }
3329df49d7eSJed Brown
3339df49d7eSJed Brown struct QFunctionTrampolineData {
3349df49d7eSJed Brown number_inputs: usize,
3359df49d7eSJed Brown number_outputs: usize,
3369df49d7eSJed Brown input_sizes: [usize; MAX_QFUNCTION_FIELDS],
3379df49d7eSJed Brown output_sizes: [usize; MAX_QFUNCTION_FIELDS],
3389df49d7eSJed Brown user_f: Box<QFunctionUserClosure>,
3399df49d7eSJed Brown }
3409df49d7eSJed Brown
3419df49d7eSJed Brown pub struct QFunction<'a> {
3429df49d7eSJed Brown qf_core: QFunctionCore<'a>,
3439df49d7eSJed Brown qf_ctx_ptr: bind_ceed::CeedQFunctionContext,
3449df49d7eSJed Brown trampoline_data: Pin<Box<QFunctionTrampolineData>>,
3459df49d7eSJed Brown }
3469df49d7eSJed Brown
347c68be7a2SJeremy L Thompson #[derive(Debug)]
3489df49d7eSJed Brown pub struct QFunctionByName<'a> {
3499df49d7eSJed Brown qf_core: QFunctionCore<'a>,
3509df49d7eSJed Brown }
3519df49d7eSJed Brown
3529df49d7eSJed Brown // -----------------------------------------------------------------------------
3539df49d7eSJed Brown // Destructor
3549df49d7eSJed Brown // -----------------------------------------------------------------------------
3559df49d7eSJed Brown impl<'a> Drop for QFunctionCore<'a> {
drop(&mut self)3569df49d7eSJed Brown fn drop(&mut self) {
3579df49d7eSJed Brown unsafe {
3589df49d7eSJed Brown if self.ptr != bind_ceed::CEED_QFUNCTION_NONE {
3599df49d7eSJed Brown bind_ceed::CeedQFunctionDestroy(&mut self.ptr);
3609df49d7eSJed Brown }
3619df49d7eSJed Brown }
3629df49d7eSJed Brown }
3639df49d7eSJed Brown }
3649df49d7eSJed Brown
3659df49d7eSJed Brown impl<'a> Drop for QFunction<'a> {
drop(&mut self)3669df49d7eSJed Brown fn drop(&mut self) {
3679df49d7eSJed Brown unsafe {
3689df49d7eSJed Brown bind_ceed::CeedQFunctionContextDestroy(&mut self.qf_ctx_ptr);
3699df49d7eSJed Brown }
3709df49d7eSJed Brown }
3719df49d7eSJed Brown }
3729df49d7eSJed Brown
3739df49d7eSJed Brown // -----------------------------------------------------------------------------
3749df49d7eSJed Brown // Display
3759df49d7eSJed Brown // -----------------------------------------------------------------------------
3769df49d7eSJed Brown impl<'a> fmt::Display for QFunctionCore<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result3779df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3789df49d7eSJed Brown let mut ptr = std::ptr::null_mut();
3799df49d7eSJed Brown let mut sizeloc = crate::MAX_BUFFER_LENGTH;
3809df49d7eSJed Brown let cstring = unsafe {
3819df49d7eSJed Brown let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc);
3829df49d7eSJed Brown bind_ceed::CeedQFunctionView(self.ptr, file);
3839df49d7eSJed Brown bind_ceed::fclose(file);
3849df49d7eSJed Brown CString::from_raw(ptr)
3859df49d7eSJed Brown };
3869df49d7eSJed Brown cstring.to_string_lossy().fmt(f)
3879df49d7eSJed Brown }
3889df49d7eSJed Brown }
3899df49d7eSJed Brown /// View a QFunction
3909df49d7eSJed Brown ///
3919df49d7eSJed Brown /// ```
392eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs};
3934d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
3949df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
3959df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
3969df49d7eSJed Brown /// // Iterate over quadrature points
3979df49d7eSJed Brown /// v.iter_mut()
3989df49d7eSJed Brown /// .zip(u.iter().zip(weights.iter()))
3999df49d7eSJed Brown /// .for_each(|(v, (u, w))| *v = u * w);
4009df49d7eSJed Brown ///
4019df49d7eSJed Brown /// // Return clean error code
4029df49d7eSJed Brown /// 0
4039df49d7eSJed Brown /// };
4049df49d7eSJed Brown ///
4059df49d7eSJed Brown /// let qf = ceed
406c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))?
407c68be7a2SJeremy L Thompson /// .input("u", 1, EvalMode::Interp)?
408c68be7a2SJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)?
409c68be7a2SJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?;
4109df49d7eSJed Brown ///
4119df49d7eSJed Brown /// println!("{}", qf);
412c68be7a2SJeremy L Thompson /// # Ok(())
413c68be7a2SJeremy L Thompson /// # }
4149df49d7eSJed Brown /// ```
4159df49d7eSJed Brown impl<'a> fmt::Display for QFunction<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result4169df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4179df49d7eSJed Brown self.qf_core.fmt(f)
4189df49d7eSJed Brown }
4199df49d7eSJed Brown }
4209df49d7eSJed Brown
4219df49d7eSJed Brown /// View a QFunction by Name
4229df49d7eSJed Brown ///
4239df49d7eSJed Brown /// ```
4249df49d7eSJed Brown /// # use libceed::prelude::*;
4254d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
4269df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
427c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
4289df49d7eSJed Brown /// println!("{}", qf);
429c68be7a2SJeremy L Thompson /// # Ok(())
430c68be7a2SJeremy L Thompson /// # }
4319df49d7eSJed Brown /// ```
4329df49d7eSJed Brown impl<'a> fmt::Display for QFunctionByName<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result4339df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4349df49d7eSJed Brown self.qf_core.fmt(f)
4359df49d7eSJed Brown }
4369df49d7eSJed Brown }
4379df49d7eSJed Brown
4389df49d7eSJed Brown // -----------------------------------------------------------------------------
4399df49d7eSJed Brown // Core functionality
4409df49d7eSJed Brown // -----------------------------------------------------------------------------
4419df49d7eSJed Brown impl<'a> QFunctionCore<'a> {
44211544396SJeremy L Thompson // Raw Ceed for error handling
44311544396SJeremy L Thompson #[doc(hidden)]
ceed(&self) -> bind_ceed::Ceed44411544396SJeremy L Thompson fn ceed(&self) -> bind_ceed::Ceed {
44511544396SJeremy L Thompson unsafe { bind_ceed::CeedQFunctionReturnCeed(self.ptr) }
44611544396SJeremy L Thompson }
44711544396SJeremy L Thompson
4481142270cSJeremy L Thompson // Error handling
4491142270cSJeremy L Thompson #[doc(hidden)]
check_error(&self, ierr: i32) -> crate::Result<i32>4501142270cSJeremy L Thompson fn check_error(&self, ierr: i32) -> crate::Result<i32> {
45111544396SJeremy L Thompson crate::check_error(|| self.ceed(), ierr)
4521142270cSJeremy L Thompson }
4531142270cSJeremy L Thompson
4549df49d7eSJed Brown // Common implementation
apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32>4559df49d7eSJed Brown pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> {
4569df49d7eSJed Brown let mut u_c = [std::ptr::null_mut(); MAX_QFUNCTION_FIELDS];
4579df49d7eSJed Brown for i in 0..std::cmp::min(MAX_QFUNCTION_FIELDS, u.len()) {
4589df49d7eSJed Brown u_c[i] = u[i].ptr;
4599df49d7eSJed Brown }
4609df49d7eSJed Brown let mut v_c = [std::ptr::null_mut(); MAX_QFUNCTION_FIELDS];
4619df49d7eSJed Brown for i in 0..std::cmp::min(MAX_QFUNCTION_FIELDS, v.len()) {
4629df49d7eSJed Brown v_c[i] = v[i].ptr;
4639df49d7eSJed Brown }
4649df49d7eSJed Brown let Q = i32::try_from(Q).unwrap();
465656ef1e5SJeremy L Thompson self.check_error(unsafe {
4669df49d7eSJed Brown bind_ceed::CeedQFunctionApply(self.ptr, Q, u_c.as_mut_ptr(), v_c.as_mut_ptr())
467656ef1e5SJeremy L Thompson })
4689df49d7eSJed Brown }
46908778c6fSJeremy L Thompson
inputs(&self) -> crate::Result<&[QFunctionField]>470eb07d68fSJeremy L Thompson pub fn inputs(&self) -> crate::Result<&[QFunctionField]> {
47108778c6fSJeremy L Thompson // Get array of raw C pointers for inputs
47208778c6fSJeremy L Thompson let mut num_inputs = 0;
47308778c6fSJeremy L Thompson let mut inputs_ptr = std::ptr::null_mut();
474656ef1e5SJeremy L Thompson self.check_error(unsafe {
47508778c6fSJeremy L Thompson bind_ceed::CeedQFunctionGetFields(
47608778c6fSJeremy L Thompson self.ptr,
47708778c6fSJeremy L Thompson &mut num_inputs,
47808778c6fSJeremy L Thompson &mut inputs_ptr,
47908778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt,
480bf55b007SJeremy L Thompson std::ptr::null_mut(),
48108778c6fSJeremy L Thompson )
482656ef1e5SJeremy L Thompson })?;
48308778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice
48408778c6fSJeremy L Thompson let inputs_slice = unsafe {
485eb07d68fSJeremy L Thompson std::slice::from_raw_parts(inputs_ptr as *const QFunctionField, num_inputs as usize)
48608778c6fSJeremy L Thompson };
48708778c6fSJeremy L Thompson Ok(inputs_slice)
48808778c6fSJeremy L Thompson }
48908778c6fSJeremy L Thompson
outputs(&self) -> crate::Result<&[QFunctionField]>490eb07d68fSJeremy L Thompson pub fn outputs(&self) -> crate::Result<&[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();
494656ef1e5SJeremy L Thompson self.check_error(unsafe {
49508778c6fSJeremy L Thompson bind_ceed::CeedQFunctionGetFields(
49608778c6fSJeremy L Thompson self.ptr,
49708778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt,
498bf55b007SJeremy L Thompson std::ptr::null_mut(),
49908778c6fSJeremy L Thompson &mut num_outputs,
50008778c6fSJeremy L Thompson &mut outputs_ptr,
50108778c6fSJeremy L Thompson )
502656ef1e5SJeremy L Thompson })?;
50308778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice
50408778c6fSJeremy L Thompson let outputs_slice = unsafe {
505eb07d68fSJeremy L Thompson std::slice::from_raw_parts(outputs_ptr as *const QFunctionField, num_outputs as usize)
50608778c6fSJeremy L Thompson };
50708778c6fSJeremy L Thompson Ok(outputs_slice)
50808778c6fSJeremy L Thompson }
5099df49d7eSJed Brown }
5109df49d7eSJed Brown
5119df49d7eSJed Brown // -----------------------------------------------------------------------------
5129df49d7eSJed Brown // User QFunction Closure
5139df49d7eSJed Brown // -----------------------------------------------------------------------------
51480a9ef05SNatalie Beams pub type QFunctionUserClosure = dyn FnMut(
51580a9ef05SNatalie Beams [&[crate::Scalar]; MAX_QFUNCTION_FIELDS],
51680a9ef05SNatalie Beams [&mut [crate::Scalar]; MAX_QFUNCTION_FIELDS],
51780a9ef05SNatalie Beams ) -> i32;
5189df49d7eSJed Brown
5199df49d7eSJed Brown macro_rules! mut_max_fields {
5209df49d7eSJed Brown ($e:expr) => {
5219df49d7eSJed Brown [
5229df49d7eSJed Brown $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e,
5239df49d7eSJed Brown ]
5249df49d7eSJed Brown };
5259df49d7eSJed Brown }
trampoline( ctx: *mut ::std::os::raw::c_void, q: bind_ceed::CeedInt, inputs: *const *const bind_ceed::CeedScalar, outputs: *const *mut bind_ceed::CeedScalar, ) -> ::std::os::raw::c_int5269df49d7eSJed Brown unsafe extern "C" fn trampoline(
5279df49d7eSJed Brown ctx: *mut ::std::os::raw::c_void,
5289df49d7eSJed Brown q: bind_ceed::CeedInt,
5299df49d7eSJed Brown inputs: *const *const bind_ceed::CeedScalar,
5309df49d7eSJed Brown outputs: *const *mut bind_ceed::CeedScalar,
5319df49d7eSJed Brown ) -> ::std::os::raw::c_int {
5329df49d7eSJed Brown let trampoline_data: Pin<&mut QFunctionTrampolineData> = std::mem::transmute(ctx);
5339df49d7eSJed Brown
5349df49d7eSJed Brown // Inputs
5359df49d7eSJed Brown let inputs_slice: &[*const bind_ceed::CeedScalar] =
5369df49d7eSJed Brown std::slice::from_raw_parts(inputs, MAX_QFUNCTION_FIELDS);
53780a9ef05SNatalie Beams let mut inputs_array: [&[crate::Scalar]; MAX_QFUNCTION_FIELDS] = [&[0.0]; MAX_QFUNCTION_FIELDS];
5389df49d7eSJed Brown inputs_slice
5399df49d7eSJed Brown .iter()
54058f118fdSJeremy L Thompson .take(trampoline_data.number_inputs)
5419df49d7eSJed Brown .enumerate()
5429df49d7eSJed Brown .map(|(i, &x)| {
54380a9ef05SNatalie Beams std::slice::from_raw_parts(x, trampoline_data.input_sizes[i] * q as usize)
54480a9ef05SNatalie Beams as &[crate::Scalar]
5459df49d7eSJed Brown })
5469df49d7eSJed Brown .zip(inputs_array.iter_mut())
5479df49d7eSJed Brown .for_each(|(x, a)| *a = x);
5489df49d7eSJed Brown
5499df49d7eSJed Brown // Outputs
5509df49d7eSJed Brown let outputs_slice: &[*mut bind_ceed::CeedScalar] =
5519df49d7eSJed Brown std::slice::from_raw_parts(outputs, MAX_QFUNCTION_FIELDS);
55280a9ef05SNatalie Beams let mut outputs_array: [&mut [crate::Scalar]; MAX_QFUNCTION_FIELDS] =
55380a9ef05SNatalie Beams mut_max_fields!(&mut [0.0]);
5549df49d7eSJed Brown outputs_slice
5559df49d7eSJed Brown .iter()
55658f118fdSJeremy L Thompson .take(trampoline_data.number_outputs)
5579df49d7eSJed Brown .enumerate()
5589df49d7eSJed Brown .map(|(i, &x)| {
5599df49d7eSJed Brown std::slice::from_raw_parts_mut(x, trampoline_data.output_sizes[i] * q as usize)
56080a9ef05SNatalie Beams as &mut [crate::Scalar]
5619df49d7eSJed Brown })
5629df49d7eSJed Brown .zip(outputs_array.iter_mut())
5639df49d7eSJed Brown .for_each(|(x, a)| *a = x);
5649df49d7eSJed Brown
5659df49d7eSJed Brown // User closure
5669df49d7eSJed Brown (trampoline_data.get_unchecked_mut().user_f)(inputs_array, outputs_array)
5679df49d7eSJed Brown }
5689df49d7eSJed Brown
5699df49d7eSJed Brown // -----------------------------------------------------------------------------
5709df49d7eSJed Brown // QFunction
5719df49d7eSJed Brown // -----------------------------------------------------------------------------
5729df49d7eSJed Brown impl<'a> QFunction<'a> {
5739df49d7eSJed Brown // Constructor
create( ceed: &crate::Ceed, vlength: usize, user_f: Box<QFunctionUserClosure>, ) -> crate::Result<Self>5749df49d7eSJed Brown pub fn create(
575594ef120SJeremy L Thompson ceed: &crate::Ceed,
5769df49d7eSJed Brown vlength: usize,
5779df49d7eSJed Brown user_f: Box<QFunctionUserClosure>,
5789df49d7eSJed Brown ) -> crate::Result<Self> {
5799df49d7eSJed Brown let source_c = CString::new("").expect("CString::new failed");
5809df49d7eSJed Brown let mut ptr = std::ptr::null_mut();
5819df49d7eSJed Brown
5829df49d7eSJed Brown // Context for closure
5839df49d7eSJed Brown let number_inputs = 0;
5849df49d7eSJed Brown let number_outputs = 0;
5859df49d7eSJed Brown let input_sizes = [0; MAX_QFUNCTION_FIELDS];
5869df49d7eSJed Brown let output_sizes = [0; MAX_QFUNCTION_FIELDS];
5879df49d7eSJed Brown let trampoline_data = unsafe {
5889df49d7eSJed Brown Pin::new_unchecked(Box::new(QFunctionTrampolineData {
5899df49d7eSJed Brown number_inputs,
5909df49d7eSJed Brown number_outputs,
5919df49d7eSJed Brown input_sizes,
5929df49d7eSJed Brown output_sizes,
5939df49d7eSJed Brown user_f,
5949df49d7eSJed Brown }))
5959df49d7eSJed Brown };
5969df49d7eSJed Brown
5979df49d7eSJed Brown // Create QFunction
5989df49d7eSJed Brown let vlength = i32::try_from(vlength).unwrap();
599656ef1e5SJeremy L Thompson ceed.check_error(unsafe {
6009df49d7eSJed Brown bind_ceed::CeedQFunctionCreateInterior(
6019df49d7eSJed Brown ceed.ptr,
6029df49d7eSJed Brown vlength,
6039df49d7eSJed Brown Some(trampoline),
6049df49d7eSJed Brown source_c.as_ptr(),
6059df49d7eSJed Brown &mut ptr,
6069df49d7eSJed Brown )
607656ef1e5SJeremy L Thompson })?;
6089df49d7eSJed Brown
6099df49d7eSJed Brown // Set closure
6109df49d7eSJed Brown let mut qf_ctx_ptr = std::ptr::null_mut();
611656ef1e5SJeremy L Thompson ceed.check_error(unsafe {
612656ef1e5SJeremy L Thompson bind_ceed::CeedQFunctionContextCreate(ceed.ptr, &mut qf_ctx_ptr)
613656ef1e5SJeremy L Thompson })?;
614656ef1e5SJeremy L Thompson ceed.check_error(unsafe {
6159df49d7eSJed Brown bind_ceed::CeedQFunctionContextSetData(
6169df49d7eSJed Brown qf_ctx_ptr,
6179df49d7eSJed Brown crate::MemType::Host as bind_ceed::CeedMemType,
6189df49d7eSJed Brown crate::CopyMode::UsePointer as bind_ceed::CeedCopyMode,
619257916f8SJed Brown std::mem::size_of::<QFunctionTrampolineData>(),
6209ab2bffdSJeremy L Thompson std::mem::transmute::<
6219ab2bffdSJeremy L Thompson std::pin::Pin<&QFunctionTrampolineData>,
6229ab2bffdSJeremy L Thompson *mut std::ffi::c_void,
6239ab2bffdSJeremy L Thompson >(trampoline_data.as_ref()),
624a71fcd9fSJeremy L Thompson )
625656ef1e5SJeremy L Thompson })?;
626656ef1e5SJeremy L Thompson ceed.check_error(unsafe { bind_ceed::CeedQFunctionSetContext(ptr, qf_ctx_ptr) })?;
627656ef1e5SJeremy L Thompson ceed.check_error(unsafe { bind_ceed::CeedQFunctionContextDestroy(&mut qf_ctx_ptr) })?;
6289df49d7eSJed Brown Ok(Self {
6291142270cSJeremy L Thompson qf_core: QFunctionCore {
6301142270cSJeremy L Thompson ptr,
6311142270cSJeremy L Thompson _lifeline: PhantomData,
6321142270cSJeremy L Thompson },
6339df49d7eSJed Brown qf_ctx_ptr,
6349df49d7eSJed Brown trampoline_data,
6359df49d7eSJed Brown })
6369df49d7eSJed Brown }
6379df49d7eSJed Brown
6389df49d7eSJed Brown /// Apply the action of a QFunction
6399df49d7eSJed Brown ///
6409df49d7eSJed Brown /// * `Q` - The number of quadrature points
6419df49d7eSJed Brown /// * `input` - Array of input Vectors
6429df49d7eSJed Brown /// * `output` - Array of output Vectors
6439df49d7eSJed Brown ///
6449df49d7eSJed Brown /// ```
645eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs, Scalar};
6464d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
6479df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
6489df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
6499df49d7eSJed Brown /// // Iterate over quadrature points
6509df49d7eSJed Brown /// v.iter_mut()
6519df49d7eSJed Brown /// .zip(u.iter().zip(weights.iter()))
6529df49d7eSJed Brown /// .for_each(|(v, (u, w))| *v = u * w);
6539df49d7eSJed Brown ///
6549df49d7eSJed Brown /// // Return clean error code
6559df49d7eSJed Brown /// 0
6569df49d7eSJed Brown /// };
6579df49d7eSJed Brown ///
6589df49d7eSJed Brown /// let qf = ceed
659c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))?
660c68be7a2SJeremy L Thompson /// .input("u", 1, EvalMode::Interp)?
661c68be7a2SJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)?
662c68be7a2SJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?;
6639df49d7eSJed Brown ///
6649df49d7eSJed Brown /// const Q: usize = 8;
6659df49d7eSJed Brown /// let mut w = [0.; Q];
6669df49d7eSJed Brown /// let mut u = [0.; Q];
6679df49d7eSJed Brown /// let mut v = [0.; Q];
6689df49d7eSJed Brown ///
6699df49d7eSJed Brown /// for i in 0..Q {
67080a9ef05SNatalie Beams /// let x = 2. * (i as Scalar) / ((Q as Scalar) - 1.) - 1.;
6719df49d7eSJed Brown /// u[i] = 2. + 3. * x + 5. * x * x;
6729df49d7eSJed Brown /// w[i] = 1. - x * x;
6739df49d7eSJed Brown /// v[i] = u[i] * w[i];
6749df49d7eSJed Brown /// }
6759df49d7eSJed Brown ///
676c68be7a2SJeremy L Thompson /// let uu = ceed.vector_from_slice(&u)?;
677c68be7a2SJeremy L Thompson /// let ww = ceed.vector_from_slice(&w)?;
678c68be7a2SJeremy L Thompson /// let mut vv = ceed.vector(Q)?;
6799df49d7eSJed Brown /// vv.set_value(0.0);
6809df49d7eSJed Brown /// {
6819df49d7eSJed Brown /// let input = vec![uu, ww];
6829df49d7eSJed Brown /// let mut output = vec![vv];
683c68be7a2SJeremy L Thompson /// qf.apply(Q, &input, &output)?;
6849df49d7eSJed Brown /// vv = output.remove(0);
6859df49d7eSJed Brown /// }
6869df49d7eSJed Brown ///
687e78171edSJeremy L Thompson /// vv.view()?
6889df49d7eSJed Brown /// .iter()
6899df49d7eSJed Brown /// .zip(v.iter())
6909df49d7eSJed Brown /// .for_each(|(computed, actual)| {
6919df49d7eSJed Brown /// assert_eq!(
6929df49d7eSJed Brown /// *computed, *actual,
6939df49d7eSJed Brown /// "Incorrect value in QFunction application"
6949df49d7eSJed Brown /// );
6959df49d7eSJed Brown /// });
696c68be7a2SJeremy L Thompson /// # Ok(())
697c68be7a2SJeremy L Thompson /// # }
6989df49d7eSJed Brown /// ```
apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32>6999df49d7eSJed Brown pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> {
7009df49d7eSJed Brown self.qf_core.apply(Q, u, v)
7019df49d7eSJed Brown }
7029df49d7eSJed Brown
7039df49d7eSJed Brown /// Add a QFunction input
7049df49d7eSJed Brown ///
7059df49d7eSJed Brown /// * `fieldname` - Name of QFunction field
7069df49d7eSJed Brown /// * `size` - Size of QFunction field, `(ncomp * dim)` for `Grad` or
7079df49d7eSJed Brown /// `(ncomp * 1)` for `None`, `Interp`, and `Weight`
7089df49d7eSJed Brown /// * `emode` - `EvalMode::None` to use values directly, `EvalMode::Interp`
7099df49d7eSJed Brown /// to use interpolated values, `EvalMode::Grad` to use
7109df49d7eSJed Brown /// gradients, `EvalMode::Weight` to use quadrature weights
7119df49d7eSJed Brown ///
7129df49d7eSJed Brown /// ```
713eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs};
7144d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
7159df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
7169df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
7179df49d7eSJed Brown /// // Iterate over quadrature points
7189df49d7eSJed Brown /// v.iter_mut()
7199df49d7eSJed Brown /// .zip(u.iter().zip(weights.iter()))
7209df49d7eSJed Brown /// .for_each(|(v, (u, w))| *v = u * w);
7219df49d7eSJed Brown ///
7229df49d7eSJed Brown /// // Return clean error code
7239df49d7eSJed Brown /// 0
7249df49d7eSJed Brown /// };
7259df49d7eSJed Brown ///
726c68be7a2SJeremy L Thompson /// let mut qf = ceed.q_function_interior(1, Box::new(user_f))?;
7279df49d7eSJed Brown ///
728c68be7a2SJeremy L Thompson /// qf = qf.input("u", 1, EvalMode::Interp)?;
729c68be7a2SJeremy L Thompson /// qf = qf.input("weights", 1, EvalMode::Weight)?;
730c68be7a2SJeremy L Thompson /// # Ok(())
731c68be7a2SJeremy L Thompson /// # }
7329df49d7eSJed Brown /// ```
input( mut self, fieldname: &str, size: usize, emode: crate::EvalMode, ) -> crate::Result<Self>7339df49d7eSJed Brown pub fn input(
7349df49d7eSJed Brown mut self,
7359df49d7eSJed Brown fieldname: &str,
7369df49d7eSJed Brown size: usize,
7379df49d7eSJed Brown emode: crate::EvalMode,
7389df49d7eSJed Brown ) -> crate::Result<Self> {
7399df49d7eSJed Brown let name_c = CString::new(fieldname).expect("CString::new failed");
7409df49d7eSJed Brown let idx = self.trampoline_data.number_inputs;
7419df49d7eSJed Brown self.trampoline_data.input_sizes[idx] = size;
7429df49d7eSJed Brown self.trampoline_data.number_inputs += 1;
7439df49d7eSJed Brown let (size, emode) = (
7449df49d7eSJed Brown i32::try_from(size).unwrap(),
7459df49d7eSJed Brown emode as bind_ceed::CeedEvalMode,
7469df49d7eSJed Brown );
747656ef1e5SJeremy L Thompson self.qf_core.check_error(unsafe {
7489df49d7eSJed Brown bind_ceed::CeedQFunctionAddInput(self.qf_core.ptr, name_c.as_ptr(), size, emode)
749656ef1e5SJeremy L Thompson })?;
7509df49d7eSJed Brown Ok(self)
7519df49d7eSJed Brown }
7529df49d7eSJed Brown
7539df49d7eSJed Brown /// Add a QFunction output
7549df49d7eSJed Brown ///
7559df49d7eSJed Brown /// * `fieldname` - Name of QFunction field
7569df49d7eSJed Brown /// * `size` - Size of QFunction field, `(ncomp * dim)` for `Grad` or
7579df49d7eSJed Brown /// `(ncomp * 1)` for `None` and `Interp`
7589df49d7eSJed Brown /// * `emode` - `EvalMode::None` to use values directly, `EvalMode::Interp`
7599df49d7eSJed Brown /// to use interpolated values, `EvalMode::Grad` to use
7609df49d7eSJed Brown /// gradients
7619df49d7eSJed Brown ///
7629df49d7eSJed Brown /// ```
763eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs};
7644d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
7659df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
7669df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
7679df49d7eSJed Brown /// // Iterate over quadrature points
7689df49d7eSJed Brown /// v.iter_mut()
7699df49d7eSJed Brown /// .zip(u.iter().zip(weights.iter()))
7709df49d7eSJed Brown /// .for_each(|(v, (u, w))| *v = u * w);
7719df49d7eSJed Brown ///
7729df49d7eSJed Brown /// // Return clean error code
7739df49d7eSJed Brown /// 0
7749df49d7eSJed Brown /// };
7759df49d7eSJed Brown ///
776c68be7a2SJeremy L Thompson /// let mut qf = ceed.q_function_interior(1, Box::new(user_f))?;
7779df49d7eSJed Brown ///
778c68be7a2SJeremy L Thompson /// qf.output("v", 1, EvalMode::Interp)?;
779c68be7a2SJeremy L Thompson /// # Ok(())
780c68be7a2SJeremy L Thompson /// # }
7819df49d7eSJed Brown /// ```
output( mut self, fieldname: &str, size: usize, emode: crate::EvalMode, ) -> crate::Result<Self>7829df49d7eSJed Brown pub fn output(
7839df49d7eSJed Brown mut self,
7849df49d7eSJed Brown fieldname: &str,
7859df49d7eSJed Brown size: usize,
7869df49d7eSJed Brown emode: crate::EvalMode,
7879df49d7eSJed Brown ) -> crate::Result<Self> {
7889df49d7eSJed Brown let name_c = CString::new(fieldname).expect("CString::new failed");
7899df49d7eSJed Brown let idx = self.trampoline_data.number_outputs;
7909df49d7eSJed Brown self.trampoline_data.output_sizes[idx] = size;
7919df49d7eSJed Brown self.trampoline_data.number_outputs += 1;
7929df49d7eSJed Brown let (size, emode) = (
7939df49d7eSJed Brown i32::try_from(size).unwrap(),
7949df49d7eSJed Brown emode as bind_ceed::CeedEvalMode,
7959df49d7eSJed Brown );
796656ef1e5SJeremy L Thompson self.qf_core.check_error(unsafe {
7979df49d7eSJed Brown bind_ceed::CeedQFunctionAddOutput(self.qf_core.ptr, name_c.as_ptr(), size, emode)
798656ef1e5SJeremy L Thompson })?;
7999df49d7eSJed Brown Ok(self)
8009df49d7eSJed Brown }
80108778c6fSJeremy L Thompson
80208778c6fSJeremy L Thompson /// Get a slice of QFunction inputs
80308778c6fSJeremy L Thompson ///
80408778c6fSJeremy L Thompson /// ```
805eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs};
8064d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
80708778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init();
80808778c6fSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
80908778c6fSJeremy L Thompson /// // Iterate over quadrature points
81008778c6fSJeremy L Thompson /// v.iter_mut()
81108778c6fSJeremy L Thompson /// .zip(u.iter().zip(weights.iter()))
81208778c6fSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w);
81308778c6fSJeremy L Thompson ///
81408778c6fSJeremy L Thompson /// // Return clean error code
81508778c6fSJeremy L Thompson /// 0
81608778c6fSJeremy L Thompson /// };
81708778c6fSJeremy L Thompson ///
81808778c6fSJeremy L Thompson /// let mut qf = ceed
81908778c6fSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))?
82008778c6fSJeremy L Thompson /// .input("u", 1, EvalMode::Interp)?
82108778c6fSJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)?;
82208778c6fSJeremy L Thompson ///
82308778c6fSJeremy L Thompson /// let inputs = qf.inputs()?;
82408778c6fSJeremy L Thompson ///
82508778c6fSJeremy L Thompson /// assert_eq!(inputs.len(), 2, "Incorrect inputs array");
82608778c6fSJeremy L Thompson /// # Ok(())
82708778c6fSJeremy L Thompson /// # }
82808778c6fSJeremy L Thompson /// ```
inputs(&self) -> crate::Result<&[QFunctionField]>829eb07d68fSJeremy L Thompson pub fn inputs(&self) -> crate::Result<&[QFunctionField]> {
83008778c6fSJeremy L Thompson self.qf_core.inputs()
83108778c6fSJeremy L Thompson }
83208778c6fSJeremy L Thompson
83308778c6fSJeremy L Thompson /// Get a slice of QFunction outputs
83408778c6fSJeremy L Thompson ///
83508778c6fSJeremy L Thompson /// ```
836eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs};
8374d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
83808778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init();
83908778c6fSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
84008778c6fSJeremy L Thompson /// // Iterate over quadrature points
84108778c6fSJeremy L Thompson /// v.iter_mut()
84208778c6fSJeremy L Thompson /// .zip(u.iter().zip(weights.iter()))
84308778c6fSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w);
84408778c6fSJeremy L Thompson ///
84508778c6fSJeremy L Thompson /// // Return clean error code
84608778c6fSJeremy L Thompson /// 0
84708778c6fSJeremy L Thompson /// };
84808778c6fSJeremy L Thompson ///
84908778c6fSJeremy L Thompson /// let mut qf = ceed
85008778c6fSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))?
85108778c6fSJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?;
85208778c6fSJeremy L Thompson ///
85308778c6fSJeremy L Thompson /// let outputs = qf.outputs()?;
85408778c6fSJeremy L Thompson ///
85508778c6fSJeremy L Thompson /// assert_eq!(outputs.len(), 1, "Incorrect outputs array");
85608778c6fSJeremy L Thompson /// # Ok(())
85708778c6fSJeremy L Thompson /// # }
85808778c6fSJeremy L Thompson /// ```
outputs(&self) -> crate::Result<&[QFunctionField]>859eb07d68fSJeremy L Thompson pub fn outputs(&self) -> crate::Result<&[QFunctionField]> {
86008778c6fSJeremy L Thompson self.qf_core.outputs()
86108778c6fSJeremy L Thompson }
8629df49d7eSJed Brown }
8639df49d7eSJed Brown
8649df49d7eSJed Brown // -----------------------------------------------------------------------------
8659df49d7eSJed Brown // QFunction
8669df49d7eSJed Brown // -----------------------------------------------------------------------------
8679df49d7eSJed Brown impl<'a> QFunctionByName<'a> {
8689df49d7eSJed Brown // Constructor
create(ceed: &crate::Ceed, name: &str) -> crate::Result<Self>869594ef120SJeremy L Thompson pub fn create(ceed: &crate::Ceed, name: &str) -> crate::Result<Self> {
8709df49d7eSJed Brown let name_c = CString::new(name).expect("CString::new failed");
8719df49d7eSJed Brown let mut ptr = std::ptr::null_mut();
872656ef1e5SJeremy L Thompson ceed.check_error(unsafe {
8739df49d7eSJed Brown bind_ceed::CeedQFunctionCreateInteriorByName(ceed.ptr, name_c.as_ptr(), &mut ptr)
874656ef1e5SJeremy L Thompson })?;
8759df49d7eSJed Brown Ok(Self {
8761142270cSJeremy L Thompson qf_core: QFunctionCore {
8771142270cSJeremy L Thompson ptr,
8781142270cSJeremy L Thompson _lifeline: PhantomData,
8791142270cSJeremy L Thompson },
8809df49d7eSJed Brown })
8819df49d7eSJed Brown }
8829df49d7eSJed Brown
8839df49d7eSJed Brown /// Apply the action of a QFunction
8849df49d7eSJed Brown ///
8859df49d7eSJed Brown /// * `Q` - The number of quadrature points
8869df49d7eSJed Brown /// * `input` - Array of input Vectors
8879df49d7eSJed Brown /// * `output` - Array of output Vectors
8889df49d7eSJed Brown ///
8899df49d7eSJed Brown /// ```
890eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs, Scalar};
8914d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
8929df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
8939df49d7eSJed Brown /// const Q: usize = 8;
894c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
895c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
8969df49d7eSJed Brown ///
8979df49d7eSJed Brown /// let mut j = [0.; Q];
8989df49d7eSJed Brown /// let mut w = [0.; Q];
8999df49d7eSJed Brown /// let mut u = [0.; Q];
9009df49d7eSJed Brown /// let mut v = [0.; Q];
9019df49d7eSJed Brown ///
9029df49d7eSJed Brown /// for i in 0..Q {
90380a9ef05SNatalie Beams /// let x = 2. * (i as Scalar) / ((Q as Scalar) - 1.) - 1.;
9049df49d7eSJed Brown /// j[i] = 1.;
9059df49d7eSJed Brown /// w[i] = 1. - x * x;
9069df49d7eSJed Brown /// u[i] = 2. + 3. * x + 5. * x * x;
9079df49d7eSJed Brown /// v[i] = w[i] * u[i];
9089df49d7eSJed Brown /// }
9099df49d7eSJed Brown ///
910c68be7a2SJeremy L Thompson /// let jj = ceed.vector_from_slice(&j)?;
911c68be7a2SJeremy L Thompson /// let ww = ceed.vector_from_slice(&w)?;
912c68be7a2SJeremy L Thompson /// let uu = ceed.vector_from_slice(&u)?;
913c68be7a2SJeremy L Thompson /// let mut vv = ceed.vector(Q)?;
9149df49d7eSJed Brown /// vv.set_value(0.0);
915c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(Q)?;
9169df49d7eSJed Brown /// qdata.set_value(0.0);
9179df49d7eSJed Brown ///
9189df49d7eSJed Brown /// {
9199df49d7eSJed Brown /// let mut input = vec![jj, ww];
9209df49d7eSJed Brown /// let mut output = vec![qdata];
921c68be7a2SJeremy L Thompson /// qf_build.apply(Q, &input, &output)?;
9229df49d7eSJed Brown /// qdata = output.remove(0);
9239df49d7eSJed Brown /// }
9249df49d7eSJed Brown ///
9259df49d7eSJed Brown /// {
9269df49d7eSJed Brown /// let mut input = vec![qdata, uu];
9279df49d7eSJed Brown /// let mut output = vec![vv];
928c68be7a2SJeremy L Thompson /// qf_mass.apply(Q, &input, &output)?;
9299df49d7eSJed Brown /// vv = output.remove(0);
9309df49d7eSJed Brown /// }
9319df49d7eSJed Brown ///
932e78171edSJeremy L Thompson /// vv.view()?
9339df49d7eSJed Brown /// .iter()
9349df49d7eSJed Brown /// .zip(v.iter())
9359df49d7eSJed Brown /// .for_each(|(computed, actual)| {
9369df49d7eSJed Brown /// assert_eq!(
9379df49d7eSJed Brown /// *computed, *actual,
9389df49d7eSJed Brown /// "Incorrect value in QFunction application"
9399df49d7eSJed Brown /// );
9409df49d7eSJed Brown /// });
941c68be7a2SJeremy L Thompson /// # Ok(())
942c68be7a2SJeremy L Thompson /// # }
9439df49d7eSJed Brown /// ```
apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32>9449df49d7eSJed Brown pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> {
9459df49d7eSJed Brown self.qf_core.apply(Q, u, v)
9469df49d7eSJed Brown }
94708778c6fSJeremy L Thompson
94808778c6fSJeremy L Thompson /// Get a slice of QFunction inputs
94908778c6fSJeremy L Thompson ///
95008778c6fSJeremy L Thompson /// ```
95108778c6fSJeremy L Thompson /// # use libceed::prelude::*;
9524d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
95308778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init();
95408778c6fSJeremy L Thompson /// const Q: usize = 8;
95508778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
95608778c6fSJeremy L Thompson ///
95708778c6fSJeremy L Thompson /// let inputs = qf.inputs()?;
95808778c6fSJeremy L Thompson ///
95908778c6fSJeremy L Thompson /// assert_eq!(inputs.len(), 2, "Incorrect inputs array");
96008778c6fSJeremy L Thompson /// # Ok(())
96108778c6fSJeremy L Thompson /// # }
96208778c6fSJeremy L Thompson /// ```
inputs(&self) -> crate::Result<&[QFunctionField]>963eb07d68fSJeremy L Thompson pub fn inputs(&self) -> crate::Result<&[QFunctionField]> {
96408778c6fSJeremy L Thompson self.qf_core.inputs()
96508778c6fSJeremy L Thompson }
96608778c6fSJeremy L Thompson
96708778c6fSJeremy L Thompson /// Get a slice of QFunction outputs
96808778c6fSJeremy L Thompson ///
96908778c6fSJeremy L Thompson /// ```
97008778c6fSJeremy L Thompson /// # use libceed::prelude::*;
9714d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
97208778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init();
97308778c6fSJeremy L Thompson /// const Q: usize = 8;
97408778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
97508778c6fSJeremy L Thompson ///
97608778c6fSJeremy L Thompson /// let outputs = qf.outputs()?;
97708778c6fSJeremy L Thompson ///
97808778c6fSJeremy L Thompson /// assert_eq!(outputs.len(), 1, "Incorrect outputs array");
97908778c6fSJeremy L Thompson /// # Ok(())
98008778c6fSJeremy L Thompson /// # }
98108778c6fSJeremy L Thompson /// ```
outputs(&self) -> crate::Result<&[QFunctionField]>982eb07d68fSJeremy L Thompson pub fn outputs(&self) -> crate::Result<&[QFunctionField]> {
98308778c6fSJeremy L Thompson self.qf_core.outputs()
98408778c6fSJeremy L Thompson }
9859df49d7eSJed Brown }
9869df49d7eSJed Brown
9879df49d7eSJed Brown // -----------------------------------------------------------------------------
988