1d275d636SJeremy L Thompson // Copyright (c) 2017-2025, Lawrence Livermore National Security, LLC and other CEED contributors. 23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 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 /// ``` 4708778c6fSJeremy L Thompson pub fn name(&self) -> &str { 4808778c6fSJeremy L Thompson let mut name_ptr: *mut std::os::raw::c_char = std::ptr::null_mut(); 4908778c6fSJeremy L Thompson unsafe { 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 /// ``` 7408778c6fSJeremy 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 /// ``` 10608778c6fSJeremy 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 } 111*bf55b007SJeremy 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> { 1269df49d7eSJed 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> { 1349df49d7eSJed 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 1429df49d7eSJed Brown 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 /// ``` 183e03682afSJeremy 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 /// ``` 224e03682afSJeremy 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 /// ``` 274e03682afSJeremy 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 /// ``` 315e03682afSJeremy 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> { 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> { 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> { 3779df49d7eSJed 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> { 4169df49d7eSJed 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> { 4339df49d7eSJed 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)] 44411544396SJeremy 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)] 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 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 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, 480*bf55b007SJeremy 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 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, 498*bf55b007SJeremy 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 } 5269df49d7eSJed 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 569a71fcd9fSJeremy L Thompson unsafe extern "C" fn destroy_trampoline(ctx: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int { 570a71fcd9fSJeremy L Thompson let trampoline_data: Pin<&mut QFunctionTrampolineData> = std::mem::transmute(ctx); 571a71fcd9fSJeremy L Thompson drop(trampoline_data); 572a71fcd9fSJeremy L Thompson 0 // Clean error code 573a71fcd9fSJeremy L Thompson } 574a71fcd9fSJeremy L Thompson 5759df49d7eSJed Brown // ----------------------------------------------------------------------------- 5769df49d7eSJed Brown // QFunction 5779df49d7eSJed Brown // ----------------------------------------------------------------------------- 5789df49d7eSJed Brown impl<'a> QFunction<'a> { 5799df49d7eSJed Brown // Constructor 5809df49d7eSJed Brown pub fn create( 581594ef120SJeremy L Thompson ceed: &crate::Ceed, 5829df49d7eSJed Brown vlength: usize, 5839df49d7eSJed Brown user_f: Box<QFunctionUserClosure>, 5849df49d7eSJed Brown ) -> crate::Result<Self> { 5859df49d7eSJed Brown let source_c = CString::new("").expect("CString::new failed"); 5869df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 5879df49d7eSJed Brown 5889df49d7eSJed Brown // Context for closure 5899df49d7eSJed Brown let number_inputs = 0; 5909df49d7eSJed Brown let number_outputs = 0; 5919df49d7eSJed Brown let input_sizes = [0; MAX_QFUNCTION_FIELDS]; 5929df49d7eSJed Brown let output_sizes = [0; MAX_QFUNCTION_FIELDS]; 5939df49d7eSJed Brown let trampoline_data = unsafe { 5949df49d7eSJed Brown Pin::new_unchecked(Box::new(QFunctionTrampolineData { 5959df49d7eSJed Brown number_inputs, 5969df49d7eSJed Brown number_outputs, 5979df49d7eSJed Brown input_sizes, 5989df49d7eSJed Brown output_sizes, 5999df49d7eSJed Brown user_f, 6009df49d7eSJed Brown })) 6019df49d7eSJed Brown }; 6029df49d7eSJed Brown 6039df49d7eSJed Brown // Create QFunction 6049df49d7eSJed Brown let vlength = i32::try_from(vlength).unwrap(); 605656ef1e5SJeremy L Thompson ceed.check_error(unsafe { 6069df49d7eSJed Brown bind_ceed::CeedQFunctionCreateInterior( 6079df49d7eSJed Brown ceed.ptr, 6089df49d7eSJed Brown vlength, 6099df49d7eSJed Brown Some(trampoline), 6109df49d7eSJed Brown source_c.as_ptr(), 6119df49d7eSJed Brown &mut ptr, 6129df49d7eSJed Brown ) 613656ef1e5SJeremy L Thompson })?; 6149df49d7eSJed Brown 6159df49d7eSJed Brown // Set closure 6169df49d7eSJed Brown let mut qf_ctx_ptr = std::ptr::null_mut(); 617656ef1e5SJeremy L Thompson ceed.check_error(unsafe { 618656ef1e5SJeremy L Thompson bind_ceed::CeedQFunctionContextCreate(ceed.ptr, &mut qf_ctx_ptr) 619656ef1e5SJeremy L Thompson })?; 620656ef1e5SJeremy L Thompson ceed.check_error(unsafe { 6219df49d7eSJed Brown bind_ceed::CeedQFunctionContextSetData( 6229df49d7eSJed Brown qf_ctx_ptr, 6239df49d7eSJed Brown crate::MemType::Host as bind_ceed::CeedMemType, 6249df49d7eSJed Brown crate::CopyMode::UsePointer as bind_ceed::CeedCopyMode, 625257916f8SJed Brown std::mem::size_of::<QFunctionTrampolineData>(), 6269df49d7eSJed Brown std::mem::transmute(trampoline_data.as_ref()), 6279df49d7eSJed Brown ) 628656ef1e5SJeremy L Thompson })?; 629656ef1e5SJeremy L Thompson ceed.check_error(unsafe { 630a71fcd9fSJeremy L Thompson bind_ceed::CeedQFunctionContextSetDataDestroy( 631a71fcd9fSJeremy L Thompson qf_ctx_ptr, 632a71fcd9fSJeremy L Thompson crate::MemType::Host as bind_ceed::CeedMemType, 633a71fcd9fSJeremy L Thompson Some(destroy_trampoline), 634a71fcd9fSJeremy L Thompson ) 635656ef1e5SJeremy L Thompson })?; 636656ef1e5SJeremy L Thompson ceed.check_error(unsafe { bind_ceed::CeedQFunctionSetContext(ptr, qf_ctx_ptr) })?; 637656ef1e5SJeremy L Thompson ceed.check_error(unsafe { bind_ceed::CeedQFunctionContextDestroy(&mut qf_ctx_ptr) })?; 6389df49d7eSJed Brown Ok(Self { 6391142270cSJeremy L Thompson qf_core: QFunctionCore { 6401142270cSJeremy L Thompson ptr, 6411142270cSJeremy L Thompson _lifeline: PhantomData, 6421142270cSJeremy L Thompson }, 6439df49d7eSJed Brown qf_ctx_ptr, 6449df49d7eSJed Brown trampoline_data, 6459df49d7eSJed Brown }) 6469df49d7eSJed Brown } 6479df49d7eSJed Brown 6489df49d7eSJed Brown /// Apply the action of a QFunction 6499df49d7eSJed Brown /// 6509df49d7eSJed Brown /// * `Q` - The number of quadrature points 6519df49d7eSJed Brown /// * `input` - Array of input Vectors 6529df49d7eSJed Brown /// * `output` - Array of output Vectors 6539df49d7eSJed Brown /// 6549df49d7eSJed Brown /// ``` 655eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs, Scalar}; 6564d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 6579df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 6589df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 6599df49d7eSJed Brown /// // Iterate over quadrature points 6609df49d7eSJed Brown /// v.iter_mut() 6619df49d7eSJed Brown /// .zip(u.iter().zip(weights.iter())) 6629df49d7eSJed Brown /// .for_each(|(v, (u, w))| *v = u * w); 6639df49d7eSJed Brown /// 6649df49d7eSJed Brown /// // Return clean error code 6659df49d7eSJed Brown /// 0 6669df49d7eSJed Brown /// }; 6679df49d7eSJed Brown /// 6689df49d7eSJed Brown /// let qf = ceed 669c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))? 670c68be7a2SJeremy L Thompson /// .input("u", 1, EvalMode::Interp)? 671c68be7a2SJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)? 672c68be7a2SJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?; 6739df49d7eSJed Brown /// 6749df49d7eSJed Brown /// const Q: usize = 8; 6759df49d7eSJed Brown /// let mut w = [0.; Q]; 6769df49d7eSJed Brown /// let mut u = [0.; Q]; 6779df49d7eSJed Brown /// let mut v = [0.; Q]; 6789df49d7eSJed Brown /// 6799df49d7eSJed Brown /// for i in 0..Q { 68080a9ef05SNatalie Beams /// let x = 2. * (i as Scalar) / ((Q as Scalar) - 1.) - 1.; 6819df49d7eSJed Brown /// u[i] = 2. + 3. * x + 5. * x * x; 6829df49d7eSJed Brown /// w[i] = 1. - x * x; 6839df49d7eSJed Brown /// v[i] = u[i] * w[i]; 6849df49d7eSJed Brown /// } 6859df49d7eSJed Brown /// 686c68be7a2SJeremy L Thompson /// let uu = ceed.vector_from_slice(&u)?; 687c68be7a2SJeremy L Thompson /// let ww = ceed.vector_from_slice(&w)?; 688c68be7a2SJeremy L Thompson /// let mut vv = ceed.vector(Q)?; 6899df49d7eSJed Brown /// vv.set_value(0.0); 6909df49d7eSJed Brown /// { 6919df49d7eSJed Brown /// let input = vec![uu, ww]; 6929df49d7eSJed Brown /// let mut output = vec![vv]; 693c68be7a2SJeremy L Thompson /// qf.apply(Q, &input, &output)?; 6949df49d7eSJed Brown /// vv = output.remove(0); 6959df49d7eSJed Brown /// } 6969df49d7eSJed Brown /// 697e78171edSJeremy L Thompson /// vv.view()? 6989df49d7eSJed Brown /// .iter() 6999df49d7eSJed Brown /// .zip(v.iter()) 7009df49d7eSJed Brown /// .for_each(|(computed, actual)| { 7019df49d7eSJed Brown /// assert_eq!( 7029df49d7eSJed Brown /// *computed, *actual, 7039df49d7eSJed Brown /// "Incorrect value in QFunction application" 7049df49d7eSJed Brown /// ); 7059df49d7eSJed Brown /// }); 706c68be7a2SJeremy L Thompson /// # Ok(()) 707c68be7a2SJeremy L Thompson /// # } 7089df49d7eSJed Brown /// ``` 7099df49d7eSJed Brown pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> { 7109df49d7eSJed Brown self.qf_core.apply(Q, u, v) 7119df49d7eSJed Brown } 7129df49d7eSJed Brown 7139df49d7eSJed Brown /// Add a QFunction input 7149df49d7eSJed Brown /// 7159df49d7eSJed Brown /// * `fieldname` - Name of QFunction field 7169df49d7eSJed Brown /// * `size` - Size of QFunction field, `(ncomp * dim)` for `Grad` or 7179df49d7eSJed Brown /// `(ncomp * 1)` for `None`, `Interp`, and `Weight` 7189df49d7eSJed Brown /// * `emode` - `EvalMode::None` to use values directly, `EvalMode::Interp` 7199df49d7eSJed Brown /// to use interpolated values, `EvalMode::Grad` to use 7209df49d7eSJed Brown /// gradients, `EvalMode::Weight` to use quadrature weights 7219df49d7eSJed Brown /// 7229df49d7eSJed Brown /// ``` 723eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs}; 7244d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 7259df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 7269df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 7279df49d7eSJed Brown /// // Iterate over quadrature points 7289df49d7eSJed Brown /// v.iter_mut() 7299df49d7eSJed Brown /// .zip(u.iter().zip(weights.iter())) 7309df49d7eSJed Brown /// .for_each(|(v, (u, w))| *v = u * w); 7319df49d7eSJed Brown /// 7329df49d7eSJed Brown /// // Return clean error code 7339df49d7eSJed Brown /// 0 7349df49d7eSJed Brown /// }; 7359df49d7eSJed Brown /// 736c68be7a2SJeremy L Thompson /// let mut qf = ceed.q_function_interior(1, Box::new(user_f))?; 7379df49d7eSJed Brown /// 738c68be7a2SJeremy L Thompson /// qf = qf.input("u", 1, EvalMode::Interp)?; 739c68be7a2SJeremy L Thompson /// qf = qf.input("weights", 1, EvalMode::Weight)?; 740c68be7a2SJeremy L Thompson /// # Ok(()) 741c68be7a2SJeremy L Thompson /// # } 7429df49d7eSJed Brown /// ``` 7439df49d7eSJed Brown pub fn input( 7449df49d7eSJed Brown mut self, 7459df49d7eSJed Brown fieldname: &str, 7469df49d7eSJed Brown size: usize, 7479df49d7eSJed Brown emode: crate::EvalMode, 7489df49d7eSJed Brown ) -> crate::Result<Self> { 7499df49d7eSJed Brown let name_c = CString::new(fieldname).expect("CString::new failed"); 7509df49d7eSJed Brown let idx = self.trampoline_data.number_inputs; 7519df49d7eSJed Brown self.trampoline_data.input_sizes[idx] = size; 7529df49d7eSJed Brown self.trampoline_data.number_inputs += 1; 7539df49d7eSJed Brown let (size, emode) = ( 7549df49d7eSJed Brown i32::try_from(size).unwrap(), 7559df49d7eSJed Brown emode as bind_ceed::CeedEvalMode, 7569df49d7eSJed Brown ); 757656ef1e5SJeremy L Thompson self.qf_core.check_error(unsafe { 7589df49d7eSJed Brown bind_ceed::CeedQFunctionAddInput(self.qf_core.ptr, name_c.as_ptr(), size, emode) 759656ef1e5SJeremy L Thompson })?; 7609df49d7eSJed Brown Ok(self) 7619df49d7eSJed Brown } 7629df49d7eSJed Brown 7639df49d7eSJed Brown /// Add a QFunction output 7649df49d7eSJed Brown /// 7659df49d7eSJed Brown /// * `fieldname` - Name of QFunction field 7669df49d7eSJed Brown /// * `size` - Size of QFunction field, `(ncomp * dim)` for `Grad` or 7679df49d7eSJed Brown /// `(ncomp * 1)` for `None` and `Interp` 7689df49d7eSJed Brown /// * `emode` - `EvalMode::None` to use values directly, `EvalMode::Interp` 7699df49d7eSJed Brown /// to use interpolated values, `EvalMode::Grad` to use 7709df49d7eSJed Brown /// gradients 7719df49d7eSJed Brown /// 7729df49d7eSJed Brown /// ``` 773eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs}; 7744d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 7759df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 7769df49d7eSJed Brown /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 7779df49d7eSJed Brown /// // Iterate over quadrature points 7789df49d7eSJed Brown /// v.iter_mut() 7799df49d7eSJed Brown /// .zip(u.iter().zip(weights.iter())) 7809df49d7eSJed Brown /// .for_each(|(v, (u, w))| *v = u * w); 7819df49d7eSJed Brown /// 7829df49d7eSJed Brown /// // Return clean error code 7839df49d7eSJed Brown /// 0 7849df49d7eSJed Brown /// }; 7859df49d7eSJed Brown /// 786c68be7a2SJeremy L Thompson /// let mut qf = ceed.q_function_interior(1, Box::new(user_f))?; 7879df49d7eSJed Brown /// 788c68be7a2SJeremy L Thompson /// qf.output("v", 1, EvalMode::Interp)?; 789c68be7a2SJeremy L Thompson /// # Ok(()) 790c68be7a2SJeremy L Thompson /// # } 7919df49d7eSJed Brown /// ``` 7929df49d7eSJed Brown pub fn output( 7939df49d7eSJed Brown mut self, 7949df49d7eSJed Brown fieldname: &str, 7959df49d7eSJed Brown size: usize, 7969df49d7eSJed Brown emode: crate::EvalMode, 7979df49d7eSJed Brown ) -> crate::Result<Self> { 7989df49d7eSJed Brown let name_c = CString::new(fieldname).expect("CString::new failed"); 7999df49d7eSJed Brown let idx = self.trampoline_data.number_outputs; 8009df49d7eSJed Brown self.trampoline_data.output_sizes[idx] = size; 8019df49d7eSJed Brown self.trampoline_data.number_outputs += 1; 8029df49d7eSJed Brown let (size, emode) = ( 8039df49d7eSJed Brown i32::try_from(size).unwrap(), 8049df49d7eSJed Brown emode as bind_ceed::CeedEvalMode, 8059df49d7eSJed Brown ); 806656ef1e5SJeremy L Thompson self.qf_core.check_error(unsafe { 8079df49d7eSJed Brown bind_ceed::CeedQFunctionAddOutput(self.qf_core.ptr, name_c.as_ptr(), size, emode) 808656ef1e5SJeremy L Thompson })?; 8099df49d7eSJed Brown Ok(self) 8109df49d7eSJed Brown } 81108778c6fSJeremy L Thompson 81208778c6fSJeremy L Thompson /// Get a slice of QFunction inputs 81308778c6fSJeremy L Thompson /// 81408778c6fSJeremy L Thompson /// ``` 815eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs}; 8164d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 81708778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 81808778c6fSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 81908778c6fSJeremy L Thompson /// // Iterate over quadrature points 82008778c6fSJeremy L Thompson /// v.iter_mut() 82108778c6fSJeremy L Thompson /// .zip(u.iter().zip(weights.iter())) 82208778c6fSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w); 82308778c6fSJeremy L Thompson /// 82408778c6fSJeremy L Thompson /// // Return clean error code 82508778c6fSJeremy L Thompson /// 0 82608778c6fSJeremy L Thompson /// }; 82708778c6fSJeremy L Thompson /// 82808778c6fSJeremy L Thompson /// let mut qf = ceed 82908778c6fSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))? 83008778c6fSJeremy L Thompson /// .input("u", 1, EvalMode::Interp)? 83108778c6fSJeremy L Thompson /// .input("weights", 1, EvalMode::Weight)?; 83208778c6fSJeremy L Thompson /// 83308778c6fSJeremy L Thompson /// let inputs = qf.inputs()?; 83408778c6fSJeremy L Thompson /// 83508778c6fSJeremy L Thompson /// assert_eq!(inputs.len(), 2, "Incorrect inputs array"); 83608778c6fSJeremy L Thompson /// # Ok(()) 83708778c6fSJeremy L Thompson /// # } 83808778c6fSJeremy L Thompson /// ``` 839eb07d68fSJeremy L Thompson pub fn inputs(&self) -> crate::Result<&[QFunctionField]> { 84008778c6fSJeremy L Thompson self.qf_core.inputs() 84108778c6fSJeremy L Thompson } 84208778c6fSJeremy L Thompson 84308778c6fSJeremy L Thompson /// Get a slice of QFunction outputs 84408778c6fSJeremy L Thompson /// 84508778c6fSJeremy L Thompson /// ``` 846eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs}; 8474d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 84808778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 84908778c6fSJeremy L Thompson /// let mut user_f = |[u, weights, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 85008778c6fSJeremy L Thompson /// // Iterate over quadrature points 85108778c6fSJeremy L Thompson /// v.iter_mut() 85208778c6fSJeremy L Thompson /// .zip(u.iter().zip(weights.iter())) 85308778c6fSJeremy L Thompson /// .for_each(|(v, (u, w))| *v = u * w); 85408778c6fSJeremy L Thompson /// 85508778c6fSJeremy L Thompson /// // Return clean error code 85608778c6fSJeremy L Thompson /// 0 85708778c6fSJeremy L Thompson /// }; 85808778c6fSJeremy L Thompson /// 85908778c6fSJeremy L Thompson /// let mut qf = ceed 86008778c6fSJeremy L Thompson /// .q_function_interior(1, Box::new(user_f))? 86108778c6fSJeremy L Thompson /// .output("v", 1, EvalMode::Interp)?; 86208778c6fSJeremy L Thompson /// 86308778c6fSJeremy L Thompson /// let outputs = qf.outputs()?; 86408778c6fSJeremy L Thompson /// 86508778c6fSJeremy L Thompson /// assert_eq!(outputs.len(), 1, "Incorrect outputs array"); 86608778c6fSJeremy L Thompson /// # Ok(()) 86708778c6fSJeremy L Thompson /// # } 86808778c6fSJeremy L Thompson /// ``` 869eb07d68fSJeremy L Thompson pub fn outputs(&self) -> crate::Result<&[QFunctionField]> { 87008778c6fSJeremy L Thompson self.qf_core.outputs() 87108778c6fSJeremy L Thompson } 8729df49d7eSJed Brown } 8739df49d7eSJed Brown 8749df49d7eSJed Brown // ----------------------------------------------------------------------------- 8759df49d7eSJed Brown // QFunction 8769df49d7eSJed Brown // ----------------------------------------------------------------------------- 8779df49d7eSJed Brown impl<'a> QFunctionByName<'a> { 8789df49d7eSJed Brown // Constructor 879594ef120SJeremy L Thompson pub fn create(ceed: &crate::Ceed, name: &str) -> crate::Result<Self> { 8809df49d7eSJed Brown let name_c = CString::new(name).expect("CString::new failed"); 8819df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 882656ef1e5SJeremy L Thompson ceed.check_error(unsafe { 8839df49d7eSJed Brown bind_ceed::CeedQFunctionCreateInteriorByName(ceed.ptr, name_c.as_ptr(), &mut ptr) 884656ef1e5SJeremy L Thompson })?; 8859df49d7eSJed Brown Ok(Self { 8861142270cSJeremy L Thompson qf_core: QFunctionCore { 8871142270cSJeremy L Thompson ptr, 8881142270cSJeremy L Thompson _lifeline: PhantomData, 8891142270cSJeremy L Thompson }, 8909df49d7eSJed Brown }) 8919df49d7eSJed Brown } 8929df49d7eSJed Brown 8939df49d7eSJed Brown /// Apply the action of a QFunction 8949df49d7eSJed Brown /// 8959df49d7eSJed Brown /// * `Q` - The number of quadrature points 8969df49d7eSJed Brown /// * `input` - Array of input Vectors 8979df49d7eSJed Brown /// * `output` - Array of output Vectors 8989df49d7eSJed Brown /// 8999df49d7eSJed Brown /// ``` 900eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, EvalMode, QFunctionInputs, QFunctionOutputs, Scalar}; 9014d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 9029df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 9039df49d7eSJed Brown /// const Q: usize = 8; 904c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 905c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 9069df49d7eSJed Brown /// 9079df49d7eSJed Brown /// let mut j = [0.; Q]; 9089df49d7eSJed Brown /// let mut w = [0.; Q]; 9099df49d7eSJed Brown /// let mut u = [0.; Q]; 9109df49d7eSJed Brown /// let mut v = [0.; Q]; 9119df49d7eSJed Brown /// 9129df49d7eSJed Brown /// for i in 0..Q { 91380a9ef05SNatalie Beams /// let x = 2. * (i as Scalar) / ((Q as Scalar) - 1.) - 1.; 9149df49d7eSJed Brown /// j[i] = 1.; 9159df49d7eSJed Brown /// w[i] = 1. - x * x; 9169df49d7eSJed Brown /// u[i] = 2. + 3. * x + 5. * x * x; 9179df49d7eSJed Brown /// v[i] = w[i] * u[i]; 9189df49d7eSJed Brown /// } 9199df49d7eSJed Brown /// 920c68be7a2SJeremy L Thompson /// let jj = ceed.vector_from_slice(&j)?; 921c68be7a2SJeremy L Thompson /// let ww = ceed.vector_from_slice(&w)?; 922c68be7a2SJeremy L Thompson /// let uu = ceed.vector_from_slice(&u)?; 923c68be7a2SJeremy L Thompson /// let mut vv = ceed.vector(Q)?; 9249df49d7eSJed Brown /// vv.set_value(0.0); 925c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(Q)?; 9269df49d7eSJed Brown /// qdata.set_value(0.0); 9279df49d7eSJed Brown /// 9289df49d7eSJed Brown /// { 9299df49d7eSJed Brown /// let mut input = vec![jj, ww]; 9309df49d7eSJed Brown /// let mut output = vec![qdata]; 931c68be7a2SJeremy L Thompson /// qf_build.apply(Q, &input, &output)?; 9329df49d7eSJed Brown /// qdata = output.remove(0); 9339df49d7eSJed Brown /// } 9349df49d7eSJed Brown /// 9359df49d7eSJed Brown /// { 9369df49d7eSJed Brown /// let mut input = vec![qdata, uu]; 9379df49d7eSJed Brown /// let mut output = vec![vv]; 938c68be7a2SJeremy L Thompson /// qf_mass.apply(Q, &input, &output)?; 9399df49d7eSJed Brown /// vv = output.remove(0); 9409df49d7eSJed Brown /// } 9419df49d7eSJed Brown /// 942e78171edSJeremy L Thompson /// vv.view()? 9439df49d7eSJed Brown /// .iter() 9449df49d7eSJed Brown /// .zip(v.iter()) 9459df49d7eSJed Brown /// .for_each(|(computed, actual)| { 9469df49d7eSJed Brown /// assert_eq!( 9479df49d7eSJed Brown /// *computed, *actual, 9489df49d7eSJed Brown /// "Incorrect value in QFunction application" 9499df49d7eSJed Brown /// ); 9509df49d7eSJed Brown /// }); 951c68be7a2SJeremy L Thompson /// # Ok(()) 952c68be7a2SJeremy L Thompson /// # } 9539df49d7eSJed Brown /// ``` 9549df49d7eSJed Brown pub fn apply(&self, Q: usize, u: &[Vector], v: &[Vector]) -> crate::Result<i32> { 9559df49d7eSJed Brown self.qf_core.apply(Q, u, v) 9569df49d7eSJed Brown } 95708778c6fSJeremy L Thompson 95808778c6fSJeremy L Thompson /// Get a slice of QFunction inputs 95908778c6fSJeremy L Thompson /// 96008778c6fSJeremy L Thompson /// ``` 96108778c6fSJeremy L Thompson /// # use libceed::prelude::*; 9624d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 96308778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 96408778c6fSJeremy L Thompson /// const Q: usize = 8; 96508778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 96608778c6fSJeremy L Thompson /// 96708778c6fSJeremy L Thompson /// let inputs = qf.inputs()?; 96808778c6fSJeremy L Thompson /// 96908778c6fSJeremy L Thompson /// assert_eq!(inputs.len(), 2, "Incorrect inputs array"); 97008778c6fSJeremy L Thompson /// # Ok(()) 97108778c6fSJeremy L Thompson /// # } 97208778c6fSJeremy L Thompson /// ``` 973eb07d68fSJeremy L Thompson pub fn inputs(&self) -> crate::Result<&[QFunctionField]> { 97408778c6fSJeremy L Thompson self.qf_core.inputs() 97508778c6fSJeremy L Thompson } 97608778c6fSJeremy L Thompson 97708778c6fSJeremy L Thompson /// Get a slice of QFunction outputs 97808778c6fSJeremy L Thompson /// 97908778c6fSJeremy L Thompson /// ``` 98008778c6fSJeremy L Thompson /// # use libceed::prelude::*; 9814d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 98208778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 98308778c6fSJeremy L Thompson /// const Q: usize = 8; 98408778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 98508778c6fSJeremy L Thompson /// 98608778c6fSJeremy L Thompson /// let outputs = qf.outputs()?; 98708778c6fSJeremy L Thompson /// 98808778c6fSJeremy L Thompson /// assert_eq!(outputs.len(), 1, "Incorrect outputs array"); 98908778c6fSJeremy L Thompson /// # Ok(()) 99008778c6fSJeremy L Thompson /// # } 99108778c6fSJeremy L Thompson /// ``` 992eb07d68fSJeremy L Thompson pub fn outputs(&self) -> crate::Result<&[QFunctionField]> { 99308778c6fSJeremy L Thompson self.qf_core.outputs() 99408778c6fSJeremy L Thompson } 9959df49d7eSJed Brown } 9969df49d7eSJed Brown 9979df49d7eSJed Brown // ----------------------------------------------------------------------------- 998