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 } 61e03682afSJeremy L Thompson 62e03682afSJeremy L Thompson /// Check if a QFunctionOpt is Some 63e03682afSJeremy L Thompson /// 64e03682afSJeremy L Thompson /// ``` 65e03682afSJeremy L Thompson /// # use libceed::prelude::*; 66e03682afSJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 67e03682afSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 68e03682afSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 69e03682afSJeremy L Thompson /// // Iterate over quadrature points 70e03682afSJeremy L Thompson /// v.iter_mut() 71e03682afSJeremy L Thompson /// .zip(u.iter().zip(weights.iter())) 72e03682afSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w); 73e03682afSJeremy L Thompson /// 74e03682afSJeremy L Thompson /// // Return clean error code 75e03682afSJeremy L Thompson /// 0 76e03682afSJeremy L Thompson /// }; 77e03682afSJeremy L Thompson /// 78e03682afSJeremy L Thompson /// let qf = ceed 79e03682afSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))? 80e03682afSJeremy L Thompson /// .input("u", 1, EvalMode::Interp)? 81e03682afSJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)? 82e03682afSJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?; 83e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf); 84e03682afSJeremy L Thompson /// assert!(qf_opt.is_some(), "Incorrect QFunctionOpt"); 85e03682afSJeremy L Thompson /// 86e03682afSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 87e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf); 88e03682afSJeremy L Thompson /// assert!(qf_opt.is_some(), "Incorrect QFunctionOpt"); 89e03682afSJeremy L Thompson /// 90e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::None; 91e03682afSJeremy L Thompson /// assert!(!qf_opt.is_some(), "Incorrect QFunctionOpt"); 92e03682afSJeremy L Thompson /// # Ok(()) 93e03682afSJeremy L Thompson /// # } 94e03682afSJeremy L Thompson /// ``` 95e03682afSJeremy L Thompson pub fn is_some(&self) -> bool { 96e03682afSJeremy L Thompson match self { 97e03682afSJeremy L Thompson Self::SomeQFunction(_) => true, 98e03682afSJeremy L Thompson Self::SomeQFunctionByName(_) => true, 99e03682afSJeremy L Thompson Self::None => false, 100e03682afSJeremy L Thompson } 101e03682afSJeremy L Thompson } 102e03682afSJeremy L Thompson 103e03682afSJeremy L Thompson /// Check if a QFunctionOpt is SomeQFunction 104e03682afSJeremy L Thompson /// 105e03682afSJeremy L Thompson /// ``` 106e03682afSJeremy L Thompson /// # use libceed::prelude::*; 107e03682afSJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 108e03682afSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 109e03682afSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 110e03682afSJeremy L Thompson /// // Iterate over quadrature points 111e03682afSJeremy L Thompson /// v.iter_mut() 112e03682afSJeremy L Thompson /// .zip(u.iter().zip(weights.iter())) 113e03682afSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w); 114e03682afSJeremy L Thompson /// 115e03682afSJeremy L Thompson /// // Return clean error code 116e03682afSJeremy L Thompson /// 0 117e03682afSJeremy L Thompson /// }; 118e03682afSJeremy L Thompson /// 119e03682afSJeremy L Thompson /// let qf = ceed 120e03682afSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))? 121e03682afSJeremy L Thompson /// .input("u", 1, EvalMode::Interp)? 122e03682afSJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)? 123e03682afSJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?; 124e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf); 125e03682afSJeremy L Thompson /// assert!(qf_opt.is_some_q_function(), "Incorrect QFunctionOpt"); 126e03682afSJeremy L Thompson /// 127e03682afSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 128e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf); 129e03682afSJeremy L Thompson /// assert!(!qf_opt.is_some_q_function(), "Incorrect QFunctionOpt"); 130e03682afSJeremy L Thompson /// 131e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::None; 132e03682afSJeremy L Thompson /// assert!(!qf_opt.is_some_q_function(), "Incorrect QFunctionOpt"); 133e03682afSJeremy L Thompson /// # Ok(()) 134e03682afSJeremy L Thompson /// # } 135e03682afSJeremy L Thompson /// ``` 136e03682afSJeremy L Thompson pub fn is_some_q_function(&self) -> bool { 137e03682afSJeremy L Thompson match self { 138e03682afSJeremy L Thompson Self::SomeQFunction(_) => true, 139e03682afSJeremy L Thompson Self::SomeQFunctionByName(_) => false, 140e03682afSJeremy L Thompson Self::None => false, 141e03682afSJeremy L Thompson } 142e03682afSJeremy L Thompson } 143e03682afSJeremy L Thompson 144e03682afSJeremy L Thompson /// Check if a QFunctionOpt is SomeQFunctionByName 145e03682afSJeremy L Thompson /// 146e03682afSJeremy L Thompson /// ``` 147e03682afSJeremy L Thompson /// # use libceed::prelude::*; 148e03682afSJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 149e03682afSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 150e03682afSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 151e03682afSJeremy L Thompson /// // Iterate over quadrature points 152e03682afSJeremy L Thompson /// v.iter_mut() 153e03682afSJeremy L Thompson /// .zip(u.iter().zip(weights.iter())) 154e03682afSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w); 155e03682afSJeremy L Thompson /// 156e03682afSJeremy L Thompson /// // Return clean error code 157e03682afSJeremy L Thompson /// 0 158e03682afSJeremy L Thompson /// }; 159e03682afSJeremy L Thompson /// 160e03682afSJeremy L Thompson /// let qf = ceed 161e03682afSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))? 162e03682afSJeremy L Thompson /// .input("u", 1, EvalMode::Interp)? 163e03682afSJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)? 164e03682afSJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?; 165e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf); 166e03682afSJeremy L Thompson /// assert!( 167e03682afSJeremy L Thompson /// !qf_opt.is_some_q_function_by_name(), 168e03682afSJeremy L Thompson /// "Incorrect QFunctionOpt" 169e03682afSJeremy L Thompson /// ); 170e03682afSJeremy L Thompson /// 171e03682afSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 172e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf); 173e03682afSJeremy L Thompson /// assert!( 174e03682afSJeremy L Thompson /// qf_opt.is_some_q_function_by_name(), 175e03682afSJeremy L Thompson /// "Incorrect QFunctionOpt" 176e03682afSJeremy L Thompson /// ); 177e03682afSJeremy L Thompson /// 178e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::None; 179e03682afSJeremy L Thompson /// assert!( 180e03682afSJeremy L Thompson /// !qf_opt.is_some_q_function_by_name(), 181e03682afSJeremy L Thompson /// "Incorrect QFunctionOpt" 182e03682afSJeremy L Thompson /// ); 183e03682afSJeremy L Thompson /// # Ok(()) 184e03682afSJeremy L Thompson /// # } 185e03682afSJeremy L Thompson /// ``` 186e03682afSJeremy L Thompson pub fn is_some_q_function_by_name(&self) -> bool { 187e03682afSJeremy L Thompson match self { 188e03682afSJeremy L Thompson Self::SomeQFunction(_) => false, 189e03682afSJeremy L Thompson Self::SomeQFunctionByName(_) => true, 190e03682afSJeremy L Thompson Self::None => false, 191e03682afSJeremy L Thompson } 192e03682afSJeremy L Thompson } 193e03682afSJeremy L Thompson 194e03682afSJeremy L Thompson /// Check if a QFunctionOpt is None 195e03682afSJeremy L Thompson /// 196e03682afSJeremy L Thompson /// ``` 197e03682afSJeremy L Thompson /// # use libceed::prelude::*; 198e03682afSJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 199e03682afSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 200e03682afSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 201e03682afSJeremy L Thompson /// // Iterate over quadrature points 202e03682afSJeremy L Thompson /// v.iter_mut() 203e03682afSJeremy L Thompson /// .zip(u.iter().zip(weights.iter())) 204e03682afSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w); 205e03682afSJeremy L Thompson /// 206e03682afSJeremy L Thompson /// // Return clean error code 207e03682afSJeremy L Thompson /// 0 208e03682afSJeremy L Thompson /// }; 209e03682afSJeremy L Thompson /// 210e03682afSJeremy L Thompson /// let qf = ceed 211e03682afSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))? 212e03682afSJeremy L Thompson /// .input("u", 1, EvalMode::Interp)? 213e03682afSJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)? 214e03682afSJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?; 215e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf); 216e03682afSJeremy L Thompson /// assert!(!qf_opt.is_none(), "Incorrect QFunctionOpt"); 217e03682afSJeremy L Thompson /// 218e03682afSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 219e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::from(&qf); 220e03682afSJeremy L Thompson /// assert!(!qf_opt.is_none(), "Incorrect QFunctionOpt"); 221e03682afSJeremy L Thompson /// 222e03682afSJeremy L Thompson /// let qf_opt = QFunctionOpt::None; 223e03682afSJeremy L Thompson /// assert!(qf_opt.is_none(), "Incorrect QFunctionOpt"); 224e03682afSJeremy L Thompson /// # Ok(()) 225e03682afSJeremy L Thompson /// # } 226e03682afSJeremy L Thompson /// ``` 227e03682afSJeremy L Thompson pub fn is_none(&self) -> bool { 228e03682afSJeremy L Thompson match self { 229e03682afSJeremy L Thompson Self::SomeQFunction(_) => false, 230e03682afSJeremy L Thompson Self::SomeQFunctionByName(_) => false, 231e03682afSJeremy L Thompson Self::None => true, 232e03682afSJeremy L Thompson } 233e03682afSJeremy 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 ptr: bind_ceed::CeedQFunction, 242*1142270cSJeremy L Thompson _lifeline: PhantomData<&'a ()>, 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> { 354*1142270cSJeremy L Thompson // Error handling 355*1142270cSJeremy L Thompson #[doc(hidden)] 356*1142270cSJeremy L Thompson fn check_error(&self, ierr: i32) -> crate::Result<i32> { 357*1142270cSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 358*1142270cSJeremy L Thompson unsafe { 359*1142270cSJeremy L Thompson bind_ceed::CeedQFunctionGetCeed(self.ptr, &mut ptr); 360*1142270cSJeremy L Thompson } 361*1142270cSJeremy L Thompson crate::check_error(ptr, ierr) 362*1142270cSJeremy L Thompson } 363*1142270cSJeremy L Thompson 3649df49d7eSJed Brown // Common implementation 3659df49d7eSJed Brown pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> { 3669df49d7eSJed Brown let mut u_c = [std::ptr::null_mut(); MAX_QFUNCTION_FIELDS]; 3679df49d7eSJed Brown for i in 0..std::cmp::min(MAX_QFUNCTION_FIELDS, u.len()) { 3689df49d7eSJed Brown u_c[i] = u[i].ptr; 3699df49d7eSJed Brown } 3709df49d7eSJed Brown let mut v_c = [std::ptr::null_mut(); MAX_QFUNCTION_FIELDS]; 3719df49d7eSJed Brown for i in 0..std::cmp::min(MAX_QFUNCTION_FIELDS, v.len()) { 3729df49d7eSJed Brown v_c[i] = v[i].ptr; 3739df49d7eSJed Brown } 3749df49d7eSJed Brown let Q = i32::try_from(Q).unwrap(); 3759df49d7eSJed Brown let ierr = unsafe { 3769df49d7eSJed Brown bind_ceed::CeedQFunctionApply(self.ptr, Q, u_c.as_mut_ptr(), v_c.as_mut_ptr()) 3779df49d7eSJed Brown }; 378*1142270cSJeremy L Thompson self.check_error(ierr) 3799df49d7eSJed Brown } 3809df49d7eSJed Brown } 3819df49d7eSJed Brown 3829df49d7eSJed Brown // ----------------------------------------------------------------------------- 3839df49d7eSJed Brown // User QFunction Closure 3849df49d7eSJed Brown // ----------------------------------------------------------------------------- 38580a9ef05SNatalie Beams pub type QFunctionUserClosure = dyn FnMut( 38680a9ef05SNatalie Beams [&[crate::Scalar]; MAX_QFUNCTION_FIELDS], 38780a9ef05SNatalie Beams [&mut [crate::Scalar]; MAX_QFUNCTION_FIELDS], 38880a9ef05SNatalie Beams ) -> i32; 3899df49d7eSJed Brown 3909df49d7eSJed Brown macro_rules! mut_max_fields { 3919df49d7eSJed Brown ($e:expr) => { 3929df49d7eSJed Brown [ 3939df49d7eSJed Brown $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, $e, 3949df49d7eSJed Brown ] 3959df49d7eSJed Brown }; 3969df49d7eSJed Brown } 3979df49d7eSJed Brown unsafe extern "C" fn trampoline( 3989df49d7eSJed Brown ctx: *mut ::std::os::raw::c_void, 3999df49d7eSJed Brown q: bind_ceed::CeedInt, 4009df49d7eSJed Brown inputs: *const *const bind_ceed::CeedScalar, 4019df49d7eSJed Brown outputs: *const *mut bind_ceed::CeedScalar, 4029df49d7eSJed Brown ) -> ::std::os::raw::c_int { 4039df49d7eSJed Brown let trampoline_data: Pin<&mut QFunctionTrampolineData> = std::mem::transmute(ctx); 4049df49d7eSJed Brown 4059df49d7eSJed Brown // Inputs 4069df49d7eSJed Brown let inputs_slice: &[*const bind_ceed::CeedScalar] = 4079df49d7eSJed Brown std::slice::from_raw_parts(inputs, MAX_QFUNCTION_FIELDS); 40880a9ef05SNatalie Beams let mut inputs_array: [&[crate::Scalar]; MAX_QFUNCTION_FIELDS] = [&[0.0]; MAX_QFUNCTION_FIELDS]; 4099df49d7eSJed Brown inputs_slice 4109df49d7eSJed Brown .iter() 4119df49d7eSJed Brown .enumerate() 4129df49d7eSJed Brown .map(|(i, &x)| { 41380a9ef05SNatalie Beams std::slice::from_raw_parts(x, trampoline_data.input_sizes[i] * q as usize) 41480a9ef05SNatalie Beams as &[crate::Scalar] 4159df49d7eSJed Brown }) 4169df49d7eSJed Brown .zip(inputs_array.iter_mut()) 4179df49d7eSJed Brown .for_each(|(x, a)| *a = x); 4189df49d7eSJed Brown 4199df49d7eSJed Brown // Outputs 4209df49d7eSJed Brown let outputs_slice: &[*mut bind_ceed::CeedScalar] = 4219df49d7eSJed Brown std::slice::from_raw_parts(outputs, MAX_QFUNCTION_FIELDS); 42280a9ef05SNatalie Beams let mut outputs_array: [&mut [crate::Scalar]; MAX_QFUNCTION_FIELDS] = 42380a9ef05SNatalie Beams mut_max_fields!(&mut [0.0]); 4249df49d7eSJed Brown outputs_slice 4259df49d7eSJed Brown .iter() 4269df49d7eSJed Brown .enumerate() 4279df49d7eSJed Brown .map(|(i, &x)| { 4289df49d7eSJed Brown std::slice::from_raw_parts_mut(x, trampoline_data.output_sizes[i] * q as usize) 42980a9ef05SNatalie Beams as &mut [crate::Scalar] 4309df49d7eSJed Brown }) 4319df49d7eSJed Brown .zip(outputs_array.iter_mut()) 4329df49d7eSJed Brown .for_each(|(x, a)| *a = x); 4339df49d7eSJed Brown 4349df49d7eSJed Brown // User closure 4359df49d7eSJed Brown (trampoline_data.get_unchecked_mut().user_f)(inputs_array, outputs_array) 4369df49d7eSJed Brown } 4379df49d7eSJed Brown 4389df49d7eSJed Brown // ----------------------------------------------------------------------------- 4399df49d7eSJed Brown // QFunction 4409df49d7eSJed Brown // ----------------------------------------------------------------------------- 4419df49d7eSJed Brown impl<'a> QFunction<'a> { 4429df49d7eSJed Brown // Constructor 4439df49d7eSJed Brown pub fn create( 4449df49d7eSJed Brown ceed: &'a crate::Ceed, 4459df49d7eSJed Brown vlength: usize, 4469df49d7eSJed Brown user_f: Box<QFunctionUserClosure>, 4479df49d7eSJed Brown ) -> crate::Result<Self> { 4489df49d7eSJed Brown let source_c = CString::new("").expect("CString::new failed"); 4499df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 4509df49d7eSJed Brown 4519df49d7eSJed Brown // Context for closure 4529df49d7eSJed Brown let number_inputs = 0; 4539df49d7eSJed Brown let number_outputs = 0; 4549df49d7eSJed Brown let input_sizes = [0; MAX_QFUNCTION_FIELDS]; 4559df49d7eSJed Brown let output_sizes = [0; MAX_QFUNCTION_FIELDS]; 4569df49d7eSJed Brown let trampoline_data = unsafe { 4579df49d7eSJed Brown Pin::new_unchecked(Box::new(QFunctionTrampolineData { 4589df49d7eSJed Brown number_inputs, 4599df49d7eSJed Brown number_outputs, 4609df49d7eSJed Brown input_sizes, 4619df49d7eSJed Brown output_sizes, 4629df49d7eSJed Brown user_f, 4639df49d7eSJed Brown })) 4649df49d7eSJed Brown }; 4659df49d7eSJed Brown 4669df49d7eSJed Brown // Create QFunction 4679df49d7eSJed Brown let vlength = i32::try_from(vlength).unwrap(); 4689df49d7eSJed Brown let mut ierr = unsafe { 4699df49d7eSJed Brown bind_ceed::CeedQFunctionCreateInterior( 4709df49d7eSJed Brown ceed.ptr, 4719df49d7eSJed Brown vlength, 4729df49d7eSJed Brown Some(trampoline), 4739df49d7eSJed Brown source_c.as_ptr(), 4749df49d7eSJed Brown &mut ptr, 4759df49d7eSJed Brown ) 4769df49d7eSJed Brown }; 4779df49d7eSJed Brown ceed.check_error(ierr)?; 4789df49d7eSJed Brown 4799df49d7eSJed Brown // Set closure 4809df49d7eSJed Brown let mut qf_ctx_ptr = std::ptr::null_mut(); 4819df49d7eSJed Brown ierr = unsafe { bind_ceed::CeedQFunctionContextCreate(ceed.ptr, &mut qf_ctx_ptr) }; 4829df49d7eSJed Brown ceed.check_error(ierr)?; 4839df49d7eSJed Brown ierr = unsafe { 4849df49d7eSJed Brown bind_ceed::CeedQFunctionContextSetData( 4859df49d7eSJed Brown qf_ctx_ptr, 4869df49d7eSJed Brown crate::MemType::Host as bind_ceed::CeedMemType, 4879df49d7eSJed Brown crate::CopyMode::UsePointer as bind_ceed::CeedCopyMode, 4889df49d7eSJed Brown std::mem::size_of::<QFunctionTrampolineData>() as u64, 4899df49d7eSJed Brown std::mem::transmute(trampoline_data.as_ref()), 4909df49d7eSJed Brown ) 4919df49d7eSJed Brown }; 4929df49d7eSJed Brown ceed.check_error(ierr)?; 4939df49d7eSJed Brown ierr = unsafe { bind_ceed::CeedQFunctionSetContext(ptr, qf_ctx_ptr) }; 4949df49d7eSJed Brown ceed.check_error(ierr)?; 4959df49d7eSJed Brown Ok(Self { 496*1142270cSJeremy L Thompson qf_core: QFunctionCore { 497*1142270cSJeremy L Thompson ptr, 498*1142270cSJeremy L Thompson _lifeline: PhantomData, 499*1142270cSJeremy L Thompson }, 5009df49d7eSJed Brown qf_ctx_ptr, 5019df49d7eSJed Brown trampoline_data, 5029df49d7eSJed Brown }) 5039df49d7eSJed Brown } 5049df49d7eSJed Brown 5059df49d7eSJed Brown /// Apply the action of a QFunction 5069df49d7eSJed Brown /// 5079df49d7eSJed Brown /// * `Q` - The number of quadrature points 5089df49d7eSJed Brown /// * `input` - Array of input Vectors 5099df49d7eSJed Brown /// * `output` - Array of output Vectors 5109df49d7eSJed Brown /// 5119df49d7eSJed Brown /// ``` 5129df49d7eSJed Brown /// # use libceed::prelude::*; 513c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 5149df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 5159df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 5169df49d7eSJed Brown /// // Iterate over quadrature points 5179df49d7eSJed Brown /// v.iter_mut() 5189df49d7eSJed Brown /// .zip(u.iter().zip(weights.iter())) 5199df49d7eSJed Brown /// .for_each(|(v, (u, w))| *v = u * w); 5209df49d7eSJed Brown /// 5219df49d7eSJed Brown /// // Return clean error code 5229df49d7eSJed Brown /// 0 5239df49d7eSJed Brown /// }; 5249df49d7eSJed Brown /// 5259df49d7eSJed Brown /// let qf = ceed 526c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))? 527c68be7a2SJeremy L Thompson /// .input("u", 1, EvalMode::Interp)? 528c68be7a2SJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)? 529c68be7a2SJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?; 5309df49d7eSJed Brown /// 5319df49d7eSJed Brown /// const Q: usize = 8; 5329df49d7eSJed Brown /// let mut w = [0.; Q]; 5339df49d7eSJed Brown /// let mut u = [0.; Q]; 5349df49d7eSJed Brown /// let mut v = [0.; Q]; 5359df49d7eSJed Brown /// 5369df49d7eSJed Brown /// for i in 0..Q { 53780a9ef05SNatalie Beams /// let x = 2. * (i as Scalar) / ((Q as Scalar) - 1.) - 1.; 5389df49d7eSJed Brown /// u[i] = 2. + 3. * x + 5. * x * x; 5399df49d7eSJed Brown /// w[i] = 1. - x * x; 5409df49d7eSJed Brown /// v[i] = u[i] * w[i]; 5419df49d7eSJed Brown /// } 5429df49d7eSJed Brown /// 543c68be7a2SJeremy L Thompson /// let uu = ceed.vector_from_slice(&u)?; 544c68be7a2SJeremy L Thompson /// let ww = ceed.vector_from_slice(&w)?; 545c68be7a2SJeremy L Thompson /// let mut vv = ceed.vector(Q)?; 5469df49d7eSJed Brown /// vv.set_value(0.0); 5479df49d7eSJed Brown /// { 5489df49d7eSJed Brown /// let input = vec![uu, ww]; 5499df49d7eSJed Brown /// let mut output = vec![vv]; 550c68be7a2SJeremy L Thompson /// qf.apply(Q, &input, &output)?; 5519df49d7eSJed Brown /// vv = output.remove(0); 5529df49d7eSJed Brown /// } 5539df49d7eSJed Brown /// 5549df49d7eSJed Brown /// vv.view() 5559df49d7eSJed Brown /// .iter() 5569df49d7eSJed Brown /// .zip(v.iter()) 5579df49d7eSJed Brown /// .for_each(|(computed, actual)| { 5589df49d7eSJed Brown /// assert_eq!( 5599df49d7eSJed Brown /// *computed, *actual, 5609df49d7eSJed Brown /// "Incorrect value in QFunction application" 5619df49d7eSJed Brown /// ); 5629df49d7eSJed Brown /// }); 563c68be7a2SJeremy L Thompson /// # Ok(()) 564c68be7a2SJeremy L Thompson /// # } 5659df49d7eSJed Brown /// ``` 5669df49d7eSJed Brown pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> { 5679df49d7eSJed Brown self.qf_core.apply(Q, u, v) 5689df49d7eSJed Brown } 5699df49d7eSJed Brown 5709df49d7eSJed Brown /// Add a QFunction input 5719df49d7eSJed Brown /// 5729df49d7eSJed Brown /// * `fieldname` - Name of QFunction field 5739df49d7eSJed Brown /// * `size` - Size of QFunction field, `(ncomp * dim)` for `Grad` or 5749df49d7eSJed Brown /// `(ncomp * 1)` for `None`, `Interp`, and `Weight` 5759df49d7eSJed Brown /// * `emode` - `EvalMode::None` to use values directly, `EvalMode::Interp` 5769df49d7eSJed Brown /// to use interpolated values, `EvalMode::Grad` to use 5779df49d7eSJed Brown /// gradients, `EvalMode::Weight` to use quadrature weights 5789df49d7eSJed Brown /// 5799df49d7eSJed Brown /// ``` 5809df49d7eSJed Brown /// # use libceed::prelude::*; 581c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 5829df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 5839df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 5849df49d7eSJed Brown /// // Iterate over quadrature points 5859df49d7eSJed Brown /// v.iter_mut() 5869df49d7eSJed Brown /// .zip(u.iter().zip(weights.iter())) 5879df49d7eSJed Brown /// .for_each(|(v, (u, w))| *v = u * w); 5889df49d7eSJed Brown /// 5899df49d7eSJed Brown /// // Return clean error code 5909df49d7eSJed Brown /// 0 5919df49d7eSJed Brown /// }; 5929df49d7eSJed Brown /// 593c68be7a2SJeremy L Thompson /// let mut qf = ceed.q_function_interior(1, Box::new(user_f))?; 5949df49d7eSJed Brown /// 595c68be7a2SJeremy L Thompson /// qf = qf.input("u", 1, EvalMode::Interp)?; 596c68be7a2SJeremy L Thompson /// qf = qf.input("weights", 1, EvalMode::Weight)?; 597c68be7a2SJeremy L Thompson /// # Ok(()) 598c68be7a2SJeremy L Thompson /// # } 5999df49d7eSJed Brown /// ``` 6009df49d7eSJed Brown pub fn input( 6019df49d7eSJed Brown mut self, 6029df49d7eSJed Brown fieldname: &str, 6039df49d7eSJed Brown size: usize, 6049df49d7eSJed Brown emode: crate::EvalMode, 6059df49d7eSJed Brown ) -> crate::Result<Self> { 6069df49d7eSJed Brown let name_c = CString::new(fieldname).expect("CString::new failed"); 6079df49d7eSJed Brown let idx = self.trampoline_data.number_inputs; 6089df49d7eSJed Brown self.trampoline_data.input_sizes[idx] = size; 6099df49d7eSJed Brown self.trampoline_data.number_inputs += 1; 6109df49d7eSJed Brown let (size, emode) = ( 6119df49d7eSJed Brown i32::try_from(size).unwrap(), 6129df49d7eSJed Brown emode as bind_ceed::CeedEvalMode, 6139df49d7eSJed Brown ); 6149df49d7eSJed Brown let ierr = unsafe { 6159df49d7eSJed Brown bind_ceed::CeedQFunctionAddInput(self.qf_core.ptr, name_c.as_ptr(), size, emode) 6169df49d7eSJed Brown }; 617*1142270cSJeremy L Thompson self.qf_core.check_error(ierr)?; 6189df49d7eSJed Brown Ok(self) 6199df49d7eSJed Brown } 6209df49d7eSJed Brown 6219df49d7eSJed Brown /// Add a QFunction output 6229df49d7eSJed Brown /// 6239df49d7eSJed Brown /// * `fieldname` - Name of QFunction field 6249df49d7eSJed Brown /// * `size` - Size of QFunction field, `(ncomp * dim)` for `Grad` or 6259df49d7eSJed Brown /// `(ncomp * 1)` for `None` and `Interp` 6269df49d7eSJed Brown /// * `emode` - `EvalMode::None` to use values directly, `EvalMode::Interp` 6279df49d7eSJed Brown /// to use interpolated values, `EvalMode::Grad` to use 6289df49d7eSJed Brown /// gradients 6299df49d7eSJed Brown /// 6309df49d7eSJed Brown /// ``` 6319df49d7eSJed Brown /// # use libceed::prelude::*; 632c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 6339df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 6349df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 6359df49d7eSJed Brown /// // Iterate over quadrature points 6369df49d7eSJed Brown /// v.iter_mut() 6379df49d7eSJed Brown /// .zip(u.iter().zip(weights.iter())) 6389df49d7eSJed Brown /// .for_each(|(v, (u, w))| *v = u * w); 6399df49d7eSJed Brown /// 6409df49d7eSJed Brown /// // Return clean error code 6419df49d7eSJed Brown /// 0 6429df49d7eSJed Brown /// }; 6439df49d7eSJed Brown /// 644c68be7a2SJeremy L Thompson /// let mut qf = ceed.q_function_interior(1, Box::new(user_f))?; 6459df49d7eSJed Brown /// 646c68be7a2SJeremy L Thompson /// qf.output("v", 1, EvalMode::Interp)?; 647c68be7a2SJeremy L Thompson /// # Ok(()) 648c68be7a2SJeremy L Thompson /// # } 6499df49d7eSJed Brown /// ``` 6509df49d7eSJed Brown pub fn output( 6519df49d7eSJed Brown mut self, 6529df49d7eSJed Brown fieldname: &str, 6539df49d7eSJed Brown size: usize, 6549df49d7eSJed Brown emode: crate::EvalMode, 6559df49d7eSJed Brown ) -> crate::Result<Self> { 6569df49d7eSJed Brown let name_c = CString::new(fieldname).expect("CString::new failed"); 6579df49d7eSJed Brown let idx = self.trampoline_data.number_outputs; 6589df49d7eSJed Brown self.trampoline_data.output_sizes[idx] = size; 6599df49d7eSJed Brown self.trampoline_data.number_outputs += 1; 6609df49d7eSJed Brown let (size, emode) = ( 6619df49d7eSJed Brown i32::try_from(size).unwrap(), 6629df49d7eSJed Brown emode as bind_ceed::CeedEvalMode, 6639df49d7eSJed Brown ); 6649df49d7eSJed Brown let ierr = unsafe { 6659df49d7eSJed Brown bind_ceed::CeedQFunctionAddOutput(self.qf_core.ptr, name_c.as_ptr(), size, emode) 6669df49d7eSJed Brown }; 667*1142270cSJeremy L Thompson self.qf_core.check_error(ierr)?; 6689df49d7eSJed Brown Ok(self) 6699df49d7eSJed Brown } 6709df49d7eSJed Brown } 6719df49d7eSJed Brown 6729df49d7eSJed Brown // ----------------------------------------------------------------------------- 6739df49d7eSJed Brown // QFunction 6749df49d7eSJed Brown // ----------------------------------------------------------------------------- 6759df49d7eSJed Brown impl<'a> QFunctionByName<'a> { 6769df49d7eSJed Brown // Constructor 6779df49d7eSJed Brown pub fn create(ceed: &'a crate::Ceed, name: &str) -> crate::Result<Self> { 6789df49d7eSJed Brown let name_c = CString::new(name).expect("CString::new failed"); 6799df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 6809df49d7eSJed Brown let ierr = unsafe { 6819df49d7eSJed Brown bind_ceed::CeedQFunctionCreateInteriorByName(ceed.ptr, name_c.as_ptr(), &mut ptr) 6829df49d7eSJed Brown }; 6839df49d7eSJed Brown ceed.check_error(ierr)?; 6849df49d7eSJed Brown Ok(Self { 685*1142270cSJeremy L Thompson qf_core: QFunctionCore { 686*1142270cSJeremy L Thompson ptr, 687*1142270cSJeremy L Thompson _lifeline: PhantomData, 688*1142270cSJeremy L Thompson }, 6899df49d7eSJed Brown }) 6909df49d7eSJed Brown } 6919df49d7eSJed Brown 6929df49d7eSJed Brown /// Apply the action of a QFunction 6939df49d7eSJed Brown /// 6949df49d7eSJed Brown /// * `Q` - The number of quadrature points 6959df49d7eSJed Brown /// * `input` - Array of input Vectors 6969df49d7eSJed Brown /// * `output` - Array of output Vectors 6979df49d7eSJed Brown /// 6989df49d7eSJed Brown /// ``` 6999df49d7eSJed Brown /// # use libceed::prelude::*; 700c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 7019df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 7029df49d7eSJed Brown /// const Q: usize = 8; 703c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 704c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 7059df49d7eSJed Brown /// 7069df49d7eSJed Brown /// let mut j = [0.; Q]; 7079df49d7eSJed Brown /// let mut w = [0.; Q]; 7089df49d7eSJed Brown /// let mut u = [0.; Q]; 7099df49d7eSJed Brown /// let mut v = [0.; Q]; 7109df49d7eSJed Brown /// 7119df49d7eSJed Brown /// for i in 0..Q { 71280a9ef05SNatalie Beams /// let x = 2. * (i as Scalar) / ((Q as Scalar) - 1.) - 1.; 7139df49d7eSJed Brown /// j[i] = 1.; 7149df49d7eSJed Brown /// w[i] = 1. - x * x; 7159df49d7eSJed Brown /// u[i] = 2. + 3. * x + 5. * x * x; 7169df49d7eSJed Brown /// v[i] = w[i] * u[i]; 7179df49d7eSJed Brown /// } 7189df49d7eSJed Brown /// 719c68be7a2SJeremy L Thompson /// let jj = ceed.vector_from_slice(&j)?; 720c68be7a2SJeremy L Thompson /// let ww = ceed.vector_from_slice(&w)?; 721c68be7a2SJeremy L Thompson /// let uu = ceed.vector_from_slice(&u)?; 722c68be7a2SJeremy L Thompson /// let mut vv = ceed.vector(Q)?; 7239df49d7eSJed Brown /// vv.set_value(0.0); 724c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(Q)?; 7259df49d7eSJed Brown /// qdata.set_value(0.0); 7269df49d7eSJed Brown /// 7279df49d7eSJed Brown /// { 7289df49d7eSJed Brown /// let mut input = vec![jj, ww]; 7299df49d7eSJed Brown /// let mut output = vec![qdata]; 730c68be7a2SJeremy L Thompson /// qf_build.apply(Q, &input, &output)?; 7319df49d7eSJed Brown /// qdata = output.remove(0); 7329df49d7eSJed Brown /// } 7339df49d7eSJed Brown /// 7349df49d7eSJed Brown /// { 7359df49d7eSJed Brown /// let mut input = vec![qdata, uu]; 7369df49d7eSJed Brown /// let mut output = vec![vv]; 737c68be7a2SJeremy L Thompson /// qf_mass.apply(Q, &input, &output)?; 7389df49d7eSJed Brown /// vv = output.remove(0); 7399df49d7eSJed Brown /// } 7409df49d7eSJed Brown /// 7419df49d7eSJed Brown /// vv.view() 7429df49d7eSJed Brown /// .iter() 7439df49d7eSJed Brown /// .zip(v.iter()) 7449df49d7eSJed Brown /// .for_each(|(computed, actual)| { 7459df49d7eSJed Brown /// assert_eq!( 7469df49d7eSJed Brown /// *computed, *actual, 7479df49d7eSJed Brown /// "Incorrect value in QFunction application" 7489df49d7eSJed Brown /// ); 7499df49d7eSJed Brown /// }); 750c68be7a2SJeremy L Thompson /// # Ok(()) 751c68be7a2SJeremy L Thompson /// # } 7529df49d7eSJed Brown /// ``` 7539df49d7eSJed Brown pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> { 7549df49d7eSJed Brown self.qf_core.apply(Q, u, v) 7559df49d7eSJed Brown } 7569df49d7eSJed Brown } 7579df49d7eSJed Brown 7589df49d7eSJed Brown // ----------------------------------------------------------------------------- 759