xref: /libCEED/rust/libceed/src/qfunction.rs (revision e03682af89f4c0f5e8c281990d44146e81dbdd46)
19df49d7eSJed Brown // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
29df49d7eSJed Brown // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
39df49d7eSJed Brown // reserved. See files LICENSE and NOTICE for details.
49df49d7eSJed Brown //
59df49d7eSJed Brown // This file is part of CEED, a collection of benchmarks, miniapps, software
69df49d7eSJed Brown // libraries and APIs for efficient high-order finite element and spectral
79df49d7eSJed Brown // element discretizations for exascale applications. For more information and
89df49d7eSJed Brown // source code availability see http://github.com/ceed.
99df49d7eSJed Brown //
109df49d7eSJed Brown // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
119df49d7eSJed Brown // a collaborative effort of two U.S. Department of Energy organizations (Office
129df49d7eSJed Brown // of Science and the National Nuclear Security Administration) responsible for
139df49d7eSJed Brown // the planning and preparation of a capable exascale ecosystem, including
149df49d7eSJed Brown // software, applications, hardware, advanced system engineering and early
159df49d7eSJed Brown // testbed platforms, in support of the nation's exascale computing imperative
169df49d7eSJed Brown 
179df49d7eSJed Brown //! A Ceed QFunction represents the spatial terms of the point-wise functions
189df49d7eSJed Brown //! describing the physics at the quadrature points.
199df49d7eSJed Brown 
209df49d7eSJed Brown use std::pin::Pin;
219df49d7eSJed Brown 
229df49d7eSJed Brown use crate::prelude::*;
239df49d7eSJed Brown 
2480a9ef05SNatalie Beams pub type QFunctionInputs<'a> = [&'a [crate::Scalar]; MAX_QFUNCTION_FIELDS];
2580a9ef05SNatalie Beams pub type QFunctionOutputs<'a> = [&'a mut [crate::Scalar]; MAX_QFUNCTION_FIELDS];
269df49d7eSJed Brown 
279df49d7eSJed Brown // -----------------------------------------------------------------------------
289df49d7eSJed Brown // CeedQFunction option
299df49d7eSJed Brown // -----------------------------------------------------------------------------
309df49d7eSJed Brown pub enum QFunctionOpt<'a> {
319df49d7eSJed Brown     SomeQFunction(&'a QFunction<'a>),
329df49d7eSJed Brown     SomeQFunctionByName(&'a QFunctionByName<'a>),
339df49d7eSJed Brown     None,
349df49d7eSJed Brown }
359df49d7eSJed Brown 
369df49d7eSJed Brown /// Construct a QFunctionOpt reference from a QFunction reference
379df49d7eSJed Brown impl<'a> From<&'a QFunction<'_>> for QFunctionOpt<'a> {
389df49d7eSJed Brown     fn from(qfunc: &'a QFunction) -> Self {
399df49d7eSJed Brown         debug_assert!(qfunc.qf_core.ptr != unsafe { bind_ceed::CEED_QFUNCTION_NONE });
409df49d7eSJed Brown         Self::SomeQFunction(qfunc)
419df49d7eSJed Brown     }
429df49d7eSJed Brown }
439df49d7eSJed Brown 
449df49d7eSJed Brown /// Construct a QFunctionOpt reference from a QFunction by Name reference
459df49d7eSJed Brown impl<'a> From<&'a QFunctionByName<'_>> for QFunctionOpt<'a> {
469df49d7eSJed Brown     fn from(qfunc: &'a QFunctionByName) -> Self {
479df49d7eSJed Brown         debug_assert!(qfunc.qf_core.ptr != unsafe { bind_ceed::CEED_QFUNCTION_NONE });
489df49d7eSJed Brown         Self::SomeQFunctionByName(qfunc)
499df49d7eSJed Brown     }
509df49d7eSJed Brown }
519df49d7eSJed Brown 
529df49d7eSJed Brown impl<'a> QFunctionOpt<'a> {
539df49d7eSJed Brown     /// Transform a Rust libCEED QFunctionOpt into C libCEED CeedQFunction
549df49d7eSJed Brown     pub(crate) fn to_raw(self) -> bind_ceed::CeedQFunction {
559df49d7eSJed Brown         match self {
569df49d7eSJed Brown             Self::SomeQFunction(qfunc) => qfunc.qf_core.ptr,
579df49d7eSJed Brown             Self::SomeQFunctionByName(qfunc) => qfunc.qf_core.ptr,
589df49d7eSJed Brown             Self::None => unsafe { bind_ceed::CEED_QFUNCTION_NONE },
599df49d7eSJed Brown         }
609df49d7eSJed Brown     }
61*e03682afSJeremy L Thompson 
62*e03682afSJeremy L Thompson     /// Check if a QFunctionOpt is Some
63*e03682afSJeremy L Thompson     ///
64*e03682afSJeremy L Thompson     /// ```
65*e03682afSJeremy L Thompson     /// # use libceed::prelude::*;
66*e03682afSJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
67*e03682afSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
68*e03682afSJeremy L Thompson     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
69*e03682afSJeremy L Thompson     ///     // Iterate over quadrature points
70*e03682afSJeremy L Thompson     ///     v.iter_mut()
71*e03682afSJeremy L Thompson     ///         .zip(u.iter().zip(weights.iter()))
72*e03682afSJeremy L Thompson     ///         .for_each(|(v, (u, w))| *v = u * w);
73*e03682afSJeremy L Thompson     ///
74*e03682afSJeremy L Thompson     ///     // Return clean error code
75*e03682afSJeremy L Thompson     ///     0
76*e03682afSJeremy L Thompson     /// };
77*e03682afSJeremy L Thompson     ///
78*e03682afSJeremy L Thompson     /// let qf = ceed
79*e03682afSJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
80*e03682afSJeremy L Thompson     ///     .input("u", 1, EvalMode::Interp)?
81*e03682afSJeremy L Thompson     ///     .input("weights", 1, EvalMode::Weight)?
82*e03682afSJeremy L Thompson     ///     .output("v", 1, EvalMode::Interp)?;
83*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
84*e03682afSJeremy L Thompson     /// assert!(qf_opt.is_some(), "Incorrect QFunctionOpt");
85*e03682afSJeremy L Thompson     ///
86*e03682afSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
87*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
88*e03682afSJeremy L Thompson     /// assert!(qf_opt.is_some(), "Incorrect QFunctionOpt");
89*e03682afSJeremy L Thompson     ///
90*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::None;
91*e03682afSJeremy L Thompson     /// assert!(!qf_opt.is_some(), "Incorrect QFunctionOpt");
92*e03682afSJeremy L Thompson     /// # Ok(())
93*e03682afSJeremy L Thompson     /// # }
94*e03682afSJeremy L Thompson     /// ```
95*e03682afSJeremy L Thompson     pub fn is_some(&self) -> bool {
96*e03682afSJeremy L Thompson         match self {
97*e03682afSJeremy L Thompson             Self::SomeQFunction(_) => true,
98*e03682afSJeremy L Thompson             Self::SomeQFunctionByName(_) => true,
99*e03682afSJeremy L Thompson             Self::None => false,
100*e03682afSJeremy L Thompson         }
101*e03682afSJeremy L Thompson     }
102*e03682afSJeremy L Thompson 
103*e03682afSJeremy L Thompson     /// Check if a QFunctionOpt is SomeQFunction
104*e03682afSJeremy L Thompson     ///
105*e03682afSJeremy L Thompson     /// ```
106*e03682afSJeremy L Thompson     /// # use libceed::prelude::*;
107*e03682afSJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
108*e03682afSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
109*e03682afSJeremy L Thompson     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
110*e03682afSJeremy L Thompson     ///     // Iterate over quadrature points
111*e03682afSJeremy L Thompson     ///     v.iter_mut()
112*e03682afSJeremy L Thompson     ///         .zip(u.iter().zip(weights.iter()))
113*e03682afSJeremy L Thompson     ///         .for_each(|(v, (u, w))| *v = u * w);
114*e03682afSJeremy L Thompson     ///
115*e03682afSJeremy L Thompson     ///     // Return clean error code
116*e03682afSJeremy L Thompson     ///     0
117*e03682afSJeremy L Thompson     /// };
118*e03682afSJeremy L Thompson     ///
119*e03682afSJeremy L Thompson     /// let qf = ceed
120*e03682afSJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
121*e03682afSJeremy L Thompson     ///     .input("u", 1, EvalMode::Interp)?
122*e03682afSJeremy L Thompson     ///     .input("weights", 1, EvalMode::Weight)?
123*e03682afSJeremy L Thompson     ///     .output("v", 1, EvalMode::Interp)?;
124*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
125*e03682afSJeremy L Thompson     /// assert!(qf_opt.is_some_q_function(), "Incorrect QFunctionOpt");
126*e03682afSJeremy L Thompson     ///
127*e03682afSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
128*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
129*e03682afSJeremy L Thompson     /// assert!(!qf_opt.is_some_q_function(), "Incorrect QFunctionOpt");
130*e03682afSJeremy L Thompson     ///
131*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::None;
132*e03682afSJeremy L Thompson     /// assert!(!qf_opt.is_some_q_function(), "Incorrect QFunctionOpt");
133*e03682afSJeremy L Thompson     /// # Ok(())
134*e03682afSJeremy L Thompson     /// # }
135*e03682afSJeremy L Thompson     /// ```
136*e03682afSJeremy L Thompson     pub fn is_some_q_function(&self) -> bool {
137*e03682afSJeremy L Thompson         match self {
138*e03682afSJeremy L Thompson             Self::SomeQFunction(_) => true,
139*e03682afSJeremy L Thompson             Self::SomeQFunctionByName(_) => false,
140*e03682afSJeremy L Thompson             Self::None => false,
141*e03682afSJeremy L Thompson         }
142*e03682afSJeremy L Thompson     }
143*e03682afSJeremy L Thompson 
144*e03682afSJeremy L Thompson     /// Check if a QFunctionOpt is SomeQFunctionByName
145*e03682afSJeremy L Thompson     ///
146*e03682afSJeremy L Thompson     /// ```
147*e03682afSJeremy L Thompson     /// # use libceed::prelude::*;
148*e03682afSJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
149*e03682afSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
150*e03682afSJeremy L Thompson     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
151*e03682afSJeremy L Thompson     ///     // Iterate over quadrature points
152*e03682afSJeremy L Thompson     ///     v.iter_mut()
153*e03682afSJeremy L Thompson     ///         .zip(u.iter().zip(weights.iter()))
154*e03682afSJeremy L Thompson     ///         .for_each(|(v, (u, w))| *v = u * w);
155*e03682afSJeremy L Thompson     ///
156*e03682afSJeremy L Thompson     ///     // Return clean error code
157*e03682afSJeremy L Thompson     ///     0
158*e03682afSJeremy L Thompson     /// };
159*e03682afSJeremy L Thompson     ///
160*e03682afSJeremy L Thompson     /// let qf = ceed
161*e03682afSJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
162*e03682afSJeremy L Thompson     ///     .input("u", 1, EvalMode::Interp)?
163*e03682afSJeremy L Thompson     ///     .input("weights", 1, EvalMode::Weight)?
164*e03682afSJeremy L Thompson     ///     .output("v", 1, EvalMode::Interp)?;
165*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
166*e03682afSJeremy L Thompson     /// assert!(
167*e03682afSJeremy L Thompson     ///     !qf_opt.is_some_q_function_by_name(),
168*e03682afSJeremy L Thompson     ///     "Incorrect QFunctionOpt"
169*e03682afSJeremy L Thompson     /// );
170*e03682afSJeremy L Thompson     ///
171*e03682afSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
172*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
173*e03682afSJeremy L Thompson     /// assert!(
174*e03682afSJeremy L Thompson     ///     qf_opt.is_some_q_function_by_name(),
175*e03682afSJeremy L Thompson     ///     "Incorrect QFunctionOpt"
176*e03682afSJeremy L Thompson     /// );
177*e03682afSJeremy L Thompson     ///
178*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::None;
179*e03682afSJeremy L Thompson     /// assert!(
180*e03682afSJeremy L Thompson     ///     !qf_opt.is_some_q_function_by_name(),
181*e03682afSJeremy L Thompson     ///     "Incorrect QFunctionOpt"
182*e03682afSJeremy L Thompson     /// );
183*e03682afSJeremy L Thompson     /// # Ok(())
184*e03682afSJeremy L Thompson     /// # }
185*e03682afSJeremy L Thompson     /// ```
186*e03682afSJeremy L Thompson     pub fn is_some_q_function_by_name(&self) -> bool {
187*e03682afSJeremy L Thompson         match self {
188*e03682afSJeremy L Thompson             Self::SomeQFunction(_) => false,
189*e03682afSJeremy L Thompson             Self::SomeQFunctionByName(_) => true,
190*e03682afSJeremy L Thompson             Self::None => false,
191*e03682afSJeremy L Thompson         }
192*e03682afSJeremy L Thompson     }
193*e03682afSJeremy L Thompson 
194*e03682afSJeremy L Thompson     /// Check if a QFunctionOpt is None
195*e03682afSJeremy L Thompson     ///
196*e03682afSJeremy L Thompson     /// ```
197*e03682afSJeremy L Thompson     /// # use libceed::prelude::*;
198*e03682afSJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
199*e03682afSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
200*e03682afSJeremy L Thompson     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
201*e03682afSJeremy L Thompson     ///     // Iterate over quadrature points
202*e03682afSJeremy L Thompson     ///     v.iter_mut()
203*e03682afSJeremy L Thompson     ///         .zip(u.iter().zip(weights.iter()))
204*e03682afSJeremy L Thompson     ///         .for_each(|(v, (u, w))| *v = u * w);
205*e03682afSJeremy L Thompson     ///
206*e03682afSJeremy L Thompson     ///     // Return clean error code
207*e03682afSJeremy L Thompson     ///     0
208*e03682afSJeremy L Thompson     /// };
209*e03682afSJeremy L Thompson     ///
210*e03682afSJeremy L Thompson     /// let qf = ceed
211*e03682afSJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
212*e03682afSJeremy L Thompson     ///     .input("u", 1, EvalMode::Interp)?
213*e03682afSJeremy L Thompson     ///     .input("weights", 1, EvalMode::Weight)?
214*e03682afSJeremy L Thompson     ///     .output("v", 1, EvalMode::Interp)?;
215*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
216*e03682afSJeremy L Thompson     /// assert!(!qf_opt.is_none(), "Incorrect QFunctionOpt");
217*e03682afSJeremy L Thompson     ///
218*e03682afSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
219*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::from(&qf);
220*e03682afSJeremy L Thompson     /// assert!(!qf_opt.is_none(), "Incorrect QFunctionOpt");
221*e03682afSJeremy L Thompson     ///
222*e03682afSJeremy L Thompson     /// let qf_opt = QFunctionOpt::None;
223*e03682afSJeremy L Thompson     /// assert!(qf_opt.is_none(), "Incorrect QFunctionOpt");
224*e03682afSJeremy L Thompson     /// # Ok(())
225*e03682afSJeremy L Thompson     /// # }
226*e03682afSJeremy L Thompson     /// ```
227*e03682afSJeremy L Thompson     pub fn is_none(&self) -> bool {
228*e03682afSJeremy L Thompson         match self {
229*e03682afSJeremy L Thompson             Self::SomeQFunction(_) => false,
230*e03682afSJeremy L Thompson             Self::SomeQFunctionByName(_) => false,
231*e03682afSJeremy L Thompson             Self::None => true,
232*e03682afSJeremy L Thompson         }
233*e03682afSJeremy L Thompson     }
2349df49d7eSJed Brown }
2359df49d7eSJed Brown 
2369df49d7eSJed Brown // -----------------------------------------------------------------------------
2379df49d7eSJed Brown // CeedQFunction context wrapper
2389df49d7eSJed Brown // -----------------------------------------------------------------------------
239c68be7a2SJeremy L Thompson #[derive(Debug)]
2409df49d7eSJed Brown pub(crate) struct QFunctionCore<'a> {
2419df49d7eSJed Brown     ceed: &'a crate::Ceed,
2429df49d7eSJed Brown     ptr: bind_ceed::CeedQFunction,
2439df49d7eSJed Brown }
2449df49d7eSJed Brown 
2459df49d7eSJed Brown struct QFunctionTrampolineData {
2469df49d7eSJed Brown     number_inputs: usize,
2479df49d7eSJed Brown     number_outputs: usize,
2489df49d7eSJed Brown     input_sizes: [usize; MAX_QFUNCTION_FIELDS],
2499df49d7eSJed Brown     output_sizes: [usize; MAX_QFUNCTION_FIELDS],
2509df49d7eSJed Brown     user_f: Box<QFunctionUserClosure>,
2519df49d7eSJed Brown }
2529df49d7eSJed Brown 
2539df49d7eSJed Brown pub struct QFunction<'a> {
2549df49d7eSJed Brown     qf_core: QFunctionCore<'a>,
2559df49d7eSJed Brown     qf_ctx_ptr: bind_ceed::CeedQFunctionContext,
2569df49d7eSJed Brown     trampoline_data: Pin<Box<QFunctionTrampolineData>>,
2579df49d7eSJed Brown }
2589df49d7eSJed Brown 
259c68be7a2SJeremy L Thompson #[derive(Debug)]
2609df49d7eSJed Brown pub struct QFunctionByName<'a> {
2619df49d7eSJed Brown     qf_core: QFunctionCore<'a>,
2629df49d7eSJed Brown }
2639df49d7eSJed Brown 
2649df49d7eSJed Brown // -----------------------------------------------------------------------------
2659df49d7eSJed Brown // Destructor
2669df49d7eSJed Brown // -----------------------------------------------------------------------------
2679df49d7eSJed Brown impl<'a> Drop for QFunctionCore<'a> {
2689df49d7eSJed Brown     fn drop(&mut self) {
2699df49d7eSJed Brown         unsafe {
2709df49d7eSJed Brown             if self.ptr != bind_ceed::CEED_QFUNCTION_NONE {
2719df49d7eSJed Brown                 bind_ceed::CeedQFunctionDestroy(&mut self.ptr);
2729df49d7eSJed Brown             }
2739df49d7eSJed Brown         }
2749df49d7eSJed Brown     }
2759df49d7eSJed Brown }
2769df49d7eSJed Brown 
2779df49d7eSJed Brown impl<'a> Drop for QFunction<'a> {
2789df49d7eSJed Brown     fn drop(&mut self) {
2799df49d7eSJed Brown         unsafe {
2809df49d7eSJed Brown             bind_ceed::CeedQFunctionContextDestroy(&mut self.qf_ctx_ptr);
2819df49d7eSJed Brown         }
2829df49d7eSJed Brown     }
2839df49d7eSJed Brown }
2849df49d7eSJed Brown 
2859df49d7eSJed Brown // -----------------------------------------------------------------------------
2869df49d7eSJed Brown // Display
2879df49d7eSJed Brown // -----------------------------------------------------------------------------
2889df49d7eSJed Brown impl<'a> fmt::Display for QFunctionCore<'a> {
2899df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2909df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
2919df49d7eSJed Brown         let mut sizeloc = crate::MAX_BUFFER_LENGTH;
2929df49d7eSJed Brown         let cstring = unsafe {
2939df49d7eSJed Brown             let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc);
2949df49d7eSJed Brown             bind_ceed::CeedQFunctionView(self.ptr, file);
2959df49d7eSJed Brown             bind_ceed::fclose(file);
2969df49d7eSJed Brown             CString::from_raw(ptr)
2979df49d7eSJed Brown         };
2989df49d7eSJed Brown         cstring.to_string_lossy().fmt(f)
2999df49d7eSJed Brown     }
3009df49d7eSJed Brown }
3019df49d7eSJed Brown /// View a QFunction
3029df49d7eSJed Brown ///
3039df49d7eSJed Brown /// ```
3049df49d7eSJed Brown /// # use libceed::prelude::*;
305c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> {
3069df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
3079df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
3089df49d7eSJed Brown ///     // Iterate over quadrature points
3099df49d7eSJed Brown ///     v.iter_mut()
3109df49d7eSJed Brown ///         .zip(u.iter().zip(weights.iter()))
3119df49d7eSJed Brown ///         .for_each(|(v, (u, w))| *v = u * w);
3129df49d7eSJed Brown ///
3139df49d7eSJed Brown ///     // Return clean error code
3149df49d7eSJed Brown ///     0
3159df49d7eSJed Brown /// };
3169df49d7eSJed Brown ///
3179df49d7eSJed Brown /// let qf = ceed
318c68be7a2SJeremy L Thompson ///     .q_function_interior(1, Box::new(user_f))?
319c68be7a2SJeremy L Thompson ///     .input("u", 1, EvalMode::Interp)?
320c68be7a2SJeremy L Thompson ///     .input("weights", 1, EvalMode::Weight)?
321c68be7a2SJeremy L Thompson ///     .output("v", 1, EvalMode::Interp)?;
3229df49d7eSJed Brown ///
3239df49d7eSJed Brown /// println!("{}", qf);
324c68be7a2SJeremy L Thompson /// # Ok(())
325c68be7a2SJeremy L Thompson /// # }
3269df49d7eSJed Brown /// ```
3279df49d7eSJed Brown impl<'a> fmt::Display for QFunction<'a> {
3289df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3299df49d7eSJed Brown         self.qf_core.fmt(f)
3309df49d7eSJed Brown     }
3319df49d7eSJed Brown }
3329df49d7eSJed Brown 
3339df49d7eSJed Brown /// View a QFunction by Name
3349df49d7eSJed Brown ///
3359df49d7eSJed Brown /// ```
3369df49d7eSJed Brown /// # use libceed::prelude::*;
337c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> {
3389df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
339c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
3409df49d7eSJed Brown /// println!("{}", qf);
341c68be7a2SJeremy L Thompson /// # Ok(())
342c68be7a2SJeremy L Thompson /// # }
3439df49d7eSJed Brown /// ```
3449df49d7eSJed Brown impl<'a> fmt::Display for QFunctionByName<'a> {
3459df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3469df49d7eSJed Brown         self.qf_core.fmt(f)
3479df49d7eSJed Brown     }
3489df49d7eSJed Brown }
3499df49d7eSJed Brown 
3509df49d7eSJed Brown // -----------------------------------------------------------------------------
3519df49d7eSJed Brown // Core functionality
3529df49d7eSJed Brown // -----------------------------------------------------------------------------
3539df49d7eSJed Brown impl<'a> QFunctionCore<'a> {
3549df49d7eSJed Brown     // Common implementation
3559df49d7eSJed Brown     pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> {
3569df49d7eSJed Brown         let mut u_c = [std::ptr::null_mut(); MAX_QFUNCTION_FIELDS];
3579df49d7eSJed Brown         for i in 0..std::cmp::min(MAX_QFUNCTION_FIELDS, u.len()) {
3589df49d7eSJed Brown             u_c[i] = u[i].ptr;
3599df49d7eSJed Brown         }
3609df49d7eSJed Brown         let mut v_c = [std::ptr::null_mut(); MAX_QFUNCTION_FIELDS];
3619df49d7eSJed Brown         for i in 0..std::cmp::min(MAX_QFUNCTION_FIELDS, v.len()) {
3629df49d7eSJed Brown             v_c[i] = v[i].ptr;
3639df49d7eSJed Brown         }
3649df49d7eSJed Brown         let Q = i32::try_from(Q).unwrap();
3659df49d7eSJed Brown         let ierr = unsafe {
3669df49d7eSJed Brown             bind_ceed::CeedQFunctionApply(self.ptr, Q, u_c.as_mut_ptr(), v_c.as_mut_ptr())
3679df49d7eSJed Brown         };
3689df49d7eSJed Brown         self.ceed.check_error(ierr)
3699df49d7eSJed Brown     }
3709df49d7eSJed Brown }
3719df49d7eSJed Brown 
3729df49d7eSJed Brown // -----------------------------------------------------------------------------
3739df49d7eSJed Brown // User QFunction Closure
3749df49d7eSJed Brown // -----------------------------------------------------------------------------
37580a9ef05SNatalie Beams pub type QFunctionUserClosure = dyn FnMut(
37680a9ef05SNatalie Beams     [&[crate::Scalar]; MAX_QFUNCTION_FIELDS],
37780a9ef05SNatalie Beams     [&mut [crate::Scalar]; MAX_QFUNCTION_FIELDS],
37880a9ef05SNatalie Beams ) -> i32;
3799df49d7eSJed Brown 
3809df49d7eSJed Brown macro_rules! mut_max_fields {
3819df49d7eSJed Brown     ($e:expr) => {
3829df49d7eSJed Brown         [
3839df49d7eSJed Brown             $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e,
3849df49d7eSJed Brown         ]
3859df49d7eSJed Brown     };
3869df49d7eSJed Brown }
3879df49d7eSJed Brown unsafe extern "C" fn trampoline(
3889df49d7eSJed Brown     ctx: *mut ::std::os::raw::c_void,
3899df49d7eSJed Brown     q: bind_ceed::CeedInt,
3909df49d7eSJed Brown     inputs: *const *const bind_ceed::CeedScalar,
3919df49d7eSJed Brown     outputs: *const *mut bind_ceed::CeedScalar,
3929df49d7eSJed Brown ) -> ::std::os::raw::c_int {
3939df49d7eSJed Brown     let trampoline_data: Pin<&mut QFunctionTrampolineData> = std::mem::transmute(ctx);
3949df49d7eSJed Brown 
3959df49d7eSJed Brown     // Inputs
3969df49d7eSJed Brown     let inputs_slice: &[*const bind_ceed::CeedScalar] =
3979df49d7eSJed Brown         std::slice::from_raw_parts(inputs, MAX_QFUNCTION_FIELDS);
39880a9ef05SNatalie Beams     let mut inputs_array: [&[crate::Scalar]; MAX_QFUNCTION_FIELDS] = [&[0.0]; MAX_QFUNCTION_FIELDS];
3999df49d7eSJed Brown     inputs_slice
4009df49d7eSJed Brown         .iter()
4019df49d7eSJed Brown         .enumerate()
4029df49d7eSJed Brown         .map(|(i, &x)| {
40380a9ef05SNatalie Beams             std::slice::from_raw_parts(x, trampoline_data.input_sizes[i] * q as usize)
40480a9ef05SNatalie Beams                 as &[crate::Scalar]
4059df49d7eSJed Brown         })
4069df49d7eSJed Brown         .zip(inputs_array.iter_mut())
4079df49d7eSJed Brown         .for_each(|(x, a)| *a = x);
4089df49d7eSJed Brown 
4099df49d7eSJed Brown     // Outputs
4109df49d7eSJed Brown     let outputs_slice: &[*mut bind_ceed::CeedScalar] =
4119df49d7eSJed Brown         std::slice::from_raw_parts(outputs, MAX_QFUNCTION_FIELDS);
41280a9ef05SNatalie Beams     let mut outputs_array: [&mut [crate::Scalar]; MAX_QFUNCTION_FIELDS] =
41380a9ef05SNatalie Beams         mut_max_fields!(&mut [0.0]);
4149df49d7eSJed Brown     outputs_slice
4159df49d7eSJed Brown         .iter()
4169df49d7eSJed Brown         .enumerate()
4179df49d7eSJed Brown         .map(|(i, &x)| {
4189df49d7eSJed Brown             std::slice::from_raw_parts_mut(x, trampoline_data.output_sizes[i] * q as usize)
41980a9ef05SNatalie Beams                 as &mut [crate::Scalar]
4209df49d7eSJed Brown         })
4219df49d7eSJed Brown         .zip(outputs_array.iter_mut())
4229df49d7eSJed Brown         .for_each(|(x, a)| *a = x);
4239df49d7eSJed Brown 
4249df49d7eSJed Brown     // User closure
4259df49d7eSJed Brown     (trampoline_data.get_unchecked_mut().user_f)(inputs_array, outputs_array)
4269df49d7eSJed Brown }
4279df49d7eSJed Brown 
4289df49d7eSJed Brown // -----------------------------------------------------------------------------
4299df49d7eSJed Brown // QFunction
4309df49d7eSJed Brown // -----------------------------------------------------------------------------
4319df49d7eSJed Brown impl<'a> QFunction<'a> {
4329df49d7eSJed Brown     // Constructor
4339df49d7eSJed Brown     pub fn create(
4349df49d7eSJed Brown         ceed: &'a crate::Ceed,
4359df49d7eSJed Brown         vlength: usize,
4369df49d7eSJed Brown         user_f: Box<QFunctionUserClosure>,
4379df49d7eSJed Brown     ) -> crate::Result<Self> {
4389df49d7eSJed Brown         let source_c = CString::new("").expect("CString::new failed");
4399df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
4409df49d7eSJed Brown 
4419df49d7eSJed Brown         // Context for closure
4429df49d7eSJed Brown         let number_inputs = 0;
4439df49d7eSJed Brown         let number_outputs = 0;
4449df49d7eSJed Brown         let input_sizes = [0; MAX_QFUNCTION_FIELDS];
4459df49d7eSJed Brown         let output_sizes = [0; MAX_QFUNCTION_FIELDS];
4469df49d7eSJed Brown         let trampoline_data = unsafe {
4479df49d7eSJed Brown             Pin::new_unchecked(Box::new(QFunctionTrampolineData {
4489df49d7eSJed Brown                 number_inputs,
4499df49d7eSJed Brown                 number_outputs,
4509df49d7eSJed Brown                 input_sizes,
4519df49d7eSJed Brown                 output_sizes,
4529df49d7eSJed Brown                 user_f,
4539df49d7eSJed Brown             }))
4549df49d7eSJed Brown         };
4559df49d7eSJed Brown 
4569df49d7eSJed Brown         // Create QFunction
4579df49d7eSJed Brown         let vlength = i32::try_from(vlength).unwrap();
4589df49d7eSJed Brown         let mut ierr = unsafe {
4599df49d7eSJed Brown             bind_ceed::CeedQFunctionCreateInterior(
4609df49d7eSJed Brown                 ceed.ptr,
4619df49d7eSJed Brown                 vlength,
4629df49d7eSJed Brown                 Some(trampoline),
4639df49d7eSJed Brown                 source_c.as_ptr(),
4649df49d7eSJed Brown                 &mut ptr,
4659df49d7eSJed Brown             )
4669df49d7eSJed Brown         };
4679df49d7eSJed Brown         ceed.check_error(ierr)?;
4689df49d7eSJed Brown 
4699df49d7eSJed Brown         // Set closure
4709df49d7eSJed Brown         let mut qf_ctx_ptr = std::ptr::null_mut();
4719df49d7eSJed Brown         ierr = unsafe { bind_ceed::CeedQFunctionContextCreate(ceed.ptr, &mut qf_ctx_ptr) };
4729df49d7eSJed Brown         ceed.check_error(ierr)?;
4739df49d7eSJed Brown         ierr = unsafe {
4749df49d7eSJed Brown             bind_ceed::CeedQFunctionContextSetData(
4759df49d7eSJed Brown                 qf_ctx_ptr,
4769df49d7eSJed Brown                 crate::MemType::Host as bind_ceed::CeedMemType,
4779df49d7eSJed Brown                 crate::CopyMode::UsePointer as bind_ceed::CeedCopyMode,
4789df49d7eSJed Brown                 std::mem::size_of::<QFunctionTrampolineData>() as u64,
4799df49d7eSJed Brown                 std::mem::transmute(trampoline_data.as_ref()),
4809df49d7eSJed Brown             )
4819df49d7eSJed Brown         };
4829df49d7eSJed Brown         ceed.check_error(ierr)?;
4839df49d7eSJed Brown         ierr = unsafe { bind_ceed::CeedQFunctionSetContext(ptr, qf_ctx_ptr) };
4849df49d7eSJed Brown         ceed.check_error(ierr)?;
4859df49d7eSJed Brown         Ok(Self {
4869df49d7eSJed Brown             qf_core: QFunctionCore { ceed, ptr },
4879df49d7eSJed Brown             qf_ctx_ptr,
4889df49d7eSJed Brown             trampoline_data,
4899df49d7eSJed Brown         })
4909df49d7eSJed Brown     }
4919df49d7eSJed Brown 
4929df49d7eSJed Brown     /// Apply the action of a QFunction
4939df49d7eSJed Brown     ///
4949df49d7eSJed Brown     /// * `Q`      - The number of quadrature points
4959df49d7eSJed Brown     /// * `input`  - Array of input Vectors
4969df49d7eSJed Brown     /// * `output` - Array of output Vectors
4979df49d7eSJed Brown     ///
4989df49d7eSJed Brown     /// ```
4999df49d7eSJed Brown     /// # use libceed::prelude::*;
500c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
5019df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
5029df49d7eSJed Brown     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
5039df49d7eSJed Brown     ///     // Iterate over quadrature points
5049df49d7eSJed Brown     ///     v.iter_mut()
5059df49d7eSJed Brown     ///         .zip(u.iter().zip(weights.iter()))
5069df49d7eSJed Brown     ///         .for_each(|(v, (u, w))| *v = u * w);
5079df49d7eSJed Brown     ///
5089df49d7eSJed Brown     ///     // Return clean error code
5099df49d7eSJed Brown     ///     0
5109df49d7eSJed Brown     /// };
5119df49d7eSJed Brown     ///
5129df49d7eSJed Brown     /// let qf = ceed
513c68be7a2SJeremy L Thompson     ///     .q_function_interior(1, Box::new(user_f))?
514c68be7a2SJeremy L Thompson     ///     .input("u", 1, EvalMode::Interp)?
515c68be7a2SJeremy L Thompson     ///     .input("weights", 1, EvalMode::Weight)?
516c68be7a2SJeremy L Thompson     ///     .output("v", 1, EvalMode::Interp)?;
5179df49d7eSJed Brown     ///
5189df49d7eSJed Brown     /// const Q: usize = 8;
5199df49d7eSJed Brown     /// let mut w = [0.; Q];
5209df49d7eSJed Brown     /// let mut u = [0.; Q];
5219df49d7eSJed Brown     /// let mut v = [0.; Q];
5229df49d7eSJed Brown     ///
5239df49d7eSJed Brown     /// for i in 0..Q {
52480a9ef05SNatalie Beams     ///     let x = 2. * (i as Scalar) / ((Q as Scalar) - 1.) - 1.;
5259df49d7eSJed Brown     ///     u[i] = 2. + 3. * x + 5. * x * x;
5269df49d7eSJed Brown     ///     w[i] = 1. - x * x;
5279df49d7eSJed Brown     ///     v[i] = u[i] * w[i];
5289df49d7eSJed Brown     /// }
5299df49d7eSJed Brown     ///
530c68be7a2SJeremy L Thompson     /// let uu = ceed.vector_from_slice(&u)?;
531c68be7a2SJeremy L Thompson     /// let ww = ceed.vector_from_slice(&w)?;
532c68be7a2SJeremy L Thompson     /// let mut vv = ceed.vector(Q)?;
5339df49d7eSJed Brown     /// vv.set_value(0.0);
5349df49d7eSJed Brown     /// {
5359df49d7eSJed Brown     ///     let input = vec![uu, ww];
5369df49d7eSJed Brown     ///     let mut output = vec![vv];
537c68be7a2SJeremy L Thompson     ///     qf.apply(Q, &input, &output)?;
5389df49d7eSJed Brown     ///     vv = output.remove(0);
5399df49d7eSJed Brown     /// }
5409df49d7eSJed Brown     ///
5419df49d7eSJed Brown     /// vv.view()
5429df49d7eSJed Brown     ///     .iter()
5439df49d7eSJed Brown     ///     .zip(v.iter())
5449df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
5459df49d7eSJed Brown     ///         assert_eq!(
5469df49d7eSJed Brown     ///             *computed, *actual,
5479df49d7eSJed Brown     ///             "Incorrect value in QFunction application"
5489df49d7eSJed Brown     ///         );
5499df49d7eSJed Brown     ///     });
550c68be7a2SJeremy L Thompson     /// # Ok(())
551c68be7a2SJeremy L Thompson     /// # }
5529df49d7eSJed Brown     /// ```
5539df49d7eSJed Brown     pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> {
5549df49d7eSJed Brown         self.qf_core.apply(Q, u, v)
5559df49d7eSJed Brown     }
5569df49d7eSJed Brown 
5579df49d7eSJed Brown     /// Add a QFunction input
5589df49d7eSJed Brown     ///
5599df49d7eSJed Brown     /// * `fieldname` - Name of QFunction field
5609df49d7eSJed Brown     /// * `size`      - Size of QFunction field, `(ncomp * dim)` for `Grad` or
5619df49d7eSJed Brown     ///                   `(ncomp * 1)` for `None`, `Interp`, and `Weight`
5629df49d7eSJed Brown     /// * `emode`     - `EvalMode::None` to use values directly, `EvalMode::Interp`
5639df49d7eSJed Brown     ///                   to use interpolated values, `EvalMode::Grad` to use
5649df49d7eSJed Brown     ///                   gradients, `EvalMode::Weight` to use quadrature weights
5659df49d7eSJed Brown     ///
5669df49d7eSJed Brown     /// ```
5679df49d7eSJed Brown     /// # use libceed::prelude::*;
568c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
5699df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
5709df49d7eSJed Brown     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
5719df49d7eSJed Brown     ///     // Iterate over quadrature points
5729df49d7eSJed Brown     ///     v.iter_mut()
5739df49d7eSJed Brown     ///         .zip(u.iter().zip(weights.iter()))
5749df49d7eSJed Brown     ///         .for_each(|(v, (u, w))| *v = u * w);
5759df49d7eSJed Brown     ///
5769df49d7eSJed Brown     ///     // Return clean error code
5779df49d7eSJed Brown     ///     0
5789df49d7eSJed Brown     /// };
5799df49d7eSJed Brown     ///
580c68be7a2SJeremy L Thompson     /// let mut qf = ceed.q_function_interior(1, Box::new(user_f))?;
5819df49d7eSJed Brown     ///
582c68be7a2SJeremy L Thompson     /// qf = qf.input("u", 1, EvalMode::Interp)?;
583c68be7a2SJeremy L Thompson     /// qf = qf.input("weights", 1, EvalMode::Weight)?;
584c68be7a2SJeremy L Thompson     /// # Ok(())
585c68be7a2SJeremy L Thompson     /// # }
5869df49d7eSJed Brown     /// ```
5879df49d7eSJed Brown     pub fn input(
5889df49d7eSJed Brown         mut self,
5899df49d7eSJed Brown         fieldname: &str,
5909df49d7eSJed Brown         size: usize,
5919df49d7eSJed Brown         emode: crate::EvalMode,
5929df49d7eSJed Brown     ) -> crate::Result<Self> {
5939df49d7eSJed Brown         let name_c = CString::new(fieldname).expect("CString::new failed");
5949df49d7eSJed Brown         let idx = self.trampoline_data.number_inputs;
5959df49d7eSJed Brown         self.trampoline_data.input_sizes[idx] = size;
5969df49d7eSJed Brown         self.trampoline_data.number_inputs += 1;
5979df49d7eSJed Brown         let (size, emode) = (
5989df49d7eSJed Brown             i32::try_from(size).unwrap(),
5999df49d7eSJed Brown             emode as bind_ceed::CeedEvalMode,
6009df49d7eSJed Brown         );
6019df49d7eSJed Brown         let ierr = unsafe {
6029df49d7eSJed Brown             bind_ceed::CeedQFunctionAddInput(self.qf_core.ptr, name_c.as_ptr(), size, emode)
6039df49d7eSJed Brown         };
6049df49d7eSJed Brown         self.qf_core.ceed.check_error(ierr)?;
6059df49d7eSJed Brown         Ok(self)
6069df49d7eSJed Brown     }
6079df49d7eSJed Brown 
6089df49d7eSJed Brown     /// Add a QFunction output
6099df49d7eSJed Brown     ///
6109df49d7eSJed Brown     /// * `fieldname` - Name of QFunction field
6119df49d7eSJed Brown     /// * `size`      - Size of QFunction field, `(ncomp * dim)` for `Grad` or
6129df49d7eSJed Brown     ///                   `(ncomp * 1)` for `None` and `Interp`
6139df49d7eSJed Brown     /// * `emode`     - `EvalMode::None` to use values directly, `EvalMode::Interp`
6149df49d7eSJed Brown     ///                   to use interpolated values, `EvalMode::Grad` to use
6159df49d7eSJed Brown     ///                   gradients
6169df49d7eSJed Brown     ///
6179df49d7eSJed Brown     /// ```
6189df49d7eSJed Brown     /// # use libceed::prelude::*;
619c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
6209df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
6219df49d7eSJed Brown     /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
6229df49d7eSJed Brown     ///     // Iterate over quadrature points
6239df49d7eSJed Brown     ///     v.iter_mut()
6249df49d7eSJed Brown     ///         .zip(u.iter().zip(weights.iter()))
6259df49d7eSJed Brown     ///         .for_each(|(v, (u, w))| *v = u * w);
6269df49d7eSJed Brown     ///
6279df49d7eSJed Brown     ///     // Return clean error code
6289df49d7eSJed Brown     ///     0
6299df49d7eSJed Brown     /// };
6309df49d7eSJed Brown     ///
631c68be7a2SJeremy L Thompson     /// let mut qf = ceed.q_function_interior(1, Box::new(user_f))?;
6329df49d7eSJed Brown     ///
633c68be7a2SJeremy L Thompson     /// qf.output("v", 1, EvalMode::Interp)?;
634c68be7a2SJeremy L Thompson     /// # Ok(())
635c68be7a2SJeremy L Thompson     /// # }
6369df49d7eSJed Brown     /// ```
6379df49d7eSJed Brown     pub fn output(
6389df49d7eSJed Brown         mut self,
6399df49d7eSJed Brown         fieldname: &str,
6409df49d7eSJed Brown         size: usize,
6419df49d7eSJed Brown         emode: crate::EvalMode,
6429df49d7eSJed Brown     ) -> crate::Result<Self> {
6439df49d7eSJed Brown         let name_c = CString::new(fieldname).expect("CString::new failed");
6449df49d7eSJed Brown         let idx = self.trampoline_data.number_outputs;
6459df49d7eSJed Brown         self.trampoline_data.output_sizes[idx] = size;
6469df49d7eSJed Brown         self.trampoline_data.number_outputs += 1;
6479df49d7eSJed Brown         let (size, emode) = (
6489df49d7eSJed Brown             i32::try_from(size).unwrap(),
6499df49d7eSJed Brown             emode as bind_ceed::CeedEvalMode,
6509df49d7eSJed Brown         );
6519df49d7eSJed Brown         let ierr = unsafe {
6529df49d7eSJed Brown             bind_ceed::CeedQFunctionAddOutput(self.qf_core.ptr, name_c.as_ptr(), size, emode)
6539df49d7eSJed Brown         };
6549df49d7eSJed Brown         self.qf_core.ceed.check_error(ierr)?;
6559df49d7eSJed Brown         Ok(self)
6569df49d7eSJed Brown     }
6579df49d7eSJed Brown }
6589df49d7eSJed Brown 
6599df49d7eSJed Brown // -----------------------------------------------------------------------------
6609df49d7eSJed Brown // QFunction
6619df49d7eSJed Brown // -----------------------------------------------------------------------------
6629df49d7eSJed Brown impl<'a> QFunctionByName<'a> {
6639df49d7eSJed Brown     // Constructor
6649df49d7eSJed Brown     pub fn create(ceed: &'a crate::Ceed, name: &str) -> crate::Result<Self> {
6659df49d7eSJed Brown         let name_c = CString::new(name).expect("CString::new failed");
6669df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
6679df49d7eSJed Brown         let ierr = unsafe {
6689df49d7eSJed Brown             bind_ceed::CeedQFunctionCreateInteriorByName(ceed.ptr, name_c.as_ptr(), &mut ptr)
6699df49d7eSJed Brown         };
6709df49d7eSJed Brown         ceed.check_error(ierr)?;
6719df49d7eSJed Brown         Ok(Self {
6729df49d7eSJed Brown             qf_core: QFunctionCore { ceed, ptr },
6739df49d7eSJed Brown         })
6749df49d7eSJed Brown     }
6759df49d7eSJed Brown 
6769df49d7eSJed Brown     /// Apply the action of a QFunction
6779df49d7eSJed Brown     ///
6789df49d7eSJed Brown     /// * `Q`      - The number of quadrature points
6799df49d7eSJed Brown     /// * `input`  - Array of input Vectors
6809df49d7eSJed Brown     /// * `output` - Array of output Vectors
6819df49d7eSJed Brown     ///
6829df49d7eSJed Brown     /// ```
6839df49d7eSJed Brown     /// # use libceed::prelude::*;
684c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
6859df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
6869df49d7eSJed Brown     /// const Q: usize = 8;
687c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
688c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
6899df49d7eSJed Brown     ///
6909df49d7eSJed Brown     /// let mut j = [0.; Q];
6919df49d7eSJed Brown     /// let mut w = [0.; Q];
6929df49d7eSJed Brown     /// let mut u = [0.; Q];
6939df49d7eSJed Brown     /// let mut v = [0.; Q];
6949df49d7eSJed Brown     ///
6959df49d7eSJed Brown     /// for i in 0..Q {
69680a9ef05SNatalie Beams     ///     let x = 2. * (i as Scalar) / ((Q as Scalar) - 1.) - 1.;
6979df49d7eSJed Brown     ///     j[i] = 1.;
6989df49d7eSJed Brown     ///     w[i] = 1. - x * x;
6999df49d7eSJed Brown     ///     u[i] = 2. + 3. * x + 5. * x * x;
7009df49d7eSJed Brown     ///     v[i] = w[i] * u[i];
7019df49d7eSJed Brown     /// }
7029df49d7eSJed Brown     ///
703c68be7a2SJeremy L Thompson     /// let jj = ceed.vector_from_slice(&j)?;
704c68be7a2SJeremy L Thompson     /// let ww = ceed.vector_from_slice(&w)?;
705c68be7a2SJeremy L Thompson     /// let uu = ceed.vector_from_slice(&u)?;
706c68be7a2SJeremy L Thompson     /// let mut vv = ceed.vector(Q)?;
7079df49d7eSJed Brown     /// vv.set_value(0.0);
708c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(Q)?;
7099df49d7eSJed Brown     /// qdata.set_value(0.0);
7109df49d7eSJed Brown     ///
7119df49d7eSJed Brown     /// {
7129df49d7eSJed Brown     ///     let mut input = vec![jj, ww];
7139df49d7eSJed Brown     ///     let mut output = vec![qdata];
714c68be7a2SJeremy L Thompson     ///     qf_build.apply(Q, &input, &output)?;
7159df49d7eSJed Brown     ///     qdata = output.remove(0);
7169df49d7eSJed Brown     /// }
7179df49d7eSJed Brown     ///
7189df49d7eSJed Brown     /// {
7199df49d7eSJed Brown     ///     let mut input = vec![qdata, uu];
7209df49d7eSJed Brown     ///     let mut output = vec![vv];
721c68be7a2SJeremy L Thompson     ///     qf_mass.apply(Q, &input, &output)?;
7229df49d7eSJed Brown     ///     vv = output.remove(0);
7239df49d7eSJed Brown     /// }
7249df49d7eSJed Brown     ///
7259df49d7eSJed Brown     /// vv.view()
7269df49d7eSJed Brown     ///     .iter()
7279df49d7eSJed Brown     ///     .zip(v.iter())
7289df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
7299df49d7eSJed Brown     ///         assert_eq!(
7309df49d7eSJed Brown     ///             *computed, *actual,
7319df49d7eSJed Brown     ///             "Incorrect value in QFunction application"
7329df49d7eSJed Brown     ///         );
7339df49d7eSJed Brown     ///     });
734c68be7a2SJeremy L Thompson     /// # Ok(())
735c68be7a2SJeremy L Thompson     /// # }
7369df49d7eSJed Brown     /// ```
7379df49d7eSJed Brown     pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> {
7389df49d7eSJed Brown         self.qf_core.apply(Q, u, v)
7399df49d7eSJed Brown     }
7409df49d7eSJed Brown }
7419df49d7eSJed Brown 
7429df49d7eSJed Brown // -----------------------------------------------------------------------------
743