15aed82e4SJeremy L Thompson // Copyright (c) 2017-2024, 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 Operator defines the finite/spectral element operator associated to a 99df49d7eSJed Brown //! Ceed QFunction. A Ceed Operator connects Ceed ElemRestrictions, 109df49d7eSJed Brown //! Ceed Bases, and Ceed QFunctions. 119df49d7eSJed Brown 129df49d7eSJed Brown use crate::prelude::*; 139df49d7eSJed Brown 149df49d7eSJed Brown // ----------------------------------------------------------------------------- 157ed177dbSJed Brown // Operator Field context wrapper 1608778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 1708778c6fSJeremy L Thompson #[derive(Debug)] 1808778c6fSJeremy L Thompson pub struct OperatorField<'a> { 1908778c6fSJeremy L Thompson pub(crate) ptr: bind_ceed::CeedOperatorField, 20e03fef56SJeremy L Thompson pub(crate) vector: crate::Vector<'a>, 21e03fef56SJeremy L Thompson pub(crate) elem_restriction: crate::ElemRestriction<'a>, 22e03fef56SJeremy L Thompson pub(crate) basis: crate::Basis<'a>, 2308778c6fSJeremy L Thompson _lifeline: PhantomData<&'a ()>, 2408778c6fSJeremy L Thompson } 2508778c6fSJeremy L Thompson 2608778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 2708778c6fSJeremy L Thompson // Implementations 2808778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 2908778c6fSJeremy L Thompson impl<'a> OperatorField<'a> { 30e03fef56SJeremy L Thompson pub(crate) fn from_raw( 31e03fef56SJeremy L Thompson ptr: bind_ceed::CeedOperatorField, 32e03fef56SJeremy L Thompson ceed: crate::Ceed, 33e03fef56SJeremy L Thompson ) -> crate::Result<Self> { 34e03fef56SJeremy L Thompson let vector = { 35e03fef56SJeremy L Thompson let mut vector_ptr = std::ptr::null_mut(); 36*656ef1e5SJeremy L Thompson ceed.check_error(unsafe { 37*656ef1e5SJeremy L Thompson bind_ceed::CeedOperatorFieldGetVector(ptr, &mut vector_ptr) 38*656ef1e5SJeremy L Thompson })?; 39e03fef56SJeremy L Thompson crate::Vector::from_raw(vector_ptr)? 40e03fef56SJeremy L Thompson }; 41e03fef56SJeremy L Thompson let elem_restriction = { 42e03fef56SJeremy L Thompson let mut elem_restriction_ptr = std::ptr::null_mut(); 43*656ef1e5SJeremy L Thompson ceed.check_error(unsafe { 44e03fef56SJeremy L Thompson bind_ceed::CeedOperatorFieldGetElemRestriction(ptr, &mut elem_restriction_ptr) 45*656ef1e5SJeremy L Thompson })?; 46e03fef56SJeremy L Thompson crate::ElemRestriction::from_raw(elem_restriction_ptr)? 47e03fef56SJeremy L Thompson }; 48e03fef56SJeremy L Thompson let basis = { 49e03fef56SJeremy L Thompson let mut basis_ptr = std::ptr::null_mut(); 50*656ef1e5SJeremy L Thompson ceed.check_error(unsafe { bind_ceed::CeedOperatorFieldGetBasis(ptr, &mut basis_ptr) })?; 51e03fef56SJeremy L Thompson crate::Basis::from_raw(basis_ptr)? 52e03fef56SJeremy L Thompson }; 53e03fef56SJeremy L Thompson Ok(Self { 54e03fef56SJeremy L Thompson ptr, 55e03fef56SJeremy L Thompson vector, 56e03fef56SJeremy L Thompson elem_restriction, 57e03fef56SJeremy L Thompson basis, 58e03fef56SJeremy L Thompson _lifeline: PhantomData, 59e03fef56SJeremy L Thompson }) 60e03fef56SJeremy L Thompson } 61e03fef56SJeremy L Thompson 6208778c6fSJeremy L Thompson /// Get the name of an OperatorField 6308778c6fSJeremy L Thompson /// 6408778c6fSJeremy L Thompson /// ``` 6508778c6fSJeremy L Thompson /// # use libceed::prelude::*; 664d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 6708778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 6808778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 6908778c6fSJeremy L Thompson /// 7008778c6fSJeremy L Thompson /// // Operator field arguments 7108778c6fSJeremy L Thompson /// let ne = 3; 7208778c6fSJeremy L Thompson /// let q = 4 as usize; 7308778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 7408778c6fSJeremy L Thompson /// for i in 0..ne { 7508778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 7608778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 7708778c6fSJeremy L Thompson /// } 7808778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 7908778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 80d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 8108778c6fSJeremy L Thompson /// 8208778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 8308778c6fSJeremy L Thompson /// 8408778c6fSJeremy L Thompson /// // Operator fields 8508778c6fSJeremy L Thompson /// let op = ceed 8608778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 8708778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 8808778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 89356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 9008778c6fSJeremy L Thompson /// 9108778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 9208778c6fSJeremy L Thompson /// 9308778c6fSJeremy L Thompson /// assert_eq!(inputs[0].name(), "dx", "Incorrect input name"); 9408778c6fSJeremy L Thompson /// assert_eq!(inputs[1].name(), "weights", "Incorrect input name"); 9508778c6fSJeremy L Thompson /// # Ok(()) 9608778c6fSJeremy L Thompson /// # } 9708778c6fSJeremy L Thompson /// ``` 9808778c6fSJeremy L Thompson pub fn name(&self) -> &str { 9908778c6fSJeremy L Thompson let mut name_ptr: *mut std::os::raw::c_char = std::ptr::null_mut(); 10008778c6fSJeremy L Thompson unsafe { 1016f8994e9SJeremy L Thompson bind_ceed::CeedOperatorFieldGetName( 1026f8994e9SJeremy L Thompson self.ptr, 1036f8994e9SJeremy L Thompson &mut name_ptr as *const _ as *mut *const _, 1046f8994e9SJeremy L Thompson ); 10508778c6fSJeremy L Thompson } 10608778c6fSJeremy L Thompson unsafe { CStr::from_ptr(name_ptr) }.to_str().unwrap() 10708778c6fSJeremy L Thompson } 10808778c6fSJeremy L Thompson 10908778c6fSJeremy L Thompson /// Get the ElemRestriction of an OperatorField 11008778c6fSJeremy L Thompson /// 11108778c6fSJeremy L Thompson /// ``` 11208778c6fSJeremy L Thompson /// # use libceed::prelude::*; 1134d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 11408778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 11508778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 11608778c6fSJeremy L Thompson /// 11708778c6fSJeremy L Thompson /// // Operator field arguments 11808778c6fSJeremy L Thompson /// let ne = 3; 11908778c6fSJeremy L Thompson /// let q = 4 as usize; 12008778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 12108778c6fSJeremy L Thompson /// for i in 0..ne { 12208778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 12308778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 12408778c6fSJeremy L Thompson /// } 12508778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 12608778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 127d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 12808778c6fSJeremy L Thompson /// 12908778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 13008778c6fSJeremy L Thompson /// 13108778c6fSJeremy L Thompson /// // Operator fields 13208778c6fSJeremy L Thompson /// let op = ceed 13308778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 13408778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 13508778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 136356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 13708778c6fSJeremy L Thompson /// 13808778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 13908778c6fSJeremy L Thompson /// 14008778c6fSJeremy L Thompson /// assert!( 14108778c6fSJeremy L Thompson /// inputs[0].elem_restriction().is_some(), 14208778c6fSJeremy L Thompson /// "Incorrect field ElemRestriction" 14308778c6fSJeremy L Thompson /// ); 144567c3c29SJeremy L Thompson /// if let ElemRestrictionOpt::Some(r) = inputs[0].elem_restriction() { 145567c3c29SJeremy L Thompson /// assert_eq!( 146567c3c29SJeremy L Thompson /// r.num_elements(), 147567c3c29SJeremy L Thompson /// ne, 148567c3c29SJeremy L Thompson /// "Incorrect field ElemRestriction number of elements" 149567c3c29SJeremy L Thompson /// ); 150567c3c29SJeremy L Thompson /// } 151567c3c29SJeremy L Thompson /// 15208778c6fSJeremy L Thompson /// assert!( 15308778c6fSJeremy L Thompson /// inputs[1].elem_restriction().is_none(), 15408778c6fSJeremy L Thompson /// "Incorrect field ElemRestriction" 15508778c6fSJeremy L Thompson /// ); 156e03fef56SJeremy L Thompson /// 157e03fef56SJeremy L Thompson /// let outputs = op.outputs()?; 158e03fef56SJeremy L Thompson /// 159e03fef56SJeremy L Thompson /// assert!( 160e03fef56SJeremy L Thompson /// outputs[0].elem_restriction().is_some(), 161e03fef56SJeremy L Thompson /// "Incorrect field ElemRestriction" 162e03fef56SJeremy L Thompson /// ); 163567c3c29SJeremy L Thompson /// if let ElemRestrictionOpt::Some(r) = outputs[0].elem_restriction() { 164567c3c29SJeremy L Thompson /// assert_eq!( 165567c3c29SJeremy L Thompson /// r.num_elements(), 166567c3c29SJeremy L Thompson /// ne, 167567c3c29SJeremy L Thompson /// "Incorrect field ElemRestriction number of elements" 168567c3c29SJeremy L Thompson /// ); 169567c3c29SJeremy L Thompson /// } 17008778c6fSJeremy L Thompson /// # Ok(()) 17108778c6fSJeremy L Thompson /// # } 17208778c6fSJeremy L Thompson /// ``` 17308778c6fSJeremy L Thompson pub fn elem_restriction(&self) -> ElemRestrictionOpt { 174e03fef56SJeremy L Thompson if self.elem_restriction.ptr == unsafe { bind_ceed::CEED_ELEMRESTRICTION_NONE } { 17508778c6fSJeremy L Thompson ElemRestrictionOpt::None 17608778c6fSJeremy L Thompson } else { 177e03fef56SJeremy L Thompson ElemRestrictionOpt::Some(&self.elem_restriction) 17808778c6fSJeremy L Thompson } 17908778c6fSJeremy L Thompson } 18008778c6fSJeremy L Thompson 18108778c6fSJeremy L Thompson /// Get the Basis of an OperatorField 18208778c6fSJeremy L Thompson /// 18308778c6fSJeremy L Thompson /// ``` 18408778c6fSJeremy L Thompson /// # use libceed::prelude::*; 1854d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 18608778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 18708778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 18808778c6fSJeremy L Thompson /// 18908778c6fSJeremy L Thompson /// // Operator field arguments 19008778c6fSJeremy L Thompson /// let ne = 3; 19108778c6fSJeremy L Thompson /// let q = 4 as usize; 19208778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 19308778c6fSJeremy L Thompson /// for i in 0..ne { 19408778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 19508778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 19608778c6fSJeremy L Thompson /// } 19708778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 19808778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 199d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 20008778c6fSJeremy L Thompson /// 20108778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 20208778c6fSJeremy L Thompson /// 20308778c6fSJeremy L Thompson /// // Operator fields 20408778c6fSJeremy L Thompson /// let op = ceed 20508778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 20608778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 20708778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 208356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 20908778c6fSJeremy L Thompson /// 21008778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 21108778c6fSJeremy L Thompson /// 21208778c6fSJeremy L Thompson /// assert!(inputs[0].basis().is_some(), "Incorrect field Basis"); 213567c3c29SJeremy L Thompson /// if let BasisOpt::Some(b) = inputs[0].basis() { 214567c3c29SJeremy L Thompson /// assert_eq!( 215567c3c29SJeremy L Thompson /// b.num_quadrature_points(), 216567c3c29SJeremy L Thompson /// q, 217567c3c29SJeremy L Thompson /// "Incorrect field Basis number of quadrature points" 218567c3c29SJeremy L Thompson /// ); 219567c3c29SJeremy L Thompson /// } 22008778c6fSJeremy L Thompson /// assert!(inputs[1].basis().is_some(), "Incorrect field Basis"); 221567c3c29SJeremy L Thompson /// if let BasisOpt::Some(b) = inputs[1].basis() { 222567c3c29SJeremy L Thompson /// assert_eq!( 223567c3c29SJeremy L Thompson /// b.num_quadrature_points(), 224567c3c29SJeremy L Thompson /// q, 225567c3c29SJeremy L Thompson /// "Incorrect field Basis number of quadrature points" 226567c3c29SJeremy L Thompson /// ); 227567c3c29SJeremy L Thompson /// } 22808778c6fSJeremy L Thompson /// 22908778c6fSJeremy L Thompson /// let outputs = op.outputs()?; 23008778c6fSJeremy L Thompson /// 231356036faSJeremy L Thompson /// assert!(outputs[0].basis().is_none(), "Incorrect field Basis"); 23208778c6fSJeremy L Thompson /// # Ok(()) 23308778c6fSJeremy L Thompson /// # } 23408778c6fSJeremy L Thompson /// ``` 23508778c6fSJeremy L Thompson pub fn basis(&self) -> BasisOpt { 236e03fef56SJeremy L Thompson if self.basis.ptr == unsafe { bind_ceed::CEED_BASIS_NONE } { 237356036faSJeremy L Thompson BasisOpt::None 23808778c6fSJeremy L Thompson } else { 239e03fef56SJeremy L Thompson BasisOpt::Some(&self.basis) 24008778c6fSJeremy L Thompson } 24108778c6fSJeremy L Thompson } 24208778c6fSJeremy L Thompson 24308778c6fSJeremy L Thompson /// Get the Vector of an OperatorField 24408778c6fSJeremy L Thompson /// 24508778c6fSJeremy L Thompson /// ``` 24608778c6fSJeremy L Thompson /// # use libceed::prelude::*; 2474d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 24808778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 24908778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 25008778c6fSJeremy L Thompson /// 25108778c6fSJeremy L Thompson /// // Operator field arguments 25208778c6fSJeremy L Thompson /// let ne = 3; 25308778c6fSJeremy L Thompson /// let q = 4 as usize; 25408778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 25508778c6fSJeremy L Thompson /// for i in 0..ne { 25608778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 25708778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 25808778c6fSJeremy L Thompson /// } 25908778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 26008778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 261d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 26208778c6fSJeremy L Thompson /// 26308778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 26408778c6fSJeremy L Thompson /// 26508778c6fSJeremy L Thompson /// // Operator fields 26608778c6fSJeremy L Thompson /// let op = ceed 26708778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 26808778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 26908778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 270356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 27108778c6fSJeremy L Thompson /// 27208778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 27308778c6fSJeremy L Thompson /// 27408778c6fSJeremy L Thompson /// assert!(inputs[0].vector().is_active(), "Incorrect field Vector"); 27508778c6fSJeremy L Thompson /// assert!(inputs[1].vector().is_none(), "Incorrect field Vector"); 276e03fef56SJeremy L Thompson /// 277e03fef56SJeremy L Thompson /// let outputs = op.outputs()?; 278e03fef56SJeremy L Thompson /// 279e03fef56SJeremy L Thompson /// assert!(outputs[0].vector().is_active(), "Incorrect field Vector"); 28008778c6fSJeremy L Thompson /// # Ok(()) 28108778c6fSJeremy L Thompson /// # } 28208778c6fSJeremy L Thompson /// ``` 28308778c6fSJeremy L Thompson pub fn vector(&self) -> VectorOpt { 284e03fef56SJeremy L Thompson if self.vector.ptr == unsafe { bind_ceed::CEED_VECTOR_ACTIVE } { 28508778c6fSJeremy L Thompson VectorOpt::Active 286e03fef56SJeremy L Thompson } else if self.vector.ptr == unsafe { bind_ceed::CEED_VECTOR_NONE } { 28708778c6fSJeremy L Thompson VectorOpt::None 28808778c6fSJeremy L Thompson } else { 289e03fef56SJeremy L Thompson VectorOpt::Some(&self.vector) 29008778c6fSJeremy L Thompson } 29108778c6fSJeremy L Thompson } 29208778c6fSJeremy L Thompson } 29308778c6fSJeremy L Thompson 29408778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 2957ed177dbSJed Brown // Operator context wrapper 2969df49d7eSJed Brown // ----------------------------------------------------------------------------- 297c68be7a2SJeremy L Thompson #[derive(Debug)] 2989df49d7eSJed Brown pub(crate) struct OperatorCore<'a> { 2999df49d7eSJed Brown ptr: bind_ceed::CeedOperator, 3001142270cSJeremy L Thompson _lifeline: PhantomData<&'a ()>, 3019df49d7eSJed Brown } 3029df49d7eSJed Brown 303c68be7a2SJeremy L Thompson #[derive(Debug)] 3049df49d7eSJed Brown pub struct Operator<'a> { 3059df49d7eSJed Brown op_core: OperatorCore<'a>, 3069df49d7eSJed Brown } 3079df49d7eSJed Brown 308c68be7a2SJeremy L Thompson #[derive(Debug)] 3099df49d7eSJed Brown pub struct CompositeOperator<'a> { 3109df49d7eSJed Brown op_core: OperatorCore<'a>, 3119df49d7eSJed Brown } 3129df49d7eSJed Brown 3139df49d7eSJed Brown // ----------------------------------------------------------------------------- 3149df49d7eSJed Brown // Destructor 3159df49d7eSJed Brown // ----------------------------------------------------------------------------- 3169df49d7eSJed Brown impl<'a> Drop for OperatorCore<'a> { 3179df49d7eSJed Brown fn drop(&mut self) { 3189df49d7eSJed Brown unsafe { 3199df49d7eSJed Brown bind_ceed::CeedOperatorDestroy(&mut self.ptr); 3209df49d7eSJed Brown } 3219df49d7eSJed Brown } 3229df49d7eSJed Brown } 3239df49d7eSJed Brown 3249df49d7eSJed Brown // ----------------------------------------------------------------------------- 3259df49d7eSJed Brown // Display 3269df49d7eSJed Brown // ----------------------------------------------------------------------------- 3279df49d7eSJed Brown impl<'a> fmt::Display for OperatorCore<'a> { 3289df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 3299df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 3309df49d7eSJed Brown let mut sizeloc = crate::MAX_BUFFER_LENGTH; 3319df49d7eSJed Brown let cstring = unsafe { 3329df49d7eSJed Brown let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc); 3339df49d7eSJed Brown bind_ceed::CeedOperatorView(self.ptr, file); 3349df49d7eSJed Brown bind_ceed::fclose(file); 3359df49d7eSJed Brown CString::from_raw(ptr) 3369df49d7eSJed Brown }; 3379df49d7eSJed Brown cstring.to_string_lossy().fmt(f) 3389df49d7eSJed Brown } 3399df49d7eSJed Brown } 3409df49d7eSJed Brown 3419df49d7eSJed Brown /// View an Operator 3429df49d7eSJed Brown /// 3439df49d7eSJed Brown /// ``` 3449df49d7eSJed Brown /// # use libceed::prelude::*; 3454d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 3469df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 347c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 3489df49d7eSJed Brown /// 3499df49d7eSJed Brown /// // Operator field arguments 3509df49d7eSJed Brown /// let ne = 3; 3519df49d7eSJed Brown /// let q = 4 as usize; 3529df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 3539df49d7eSJed Brown /// for i in 0..ne { 3549df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 3559df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 3569df49d7eSJed Brown /// } 357c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 3589df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 359d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 3609df49d7eSJed Brown /// 361c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 3629df49d7eSJed Brown /// 3639df49d7eSJed Brown /// // Operator fields 3649df49d7eSJed Brown /// let op = ceed 365c68be7a2SJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 366ea6b5821SJeremy L Thompson /// .name("mass")? 367c68be7a2SJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 368c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 369356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 3709df49d7eSJed Brown /// 3719df49d7eSJed Brown /// println!("{}", op); 372c68be7a2SJeremy L Thompson /// # Ok(()) 373c68be7a2SJeremy L Thompson /// # } 3749df49d7eSJed Brown /// ``` 3759df49d7eSJed Brown impl<'a> fmt::Display for Operator<'a> { 3769df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 3779df49d7eSJed Brown self.op_core.fmt(f) 3789df49d7eSJed Brown } 3799df49d7eSJed Brown } 3809df49d7eSJed Brown 3819df49d7eSJed Brown /// View a composite Operator 3829df49d7eSJed Brown /// 3839df49d7eSJed Brown /// ``` 3849df49d7eSJed Brown /// # use libceed::prelude::*; 3854d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 3869df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 3879df49d7eSJed Brown /// 3889df49d7eSJed Brown /// // Sub operator field arguments 3899df49d7eSJed Brown /// let ne = 3; 3909df49d7eSJed Brown /// let q = 4 as usize; 3919df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 3929df49d7eSJed Brown /// for i in 0..ne { 3939df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 3949df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 3959df49d7eSJed Brown /// } 396c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 3979df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 398d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 3999df49d7eSJed Brown /// 400c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 4019df49d7eSJed Brown /// 402c68be7a2SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?; 403c68be7a2SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?; 4049df49d7eSJed Brown /// 405c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 4069df49d7eSJed Brown /// let op_mass = ceed 407c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 408ea6b5821SJeremy L Thompson /// .name("Mass term")? 409c68be7a2SJeremy L Thompson /// .field("u", &r, &b, VectorOpt::Active)? 410356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_mass)? 411c68be7a2SJeremy L Thompson /// .field("v", &r, &b, VectorOpt::Active)?; 4129df49d7eSJed Brown /// 413c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 4149df49d7eSJed Brown /// let op_diff = ceed 415c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 416ea6b5821SJeremy L Thompson /// .name("Poisson term")? 417c68be7a2SJeremy L Thompson /// .field("du", &r, &b, VectorOpt::Active)? 418356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_diff)? 419c68be7a2SJeremy L Thompson /// .field("dv", &r, &b, VectorOpt::Active)?; 4209df49d7eSJed Brown /// 4219df49d7eSJed Brown /// let op = ceed 422c68be7a2SJeremy L Thompson /// .composite_operator()? 423ea6b5821SJeremy L Thompson /// .name("Screened Poisson")? 424c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 425c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 4269df49d7eSJed Brown /// 4279df49d7eSJed Brown /// println!("{}", op); 428c68be7a2SJeremy L Thompson /// # Ok(()) 429c68be7a2SJeremy L Thompson /// # } 4309df49d7eSJed Brown /// ``` 4319df49d7eSJed Brown impl<'a> fmt::Display for CompositeOperator<'a> { 4329df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 4339df49d7eSJed Brown self.op_core.fmt(f) 4349df49d7eSJed Brown } 4359df49d7eSJed Brown } 4369df49d7eSJed Brown 4379df49d7eSJed Brown // ----------------------------------------------------------------------------- 4389df49d7eSJed Brown // Core functionality 4399df49d7eSJed Brown // ----------------------------------------------------------------------------- 4409df49d7eSJed Brown impl<'a> OperatorCore<'a> { 44111544396SJeremy L Thompson // Raw Ceed for error handling 44211544396SJeremy L Thompson #[doc(hidden)] 44311544396SJeremy L Thompson fn ceed(&self) -> bind_ceed::Ceed { 44411544396SJeremy L Thompson unsafe { bind_ceed::CeedOperatorReturnCeed(self.ptr) } 44511544396SJeremy L Thompson } 44611544396SJeremy L Thompson 4471142270cSJeremy L Thompson // Error handling 4481142270cSJeremy L Thompson #[doc(hidden)] 4491142270cSJeremy L Thompson fn check_error(&self, ierr: i32) -> crate::Result<i32> { 45011544396SJeremy L Thompson crate::check_error(|| self.ceed(), ierr) 4511142270cSJeremy L Thompson } 4521142270cSJeremy L Thompson 4539df49d7eSJed Brown // Common implementations 4546f97ff0aSJeremy L Thompson pub fn check(&self) -> crate::Result<i32> { 455*656ef1e5SJeremy L Thompson self.check_error(unsafe { bind_ceed::CeedOperatorCheckReady(self.ptr) }) 4566f97ff0aSJeremy L Thompson } 4576f97ff0aSJeremy L Thompson 458ea6b5821SJeremy L Thompson pub fn name(&self, name: &str) -> crate::Result<i32> { 459ea6b5821SJeremy L Thompson let name_c = CString::new(name).expect("CString::new failed"); 460*656ef1e5SJeremy L Thompson self.check_error(unsafe { bind_ceed::CeedOperatorSetName(self.ptr, name_c.as_ptr()) }) 461ea6b5821SJeremy L Thompson } 462ea6b5821SJeremy L Thompson 4639df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 464*656ef1e5SJeremy L Thompson self.check_error(unsafe { 4659df49d7eSJed Brown bind_ceed::CeedOperatorApply( 4669df49d7eSJed Brown self.ptr, 4679df49d7eSJed Brown input.ptr, 4689df49d7eSJed Brown output.ptr, 4699df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4709df49d7eSJed Brown ) 471*656ef1e5SJeremy L Thompson }) 4729df49d7eSJed Brown } 4739df49d7eSJed Brown 4749df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 475*656ef1e5SJeremy L Thompson self.check_error(unsafe { 4769df49d7eSJed Brown bind_ceed::CeedOperatorApplyAdd( 4779df49d7eSJed Brown self.ptr, 4789df49d7eSJed Brown input.ptr, 4799df49d7eSJed Brown output.ptr, 4809df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4819df49d7eSJed Brown ) 482*656ef1e5SJeremy L Thompson }) 4839df49d7eSJed Brown } 4849df49d7eSJed Brown 4859df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 486*656ef1e5SJeremy L Thompson self.check_error(unsafe { 4879df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleDiagonal( 4889df49d7eSJed Brown self.ptr, 4899df49d7eSJed Brown assembled.ptr, 4909df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4919df49d7eSJed Brown ) 492*656ef1e5SJeremy L Thompson }) 4939df49d7eSJed Brown } 4949df49d7eSJed Brown 4959df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 496*656ef1e5SJeremy L Thompson self.check_error(unsafe { 4979df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddDiagonal( 4989df49d7eSJed Brown self.ptr, 4999df49d7eSJed Brown assembled.ptr, 5009df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 5019df49d7eSJed Brown ) 502*656ef1e5SJeremy L Thompson }) 5039df49d7eSJed Brown } 5049df49d7eSJed Brown 5059df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 5069df49d7eSJed Brown &self, 5079df49d7eSJed Brown assembled: &mut Vector, 5089df49d7eSJed Brown ) -> crate::Result<i32> { 509*656ef1e5SJeremy L Thompson self.check_error(unsafe { 5109df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssemblePointBlockDiagonal( 5119df49d7eSJed Brown self.ptr, 5129df49d7eSJed Brown assembled.ptr, 5139df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 5149df49d7eSJed Brown ) 515*656ef1e5SJeremy L Thompson }) 5169df49d7eSJed Brown } 5179df49d7eSJed Brown 5189df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 5199df49d7eSJed Brown &self, 5209df49d7eSJed Brown assembled: &mut Vector, 5219df49d7eSJed Brown ) -> crate::Result<i32> { 522*656ef1e5SJeremy L Thompson self.check_error(unsafe { 5239df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddPointBlockDiagonal( 5249df49d7eSJed Brown self.ptr, 5259df49d7eSJed Brown assembled.ptr, 5269df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 5279df49d7eSJed Brown ) 528*656ef1e5SJeremy L Thompson }) 5299df49d7eSJed Brown } 5309df49d7eSJed Brown } 5319df49d7eSJed Brown 5329df49d7eSJed Brown // ----------------------------------------------------------------------------- 5339df49d7eSJed Brown // Operator 5349df49d7eSJed Brown // ----------------------------------------------------------------------------- 5359df49d7eSJed Brown impl<'a> Operator<'a> { 5369df49d7eSJed Brown // Constructor 5379df49d7eSJed Brown pub fn create<'b>( 538594ef120SJeremy L Thompson ceed: &crate::Ceed, 5399df49d7eSJed Brown qf: impl Into<QFunctionOpt<'b>>, 5409df49d7eSJed Brown dqf: impl Into<QFunctionOpt<'b>>, 5419df49d7eSJed Brown dqfT: impl Into<QFunctionOpt<'b>>, 5429df49d7eSJed Brown ) -> crate::Result<Self> { 5439df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 544*656ef1e5SJeremy L Thompson ceed.check_error(unsafe { 5459df49d7eSJed Brown bind_ceed::CeedOperatorCreate( 5469df49d7eSJed Brown ceed.ptr, 5479df49d7eSJed Brown qf.into().to_raw(), 5489df49d7eSJed Brown dqf.into().to_raw(), 5499df49d7eSJed Brown dqfT.into().to_raw(), 5509df49d7eSJed Brown &mut ptr, 5519df49d7eSJed Brown ) 552*656ef1e5SJeremy L Thompson })?; 5539df49d7eSJed Brown Ok(Self { 5541142270cSJeremy L Thompson op_core: OperatorCore { 5551142270cSJeremy L Thompson ptr, 5561142270cSJeremy L Thompson _lifeline: PhantomData, 5571142270cSJeremy L Thompson }, 5589df49d7eSJed Brown }) 5599df49d7eSJed Brown } 5609df49d7eSJed Brown 5611142270cSJeremy L Thompson fn from_raw(ptr: bind_ceed::CeedOperator) -> crate::Result<Self> { 5629df49d7eSJed Brown Ok(Self { 5631142270cSJeremy L Thompson op_core: OperatorCore { 5641142270cSJeremy L Thompson ptr, 5651142270cSJeremy L Thompson _lifeline: PhantomData, 5661142270cSJeremy L Thompson }, 5679df49d7eSJed Brown }) 5689df49d7eSJed Brown } 5699df49d7eSJed Brown 570ea6b5821SJeremy L Thompson /// Set name for Operator printing 571ea6b5821SJeremy L Thompson /// 572ea6b5821SJeremy L Thompson /// * 'name' - Name to set 573ea6b5821SJeremy L Thompson /// 574ea6b5821SJeremy L Thompson /// ``` 575ea6b5821SJeremy L Thompson /// # use libceed::prelude::*; 576ea6b5821SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 577ea6b5821SJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 578ea6b5821SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 579ea6b5821SJeremy L Thompson /// 580ea6b5821SJeremy L Thompson /// // Operator field arguments 581ea6b5821SJeremy L Thompson /// let ne = 3; 582ea6b5821SJeremy L Thompson /// let q = 4 as usize; 583ea6b5821SJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 584ea6b5821SJeremy L Thompson /// for i in 0..ne { 585ea6b5821SJeremy L Thompson /// ind[2 * i + 0] = i as i32; 586ea6b5821SJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 587ea6b5821SJeremy L Thompson /// } 588ea6b5821SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 589ea6b5821SJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 590d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 591ea6b5821SJeremy L Thompson /// 592ea6b5821SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 593ea6b5821SJeremy L Thompson /// 594ea6b5821SJeremy L Thompson /// // Operator fields 595ea6b5821SJeremy L Thompson /// let op = ceed 596ea6b5821SJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 597ea6b5821SJeremy L Thompson /// .name("mass")? 598ea6b5821SJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 599ea6b5821SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 600356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 601ea6b5821SJeremy L Thompson /// # Ok(()) 602ea6b5821SJeremy L Thompson /// # } 603ea6b5821SJeremy L Thompson /// ``` 604ea6b5821SJeremy L Thompson #[allow(unused_mut)] 605ea6b5821SJeremy L Thompson pub fn name(mut self, name: &str) -> crate::Result<Self> { 606ea6b5821SJeremy L Thompson self.op_core.name(name)?; 607ea6b5821SJeremy L Thompson Ok(self) 608ea6b5821SJeremy L Thompson } 609ea6b5821SJeremy L Thompson 6109df49d7eSJed Brown /// Apply Operator to a vector 6119df49d7eSJed Brown /// 6129df49d7eSJed Brown /// * `input` - Input Vector 6139df49d7eSJed Brown /// * `output` - Output Vector 6149df49d7eSJed Brown /// 6159df49d7eSJed Brown /// ``` 6169df49d7eSJed Brown /// # use libceed::prelude::*; 6174d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 6189df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 6199df49d7eSJed Brown /// let ne = 4; 6209df49d7eSJed Brown /// let p = 3; 6219df49d7eSJed Brown /// let q = 4; 6229df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 6239df49d7eSJed Brown /// 6249df49d7eSJed Brown /// // Vectors 625c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 626c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 6279df49d7eSJed Brown /// qdata.set_value(0.0); 628c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 629c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 6309df49d7eSJed Brown /// v.set_value(0.0); 6319df49d7eSJed Brown /// 6329df49d7eSJed Brown /// // Restrictions 6339df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 6349df49d7eSJed Brown /// for i in 0..ne { 6359df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 6369df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 6379df49d7eSJed Brown /// } 638c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 6399df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 6409df49d7eSJed Brown /// for i in 0..ne { 6419df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 6429df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 6439df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 6449df49d7eSJed Brown /// } 645c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 6469df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 647c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 6489df49d7eSJed Brown /// 6499df49d7eSJed Brown /// // Bases 650c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 651c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 6529df49d7eSJed Brown /// 6539df49d7eSJed Brown /// // Build quadrature data 654c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 655c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 656c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 657c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 658356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 659c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 6609df49d7eSJed Brown /// 6619df49d7eSJed Brown /// // Mass operator 662c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 6639df49d7eSJed Brown /// let op_mass = ceed 664c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 665c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 666356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 667c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 6689df49d7eSJed Brown /// 6699df49d7eSJed Brown /// v.set_value(0.0); 670c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 6719df49d7eSJed Brown /// 6729df49d7eSJed Brown /// // Check 673e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 6744b61a5a0SRezgar Shakeri /// let error: Scalar = (sum - 2.0).abs(); 6759df49d7eSJed Brown /// assert!( 6764b61a5a0SRezgar Shakeri /// error < 50.0 * libceed::EPSILON, 6774b61a5a0SRezgar Shakeri /// "Incorrect interval length computed. Expected: 2.0, Found: {}, Error: {:.12e}", 6784b61a5a0SRezgar Shakeri /// sum, 6794b61a5a0SRezgar Shakeri /// error 6809df49d7eSJed Brown /// ); 681c68be7a2SJeremy L Thompson /// # Ok(()) 682c68be7a2SJeremy L Thompson /// # } 6839df49d7eSJed Brown /// ``` 6849df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 6859df49d7eSJed Brown self.op_core.apply(input, output) 6869df49d7eSJed Brown } 6879df49d7eSJed Brown 6889df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 6899df49d7eSJed Brown /// 6909df49d7eSJed Brown /// * `input` - Input Vector 6919df49d7eSJed Brown /// * `output` - Output Vector 6929df49d7eSJed Brown /// 6939df49d7eSJed Brown /// ``` 6949df49d7eSJed Brown /// # use libceed::prelude::*; 6954d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 6969df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 6979df49d7eSJed Brown /// let ne = 4; 6989df49d7eSJed Brown /// let p = 3; 6999df49d7eSJed Brown /// let q = 4; 7009df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 7019df49d7eSJed Brown /// 7029df49d7eSJed Brown /// // Vectors 703c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 704c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 7059df49d7eSJed Brown /// qdata.set_value(0.0); 706c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 707c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 7089df49d7eSJed Brown /// 7099df49d7eSJed Brown /// // Restrictions 7109df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 7119df49d7eSJed Brown /// for i in 0..ne { 7129df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 7139df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 7149df49d7eSJed Brown /// } 715c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 7169df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 7179df49d7eSJed Brown /// for i in 0..ne { 7189df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 7199df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 7209df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 7219df49d7eSJed Brown /// } 722c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 7239df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 724c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 7259df49d7eSJed Brown /// 7269df49d7eSJed Brown /// // Bases 727c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 728c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 7299df49d7eSJed Brown /// 7309df49d7eSJed Brown /// // Build quadrature data 731c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 732c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 733c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 734c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 735356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 736c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 7379df49d7eSJed Brown /// 7389df49d7eSJed Brown /// // Mass operator 739c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 7409df49d7eSJed Brown /// let op_mass = ceed 741c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 742c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 743356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 744c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 7459df49d7eSJed Brown /// 7469df49d7eSJed Brown /// v.set_value(1.0); 747c68be7a2SJeremy L Thompson /// op_mass.apply_add(&u, &mut v)?; 7489df49d7eSJed Brown /// 7499df49d7eSJed Brown /// // Check 750e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 7519df49d7eSJed Brown /// assert!( 75280a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 7539df49d7eSJed Brown /// "Incorrect interval length computed and added" 7549df49d7eSJed Brown /// ); 755c68be7a2SJeremy L Thompson /// # Ok(()) 756c68be7a2SJeremy L Thompson /// # } 7579df49d7eSJed Brown /// ``` 7589df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 7599df49d7eSJed Brown self.op_core.apply_add(input, output) 7609df49d7eSJed Brown } 7619df49d7eSJed Brown 7629df49d7eSJed Brown /// Provide a field to a Operator for use by its QFunction 7639df49d7eSJed Brown /// 7649df49d7eSJed Brown /// * `fieldname` - Name of the field (to be matched with the name used by 7659df49d7eSJed Brown /// the QFunction) 7669df49d7eSJed Brown /// * `r` - ElemRestriction 767356036faSJeremy L Thompson /// * `b` - Basis in which the field resides or `BasisOpt::None` 768356036faSJeremy L Thompson /// * `v` - Vector to be used by Operator or `VectorOpt::Active` if field 769356036faSJeremy L Thompson /// is active or `VectorOpt::None` if using `Weight` with the 7709df49d7eSJed Brown /// QFunction 7719df49d7eSJed Brown /// 7729df49d7eSJed Brown /// 7739df49d7eSJed Brown /// ``` 7749df49d7eSJed Brown /// # use libceed::prelude::*; 7754d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 7769df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 777c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 778c68be7a2SJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 7799df49d7eSJed Brown /// 7809df49d7eSJed Brown /// // Operator field arguments 7819df49d7eSJed Brown /// let ne = 3; 7829df49d7eSJed Brown /// let q = 4; 7839df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 7849df49d7eSJed Brown /// for i in 0..ne { 7859df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 7869df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 7879df49d7eSJed Brown /// } 788c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 7899df49d7eSJed Brown /// 790c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 7919df49d7eSJed Brown /// 7929df49d7eSJed Brown /// // Operator field 793c68be7a2SJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 794c68be7a2SJeremy L Thompson /// # Ok(()) 795c68be7a2SJeremy L Thompson /// # } 7969df49d7eSJed Brown /// ``` 7979df49d7eSJed Brown #[allow(unused_mut)] 7989df49d7eSJed Brown pub fn field<'b>( 7999df49d7eSJed Brown mut self, 8009df49d7eSJed Brown fieldname: &str, 8019df49d7eSJed Brown r: impl Into<ElemRestrictionOpt<'b>>, 8029df49d7eSJed Brown b: impl Into<BasisOpt<'b>>, 8039df49d7eSJed Brown v: impl Into<VectorOpt<'b>>, 8049df49d7eSJed Brown ) -> crate::Result<Self> { 8059df49d7eSJed Brown let fieldname = CString::new(fieldname).expect("CString::new failed"); 8069df49d7eSJed Brown let fieldname = fieldname.as_ptr() as *const i8; 807*656ef1e5SJeremy L Thompson self.op_core.check_error(unsafe { 8089df49d7eSJed Brown bind_ceed::CeedOperatorSetField( 8099df49d7eSJed Brown self.op_core.ptr, 8109df49d7eSJed Brown fieldname, 8119df49d7eSJed Brown r.into().to_raw(), 8129df49d7eSJed Brown b.into().to_raw(), 8139df49d7eSJed Brown v.into().to_raw(), 8149df49d7eSJed Brown ) 815*656ef1e5SJeremy L Thompson })?; 8169df49d7eSJed Brown Ok(self) 8179df49d7eSJed Brown } 8189df49d7eSJed Brown 81908778c6fSJeremy L Thompson /// Get a slice of Operator inputs 82008778c6fSJeremy L Thompson /// 82108778c6fSJeremy L Thompson /// ``` 82208778c6fSJeremy L Thompson /// # use libceed::prelude::*; 8234d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 82408778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 82508778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 82608778c6fSJeremy L Thompson /// 82708778c6fSJeremy L Thompson /// // Operator field arguments 82808778c6fSJeremy L Thompson /// let ne = 3; 82908778c6fSJeremy L Thompson /// let q = 4 as usize; 83008778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 83108778c6fSJeremy L Thompson /// for i in 0..ne { 83208778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 83308778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 83408778c6fSJeremy L Thompson /// } 83508778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 83608778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 837d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 83808778c6fSJeremy L Thompson /// 83908778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 84008778c6fSJeremy L Thompson /// 84108778c6fSJeremy L Thompson /// // Operator fields 84208778c6fSJeremy L Thompson /// let op = ceed 84308778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 84408778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 84508778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 846356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 84708778c6fSJeremy L Thompson /// 84808778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 84908778c6fSJeremy L Thompson /// 85008778c6fSJeremy L Thompson /// assert_eq!(inputs.len(), 2, "Incorrect inputs array"); 85108778c6fSJeremy L Thompson /// # Ok(()) 85208778c6fSJeremy L Thompson /// # } 85308778c6fSJeremy L Thompson /// ``` 854e03fef56SJeremy L Thompson pub fn inputs(&self) -> crate::Result<Vec<crate::OperatorField>> { 85508778c6fSJeremy L Thompson // Get array of raw C pointers for inputs 85608778c6fSJeremy L Thompson let mut num_inputs = 0; 85708778c6fSJeremy L Thompson let mut inputs_ptr = std::ptr::null_mut(); 858*656ef1e5SJeremy L Thompson self.op_core.check_error(unsafe { 85908778c6fSJeremy L Thompson bind_ceed::CeedOperatorGetFields( 86008778c6fSJeremy L Thompson self.op_core.ptr, 86108778c6fSJeremy L Thompson &mut num_inputs, 86208778c6fSJeremy L Thompson &mut inputs_ptr, 86308778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt, 86408778c6fSJeremy L Thompson std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField, 86508778c6fSJeremy L Thompson ) 866*656ef1e5SJeremy L Thompson })?; 86708778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice 86808778c6fSJeremy L Thompson let inputs_slice = unsafe { 86908778c6fSJeremy L Thompson std::slice::from_raw_parts( 870e03fef56SJeremy L Thompson inputs_ptr as *mut bind_ceed::CeedOperatorField, 87108778c6fSJeremy L Thompson num_inputs as usize, 87208778c6fSJeremy L Thompson ) 87308778c6fSJeremy L Thompson }; 874e03fef56SJeremy L Thompson // And finally build vec 875e03fef56SJeremy L Thompson let ceed = { 876*656ef1e5SJeremy L Thompson let ceed_raw = self.op_core.ceed(); 877e03fef56SJeremy L Thompson let mut ptr = std::ptr::null_mut(); 878e03fef56SJeremy L Thompson unsafe { 879*656ef1e5SJeremy L Thompson bind_ceed::CeedReferenceCopy(ceed_raw, &mut ptr); // refcount 880e03fef56SJeremy L Thompson } 881e03fef56SJeremy L Thompson crate::Ceed { ptr } 882e03fef56SJeremy L Thompson }; 883e03fef56SJeremy L Thompson let inputs = (0..num_inputs as usize) 884e03fef56SJeremy L Thompson .map(|i| crate::OperatorField::from_raw(inputs_slice[i], ceed.clone())) 885e03fef56SJeremy L Thompson .collect::<crate::Result<Vec<_>>>()?; 886e03fef56SJeremy L Thompson Ok(inputs) 88708778c6fSJeremy L Thompson } 88808778c6fSJeremy L Thompson 88908778c6fSJeremy L Thompson /// Get a slice of Operator outputs 89008778c6fSJeremy L Thompson /// 89108778c6fSJeremy L Thompson /// ``` 89208778c6fSJeremy L Thompson /// # use libceed::prelude::*; 8934d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 89408778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 89508778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 89608778c6fSJeremy L Thompson /// 89708778c6fSJeremy L Thompson /// // Operator field arguments 89808778c6fSJeremy L Thompson /// let ne = 3; 89908778c6fSJeremy L Thompson /// let q = 4 as usize; 90008778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 90108778c6fSJeremy L Thompson /// for i in 0..ne { 90208778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 90308778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 90408778c6fSJeremy L Thompson /// } 90508778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 90608778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 907d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 90808778c6fSJeremy L Thompson /// 90908778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 91008778c6fSJeremy L Thompson /// 91108778c6fSJeremy L Thompson /// // Operator fields 91208778c6fSJeremy L Thompson /// let op = ceed 91308778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 91408778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 91508778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 916356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 91708778c6fSJeremy L Thompson /// 91808778c6fSJeremy L Thompson /// let outputs = op.outputs()?; 91908778c6fSJeremy L Thompson /// 92008778c6fSJeremy L Thompson /// assert_eq!(outputs.len(), 1, "Incorrect outputs array"); 92108778c6fSJeremy L Thompson /// # Ok(()) 92208778c6fSJeremy L Thompson /// # } 92308778c6fSJeremy L Thompson /// ``` 924e03fef56SJeremy L Thompson pub fn outputs(&self) -> crate::Result<Vec<crate::OperatorField>> { 92508778c6fSJeremy L Thompson // Get array of raw C pointers for outputs 92608778c6fSJeremy L Thompson let mut num_outputs = 0; 92708778c6fSJeremy L Thompson let mut outputs_ptr = std::ptr::null_mut(); 928*656ef1e5SJeremy L Thompson self.op_core.check_error(unsafe { 92908778c6fSJeremy L Thompson bind_ceed::CeedOperatorGetFields( 93008778c6fSJeremy L Thompson self.op_core.ptr, 93108778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt, 93208778c6fSJeremy L Thompson std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField, 93308778c6fSJeremy L Thompson &mut num_outputs, 93408778c6fSJeremy L Thompson &mut outputs_ptr, 93508778c6fSJeremy L Thompson ) 936*656ef1e5SJeremy L Thompson })?; 93708778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice 93808778c6fSJeremy L Thompson let outputs_slice = unsafe { 93908778c6fSJeremy L Thompson std::slice::from_raw_parts( 940e03fef56SJeremy L Thompson outputs_ptr as *mut bind_ceed::CeedOperatorField, 94108778c6fSJeremy L Thompson num_outputs as usize, 94208778c6fSJeremy L Thompson ) 94308778c6fSJeremy L Thompson }; 944e03fef56SJeremy L Thompson // And finally build vec 945e03fef56SJeremy L Thompson let ceed = { 946*656ef1e5SJeremy L Thompson let ceed_raw = self.op_core.ceed(); 947e03fef56SJeremy L Thompson let mut ptr = std::ptr::null_mut(); 948e03fef56SJeremy L Thompson unsafe { 949*656ef1e5SJeremy L Thompson bind_ceed::CeedReferenceCopy(ceed_raw, &mut ptr); // refcount 950e03fef56SJeremy L Thompson } 951e03fef56SJeremy L Thompson crate::Ceed { ptr } 952e03fef56SJeremy L Thompson }; 953e03fef56SJeremy L Thompson let outputs = (0..num_outputs as usize) 954e03fef56SJeremy L Thompson .map(|i| crate::OperatorField::from_raw(outputs_slice[i], ceed.clone())) 955e03fef56SJeremy L Thompson .collect::<crate::Result<Vec<_>>>()?; 956e03fef56SJeremy L Thompson Ok(outputs) 95708778c6fSJeremy L Thompson } 95808778c6fSJeremy L Thompson 9596f97ff0aSJeremy L Thompson /// Check if Operator is setup correctly 9606f97ff0aSJeremy L Thompson /// 9616f97ff0aSJeremy L Thompson /// ``` 9626f97ff0aSJeremy L Thompson /// # use libceed::prelude::*; 9636f97ff0aSJeremy L Thompson /// # fn main() -> libceed::Result<()> { 9646f97ff0aSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 9656f97ff0aSJeremy L Thompson /// let ne = 4; 9666f97ff0aSJeremy L Thompson /// let p = 3; 9676f97ff0aSJeremy L Thompson /// let q = 4; 9686f97ff0aSJeremy L Thompson /// let ndofs = p * ne - ne + 1; 9696f97ff0aSJeremy L Thompson /// 9706f97ff0aSJeremy L Thompson /// // Restrictions 9716f97ff0aSJeremy L Thompson /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 9726f97ff0aSJeremy L Thompson /// for i in 0..ne { 9736f97ff0aSJeremy L Thompson /// indx[2 * i + 0] = i as i32; 9746f97ff0aSJeremy L Thompson /// indx[2 * i + 1] = (i + 1) as i32; 9756f97ff0aSJeremy L Thompson /// } 9766f97ff0aSJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 9776f97ff0aSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 9786f97ff0aSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 9796f97ff0aSJeremy L Thompson /// 9806f97ff0aSJeremy L Thompson /// // Bases 9816f97ff0aSJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 9826f97ff0aSJeremy L Thompson /// 9836f97ff0aSJeremy L Thompson /// // Build quadrature data 9846f97ff0aSJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 9856f97ff0aSJeremy L Thompson /// let op_build = ceed 9866f97ff0aSJeremy L Thompson /// .operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 9876f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 9886f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 989356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 9906f97ff0aSJeremy L Thompson /// 9916f97ff0aSJeremy L Thompson /// // Check 9926f97ff0aSJeremy L Thompson /// assert!(op_build.check().is_ok(), "Operator setup incorrectly"); 9936f97ff0aSJeremy L Thompson /// # Ok(()) 9946f97ff0aSJeremy L Thompson /// # } 9956f97ff0aSJeremy L Thompson /// ``` 9966f97ff0aSJeremy L Thompson pub fn check(self) -> crate::Result<Self> { 9976f97ff0aSJeremy L Thompson self.op_core.check()?; 9986f97ff0aSJeremy L Thompson Ok(self) 9996f97ff0aSJeremy L Thompson } 10006f97ff0aSJeremy L Thompson 10013f2759cfSJeremy L Thompson /// Get the number of elements associated with an Operator 10023f2759cfSJeremy L Thompson /// 10033f2759cfSJeremy L Thompson /// 10043f2759cfSJeremy L Thompson /// ``` 10053f2759cfSJeremy L Thompson /// # use libceed::prelude::*; 10064d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 10073f2759cfSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 10083f2759cfSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 10093f2759cfSJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 10103f2759cfSJeremy L Thompson /// 10113f2759cfSJeremy L Thompson /// // Operator field arguments 10123f2759cfSJeremy L Thompson /// let ne = 3; 10133f2759cfSJeremy L Thompson /// let q = 4; 10143f2759cfSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 10153f2759cfSJeremy L Thompson /// for i in 0..ne { 10163f2759cfSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 10173f2759cfSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 10183f2759cfSJeremy L Thompson /// } 10193f2759cfSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 10203f2759cfSJeremy L Thompson /// 10213f2759cfSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 10223f2759cfSJeremy L Thompson /// 10233f2759cfSJeremy L Thompson /// // Operator field 10243f2759cfSJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 10253f2759cfSJeremy L Thompson /// 10263f2759cfSJeremy L Thompson /// // Check number of elements 10273f2759cfSJeremy L Thompson /// assert_eq!(op.num_elements(), ne, "Incorrect number of elements"); 10283f2759cfSJeremy L Thompson /// # Ok(()) 10293f2759cfSJeremy L Thompson /// # } 10303f2759cfSJeremy L Thompson /// ``` 10313f2759cfSJeremy L Thompson pub fn num_elements(&self) -> usize { 10323f2759cfSJeremy L Thompson let mut nelem = 0; 10333f2759cfSJeremy L Thompson unsafe { bind_ceed::CeedOperatorGetNumElements(self.op_core.ptr, &mut nelem) }; 10343f2759cfSJeremy L Thompson usize::try_from(nelem).unwrap() 10353f2759cfSJeremy L Thompson } 10363f2759cfSJeremy L Thompson 10373f2759cfSJeremy L Thompson /// Get the number of quadrature points associated with each element of 10383f2759cfSJeremy L Thompson /// an Operator 10393f2759cfSJeremy L Thompson /// 10403f2759cfSJeremy L Thompson /// 10413f2759cfSJeremy L Thompson /// ``` 10423f2759cfSJeremy L Thompson /// # use libceed::prelude::*; 10434d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 10443f2759cfSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 10453f2759cfSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 10463f2759cfSJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 10473f2759cfSJeremy L Thompson /// 10483f2759cfSJeremy L Thompson /// // Operator field arguments 10493f2759cfSJeremy L Thompson /// let ne = 3; 10503f2759cfSJeremy L Thompson /// let q = 4; 10513f2759cfSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 10523f2759cfSJeremy L Thompson /// for i in 0..ne { 10533f2759cfSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 10543f2759cfSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 10553f2759cfSJeremy L Thompson /// } 10563f2759cfSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 10573f2759cfSJeremy L Thompson /// 10583f2759cfSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 10593f2759cfSJeremy L Thompson /// 10603f2759cfSJeremy L Thompson /// // Operator field 10613f2759cfSJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 10623f2759cfSJeremy L Thompson /// 10633f2759cfSJeremy L Thompson /// // Check number of quadrature points 10643f2759cfSJeremy L Thompson /// assert_eq!( 10653f2759cfSJeremy L Thompson /// op.num_quadrature_points(), 10663f2759cfSJeremy L Thompson /// q, 10673f2759cfSJeremy L Thompson /// "Incorrect number of quadrature points" 10683f2759cfSJeremy L Thompson /// ); 10693f2759cfSJeremy L Thompson /// # Ok(()) 10703f2759cfSJeremy L Thompson /// # } 10713f2759cfSJeremy L Thompson /// ``` 10723f2759cfSJeremy L Thompson pub fn num_quadrature_points(&self) -> usize { 10733f2759cfSJeremy L Thompson let mut Q = 0; 10743f2759cfSJeremy L Thompson unsafe { bind_ceed::CeedOperatorGetNumQuadraturePoints(self.op_core.ptr, &mut Q) }; 10753f2759cfSJeremy L Thompson usize::try_from(Q).unwrap() 10763f2759cfSJeremy L Thompson } 10773f2759cfSJeremy L Thompson 10789df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 10799df49d7eSJed Brown /// 10809df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 10819df49d7eSJed Brown /// 10829df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 10839df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 10849df49d7eSJed Brown /// 10859df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 10869df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 10879df49d7eSJed Brown /// 10889df49d7eSJed Brown /// ``` 10899df49d7eSJed Brown /// # use libceed::prelude::*; 10904d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 10919df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 10929df49d7eSJed Brown /// let ne = 4; 10939df49d7eSJed Brown /// let p = 3; 10949df49d7eSJed Brown /// let q = 4; 10959df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 10969df49d7eSJed Brown /// 10979df49d7eSJed Brown /// // Vectors 1098c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1099c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 11009df49d7eSJed Brown /// qdata.set_value(0.0); 1101c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 11029df49d7eSJed Brown /// u.set_value(1.0); 1103c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 11049df49d7eSJed Brown /// v.set_value(0.0); 11059df49d7eSJed Brown /// 11069df49d7eSJed Brown /// // Restrictions 11079df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 11089df49d7eSJed Brown /// for i in 0..ne { 11099df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 11109df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 11119df49d7eSJed Brown /// } 1112c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 11139df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 11149df49d7eSJed Brown /// for i in 0..ne { 11159df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 11169df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 11179df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 11189df49d7eSJed Brown /// } 1119c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 11209df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1121c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 11229df49d7eSJed Brown /// 11239df49d7eSJed Brown /// // Bases 1124c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1125c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 11269df49d7eSJed Brown /// 11279df49d7eSJed Brown /// // Build quadrature data 1128c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1129c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1130c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1131c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1132356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1133c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 11349df49d7eSJed Brown /// 11359df49d7eSJed Brown /// // Mass operator 1136c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 11379df49d7eSJed Brown /// let op_mass = ceed 1138c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1139c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1140356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1141c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 11429df49d7eSJed Brown /// 11439df49d7eSJed Brown /// // Diagonal 1144c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 11459df49d7eSJed Brown /// diag.set_value(0.0); 1146c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_diagonal(&mut diag)?; 11479df49d7eSJed Brown /// 11489df49d7eSJed Brown /// // Manual diagonal computation 1149c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 11509c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 11519df49d7eSJed Brown /// for i in 0..ndofs { 11529df49d7eSJed Brown /// u.set_value(0.0); 11539df49d7eSJed Brown /// { 1154e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 11559df49d7eSJed Brown /// u_array[i] = 1.; 11569df49d7eSJed Brown /// } 11579df49d7eSJed Brown /// 1158c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 11599df49d7eSJed Brown /// 11609df49d7eSJed Brown /// { 11619c774eddSJeremy L Thompson /// let v_array = v.view()?; 1162e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 11639df49d7eSJed Brown /// true_array[i] = v_array[i]; 11649df49d7eSJed Brown /// } 11659df49d7eSJed Brown /// } 11669df49d7eSJed Brown /// 11679df49d7eSJed Brown /// // Check 1168e78171edSJeremy L Thompson /// diag.view()? 11699df49d7eSJed Brown /// .iter() 1170e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 11719df49d7eSJed Brown /// .for_each(|(computed, actual)| { 11729df49d7eSJed Brown /// assert!( 117380a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 11749df49d7eSJed Brown /// "Diagonal entry incorrect" 11759df49d7eSJed Brown /// ); 11769df49d7eSJed Brown /// }); 1177c68be7a2SJeremy L Thompson /// # Ok(()) 1178c68be7a2SJeremy L Thompson /// # } 11799df49d7eSJed Brown /// ``` 11809df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 11819df49d7eSJed Brown self.op_core.linear_assemble_diagonal(assembled) 11829df49d7eSJed Brown } 11839df49d7eSJed Brown 11849df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 11859df49d7eSJed Brown /// 11869df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 11879df49d7eSJed Brown /// 11889df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 11899df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 11909df49d7eSJed Brown /// 11919df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 11929df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 11939df49d7eSJed Brown /// 11949df49d7eSJed Brown /// 11959df49d7eSJed Brown /// ``` 11969df49d7eSJed Brown /// # use libceed::prelude::*; 11974d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 11989df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 11999df49d7eSJed Brown /// let ne = 4; 12009df49d7eSJed Brown /// let p = 3; 12019df49d7eSJed Brown /// let q = 4; 12029df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 12039df49d7eSJed Brown /// 12049df49d7eSJed Brown /// // Vectors 1205c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1206c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 12079df49d7eSJed Brown /// qdata.set_value(0.0); 1208c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 12099df49d7eSJed Brown /// u.set_value(1.0); 1210c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 12119df49d7eSJed Brown /// v.set_value(0.0); 12129df49d7eSJed Brown /// 12139df49d7eSJed Brown /// // Restrictions 12149df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 12159df49d7eSJed Brown /// for i in 0..ne { 12169df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 12179df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 12189df49d7eSJed Brown /// } 1219c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 12209df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 12219df49d7eSJed Brown /// for i in 0..ne { 12229df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 12239df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 12249df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 12259df49d7eSJed Brown /// } 1226c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 12279df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1228c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 12299df49d7eSJed Brown /// 12309df49d7eSJed Brown /// // Bases 1231c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1232c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 12339df49d7eSJed Brown /// 12349df49d7eSJed Brown /// // Build quadrature data 1235c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1236c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1237c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1238c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1239356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1240c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 12419df49d7eSJed Brown /// 12429df49d7eSJed Brown /// // Mass operator 1243c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 12449df49d7eSJed Brown /// let op_mass = ceed 1245c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1246c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1247356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1248c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 12499df49d7eSJed Brown /// 12509df49d7eSJed Brown /// // Diagonal 1251c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 12529df49d7eSJed Brown /// diag.set_value(1.0); 1253c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_diagonal(&mut diag)?; 12549df49d7eSJed Brown /// 12559df49d7eSJed Brown /// // Manual diagonal computation 1256c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 12579c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 12589df49d7eSJed Brown /// for i in 0..ndofs { 12599df49d7eSJed Brown /// u.set_value(0.0); 12609df49d7eSJed Brown /// { 1261e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 12629df49d7eSJed Brown /// u_array[i] = 1.; 12639df49d7eSJed Brown /// } 12649df49d7eSJed Brown /// 1265c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 12669df49d7eSJed Brown /// 12679df49d7eSJed Brown /// { 12689c774eddSJeremy L Thompson /// let v_array = v.view()?; 1269e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 12709df49d7eSJed Brown /// true_array[i] = v_array[i] + 1.0; 12719df49d7eSJed Brown /// } 12729df49d7eSJed Brown /// } 12739df49d7eSJed Brown /// 12749df49d7eSJed Brown /// // Check 1275e78171edSJeremy L Thompson /// diag.view()? 12769df49d7eSJed Brown /// .iter() 1277e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 12789df49d7eSJed Brown /// .for_each(|(computed, actual)| { 12799df49d7eSJed Brown /// assert!( 128080a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 12819df49d7eSJed Brown /// "Diagonal entry incorrect" 12829df49d7eSJed Brown /// ); 12839df49d7eSJed Brown /// }); 1284c68be7a2SJeremy L Thompson /// # Ok(()) 1285c68be7a2SJeremy L Thompson /// # } 12869df49d7eSJed Brown /// ``` 12879df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 12889df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 12899df49d7eSJed Brown } 12909df49d7eSJed Brown 12919df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 12929df49d7eSJed Brown /// 12939df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 12949df49d7eSJed Brown /// Operator. 12959df49d7eSJed Brown /// 12969df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 12979df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 12989df49d7eSJed Brown /// 12999df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 13009df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 13019df49d7eSJed Brown /// diagonal, provided in row-major form with an 13029df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 13039df49d7eSJed Brown /// this vector are derived from the active vector for 13049df49d7eSJed Brown /// the CeedOperator. The array has shape 13059df49d7eSJed Brown /// `[nodes, component out, component in]`. 13069df49d7eSJed Brown /// 13079df49d7eSJed Brown /// ``` 13089df49d7eSJed Brown /// # use libceed::prelude::*; 13094d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 13109df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 13119df49d7eSJed Brown /// let ne = 4; 13129df49d7eSJed Brown /// let p = 3; 13139df49d7eSJed Brown /// let q = 4; 13149df49d7eSJed Brown /// let ncomp = 2; 13159df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 13169df49d7eSJed Brown /// 13179df49d7eSJed Brown /// // Vectors 1318c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1319c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 13209df49d7eSJed Brown /// qdata.set_value(0.0); 1321c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 13229df49d7eSJed Brown /// u.set_value(1.0); 1323c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 13249df49d7eSJed Brown /// v.set_value(0.0); 13259df49d7eSJed Brown /// 13269df49d7eSJed Brown /// // Restrictions 13279df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 13289df49d7eSJed Brown /// for i in 0..ne { 13299df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 13309df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 13319df49d7eSJed Brown /// } 1332c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 13339df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 13349df49d7eSJed Brown /// for i in 0..ne { 13359df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 13369df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 13379df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 13389df49d7eSJed Brown /// } 1339c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 13409df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1341c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 13429df49d7eSJed Brown /// 13439df49d7eSJed Brown /// // Bases 1344c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1345c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 13469df49d7eSJed Brown /// 13479df49d7eSJed Brown /// // Build quadrature data 1348c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1349c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1350c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1351c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1352356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1353c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 13549df49d7eSJed Brown /// 13559df49d7eSJed Brown /// // Mass operator 13569df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 13579df49d7eSJed Brown /// // Number of quadrature points 13589df49d7eSJed Brown /// let q = qdata.len(); 13599df49d7eSJed Brown /// 13609df49d7eSJed Brown /// // Iterate over quadrature points 13619df49d7eSJed Brown /// for i in 0..q { 13629df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 13639df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 13649df49d7eSJed Brown /// } 13659df49d7eSJed Brown /// 13669df49d7eSJed Brown /// // Return clean error code 13679df49d7eSJed Brown /// 0 13689df49d7eSJed Brown /// }; 13699df49d7eSJed Brown /// 13709df49d7eSJed Brown /// let qf_mass = ceed 1371c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 1372c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 1373c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 1374c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 13759df49d7eSJed Brown /// 13769df49d7eSJed Brown /// let op_mass = ceed 1377c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1378c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1379356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1380c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 13819df49d7eSJed Brown /// 13829df49d7eSJed Brown /// // Diagonal 1383c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 13849df49d7eSJed Brown /// diag.set_value(0.0); 1385c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_point_block_diagonal(&mut diag)?; 13869df49d7eSJed Brown /// 13879df49d7eSJed Brown /// // Manual diagonal computation 1388c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 13899c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 13909df49d7eSJed Brown /// for i in 0..ndofs { 13919df49d7eSJed Brown /// for j in 0..ncomp { 13929df49d7eSJed Brown /// u.set_value(0.0); 13939df49d7eSJed Brown /// { 1394e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 13959df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 13969df49d7eSJed Brown /// } 13979df49d7eSJed Brown /// 1398c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 13999df49d7eSJed Brown /// 14009df49d7eSJed Brown /// { 14019c774eddSJeremy L Thompson /// let v_array = v.view()?; 1402e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 14039df49d7eSJed Brown /// for k in 0..ncomp { 14049df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 14059df49d7eSJed Brown /// } 14069df49d7eSJed Brown /// } 14079df49d7eSJed Brown /// } 14089df49d7eSJed Brown /// } 14099df49d7eSJed Brown /// 14109df49d7eSJed Brown /// // Check 1411e78171edSJeremy L Thompson /// diag.view()? 14129df49d7eSJed Brown /// .iter() 1413e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 14149df49d7eSJed Brown /// .for_each(|(computed, actual)| { 14159df49d7eSJed Brown /// assert!( 141680a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 14179df49d7eSJed Brown /// "Diagonal entry incorrect" 14189df49d7eSJed Brown /// ); 14199df49d7eSJed Brown /// }); 1420c68be7a2SJeremy L Thompson /// # Ok(()) 1421c68be7a2SJeremy L Thompson /// # } 14229df49d7eSJed Brown /// ``` 14239df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 14249df49d7eSJed Brown &self, 14259df49d7eSJed Brown assembled: &mut Vector, 14269df49d7eSJed Brown ) -> crate::Result<i32> { 14279df49d7eSJed Brown self.op_core.linear_assemble_point_block_diagonal(assembled) 14289df49d7eSJed Brown } 14299df49d7eSJed Brown 14309df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 14319df49d7eSJed Brown /// 14329df49d7eSJed Brown /// This sums into a Vector with the point block diagonal of a linear 14339df49d7eSJed Brown /// Operator. 14349df49d7eSJed Brown /// 14359df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 14369df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 14379df49d7eSJed Brown /// 14389df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 14399df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 14409df49d7eSJed Brown /// diagonal, provided in row-major form with an 14419df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 14429df49d7eSJed Brown /// this vector are derived from the active vector for 14439df49d7eSJed Brown /// the CeedOperator. The array has shape 14449df49d7eSJed Brown /// `[nodes, component out, component in]`. 14459df49d7eSJed Brown /// 14469df49d7eSJed Brown /// ``` 14479df49d7eSJed Brown /// # use libceed::prelude::*; 14484d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 14499df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 14509df49d7eSJed Brown /// let ne = 4; 14519df49d7eSJed Brown /// let p = 3; 14529df49d7eSJed Brown /// let q = 4; 14539df49d7eSJed Brown /// let ncomp = 2; 14549df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 14559df49d7eSJed Brown /// 14569df49d7eSJed Brown /// // Vectors 1457c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1458c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 14599df49d7eSJed Brown /// qdata.set_value(0.0); 1460c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 14619df49d7eSJed Brown /// u.set_value(1.0); 1462c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 14639df49d7eSJed Brown /// v.set_value(0.0); 14649df49d7eSJed Brown /// 14659df49d7eSJed Brown /// // Restrictions 14669df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 14679df49d7eSJed Brown /// for i in 0..ne { 14689df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 14699df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 14709df49d7eSJed Brown /// } 1471c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 14729df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 14739df49d7eSJed Brown /// for i in 0..ne { 14749df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 14759df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 14769df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 14779df49d7eSJed Brown /// } 1478c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 14799df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1480c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 14819df49d7eSJed Brown /// 14829df49d7eSJed Brown /// // Bases 1483c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1484c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 14859df49d7eSJed Brown /// 14869df49d7eSJed Brown /// // Build quadrature data 1487c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1488c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1489c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1490c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1491356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1492c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 14939df49d7eSJed Brown /// 14949df49d7eSJed Brown /// // Mass operator 14959df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 14969df49d7eSJed Brown /// // Number of quadrature points 14979df49d7eSJed Brown /// let q = qdata.len(); 14989df49d7eSJed Brown /// 14999df49d7eSJed Brown /// // Iterate over quadrature points 15009df49d7eSJed Brown /// for i in 0..q { 15019df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 15029df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 15039df49d7eSJed Brown /// } 15049df49d7eSJed Brown /// 15059df49d7eSJed Brown /// // Return clean error code 15069df49d7eSJed Brown /// 0 15079df49d7eSJed Brown /// }; 15089df49d7eSJed Brown /// 15099df49d7eSJed Brown /// let qf_mass = ceed 1510c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 1511c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 1512c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 1513c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 15149df49d7eSJed Brown /// 15159df49d7eSJed Brown /// let op_mass = ceed 1516c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1517c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1518356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1519c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 15209df49d7eSJed Brown /// 15219df49d7eSJed Brown /// // Diagonal 1522c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 15239df49d7eSJed Brown /// diag.set_value(1.0); 1524c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_point_block_diagonal(&mut diag)?; 15259df49d7eSJed Brown /// 15269df49d7eSJed Brown /// // Manual diagonal computation 1527c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 15289c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 15299df49d7eSJed Brown /// for i in 0..ndofs { 15309df49d7eSJed Brown /// for j in 0..ncomp { 15319df49d7eSJed Brown /// u.set_value(0.0); 15329df49d7eSJed Brown /// { 1533e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 15349df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 15359df49d7eSJed Brown /// } 15369df49d7eSJed Brown /// 1537c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 15389df49d7eSJed Brown /// 15399df49d7eSJed Brown /// { 15409c774eddSJeremy L Thompson /// let v_array = v.view()?; 1541e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 15429df49d7eSJed Brown /// for k in 0..ncomp { 15439df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 15449df49d7eSJed Brown /// } 15459df49d7eSJed Brown /// } 15469df49d7eSJed Brown /// } 15479df49d7eSJed Brown /// } 15489df49d7eSJed Brown /// 15499df49d7eSJed Brown /// // Check 1550e78171edSJeremy L Thompson /// diag.view()? 15519df49d7eSJed Brown /// .iter() 1552e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 15539df49d7eSJed Brown /// .for_each(|(computed, actual)| { 15549df49d7eSJed Brown /// assert!( 155580a9ef05SNatalie Beams /// (*computed - 1.0 - *actual).abs() < 10.0 * libceed::EPSILON, 15569df49d7eSJed Brown /// "Diagonal entry incorrect" 15579df49d7eSJed Brown /// ); 15589df49d7eSJed Brown /// }); 1559c68be7a2SJeremy L Thompson /// # Ok(()) 1560c68be7a2SJeremy L Thompson /// # } 15619df49d7eSJed Brown /// ``` 15629df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 15639df49d7eSJed Brown &self, 15649df49d7eSJed Brown assembled: &mut Vector, 15659df49d7eSJed Brown ) -> crate::Result<i32> { 15669df49d7eSJed Brown self.op_core 15679df49d7eSJed Brown .linear_assemble_add_point_block_diagonal(assembled) 15689df49d7eSJed Brown } 15699df49d7eSJed Brown 15709df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 15719df49d7eSJed Brown /// given Operator, creating the prolongation basis from the fine and 15729df49d7eSJed Brown /// coarse grid interpolation 15739df49d7eSJed Brown /// 15749df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 15759df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 15769df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 15779df49d7eSJed Brown /// 15789df49d7eSJed Brown /// ``` 15799df49d7eSJed Brown /// # use libceed::prelude::*; 15804d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 15819df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 15829df49d7eSJed Brown /// let ne = 15; 15839df49d7eSJed Brown /// let p_coarse = 3; 15849df49d7eSJed Brown /// let p_fine = 5; 15859df49d7eSJed Brown /// let q = 6; 15869df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 15879df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 15889df49d7eSJed Brown /// 15899df49d7eSJed Brown /// // Vectors 15909df49d7eSJed Brown /// let x_array = (0..ne + 1) 159180a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 159280a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1593c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1594c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 15959df49d7eSJed Brown /// qdata.set_value(0.0); 1596c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 15979df49d7eSJed Brown /// u_coarse.set_value(1.0); 1598c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 15999df49d7eSJed Brown /// u_fine.set_value(1.0); 1600c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 16019df49d7eSJed Brown /// v_coarse.set_value(0.0); 1602c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 16039df49d7eSJed Brown /// v_fine.set_value(0.0); 1604c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 16059df49d7eSJed Brown /// multiplicity.set_value(1.0); 16069df49d7eSJed Brown /// 16079df49d7eSJed Brown /// // Restrictions 16089df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1609c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 16109df49d7eSJed Brown /// 16119df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 16129df49d7eSJed Brown /// for i in 0..ne { 16139df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 16149df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 16159df49d7eSJed Brown /// } 1616c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 16179df49d7eSJed Brown /// 16189df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 16199df49d7eSJed Brown /// for i in 0..ne { 16209df49d7eSJed Brown /// for j in 0..p_coarse { 16219df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 16229df49d7eSJed Brown /// } 16239df49d7eSJed Brown /// } 1624c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 16259df49d7eSJed Brown /// ne, 16269df49d7eSJed Brown /// p_coarse, 16279df49d7eSJed Brown /// 1, 16289df49d7eSJed Brown /// 1, 16299df49d7eSJed Brown /// ndofs_coarse, 16309df49d7eSJed Brown /// MemType::Host, 16319df49d7eSJed Brown /// &indu_coarse, 1632c68be7a2SJeremy L Thompson /// )?; 16339df49d7eSJed Brown /// 16349df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 16359df49d7eSJed Brown /// for i in 0..ne { 16369df49d7eSJed Brown /// for j in 0..p_fine { 16379df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 16389df49d7eSJed Brown /// } 16399df49d7eSJed Brown /// } 1640c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 16419df49d7eSJed Brown /// 16429df49d7eSJed Brown /// // Bases 1643c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1644c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1645c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 16469df49d7eSJed Brown /// 16479df49d7eSJed Brown /// // Build quadrature data 1648c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1649c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1650c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1651c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1652356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1653c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 16549df49d7eSJed Brown /// 16559df49d7eSJed Brown /// // Mass operator 1656c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 16579df49d7eSJed Brown /// let op_mass_fine = ceed 1658c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1659c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1660356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1661c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 16629df49d7eSJed Brown /// 16639df49d7eSJed Brown /// // Multigrid setup 1664c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = 1665c68be7a2SJeremy L Thompson /// op_mass_fine.create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)?; 16669df49d7eSJed Brown /// 16679df49d7eSJed Brown /// // Coarse problem 16689df49d7eSJed Brown /// u_coarse.set_value(1.0); 1669c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 16709df49d7eSJed Brown /// 16719df49d7eSJed Brown /// // Check 1672e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 16739df49d7eSJed Brown /// assert!( 167480a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 16759df49d7eSJed Brown /// "Incorrect interval length computed" 16769df49d7eSJed Brown /// ); 16779df49d7eSJed Brown /// 16789df49d7eSJed Brown /// // Prolong 1679c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 16809df49d7eSJed Brown /// 16819df49d7eSJed Brown /// // Fine problem 1682c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 16839df49d7eSJed Brown /// 16849df49d7eSJed Brown /// // Check 1685e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 16869df49d7eSJed Brown /// assert!( 1687392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 16889df49d7eSJed Brown /// "Incorrect interval length computed" 16899df49d7eSJed Brown /// ); 16909df49d7eSJed Brown /// 16919df49d7eSJed Brown /// // Restrict 1692c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 16939df49d7eSJed Brown /// 16949df49d7eSJed Brown /// // Check 1695e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 16969df49d7eSJed Brown /// assert!( 1697392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 16989df49d7eSJed Brown /// "Incorrect interval length computed" 16999df49d7eSJed Brown /// ); 1700c68be7a2SJeremy L Thompson /// # Ok(()) 1701c68be7a2SJeremy L Thompson /// # } 17029df49d7eSJed Brown /// ``` 1703594ef120SJeremy L Thompson pub fn create_multigrid_level<'b>( 17049df49d7eSJed Brown &self, 17059df49d7eSJed Brown p_mult_fine: &Vector, 17069df49d7eSJed Brown rstr_coarse: &ElemRestriction, 17079df49d7eSJed Brown basis_coarse: &Basis, 1708594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 17099df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 17109df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 17119df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 1712*656ef1e5SJeremy L Thompson self.op_core.check_error(unsafe { 17139df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreate( 17149df49d7eSJed Brown self.op_core.ptr, 17159df49d7eSJed Brown p_mult_fine.ptr, 17169df49d7eSJed Brown rstr_coarse.ptr, 17179df49d7eSJed Brown basis_coarse.ptr, 17189df49d7eSJed Brown &mut ptr_coarse, 17199df49d7eSJed Brown &mut ptr_prolong, 17209df49d7eSJed Brown &mut ptr_restrict, 17219df49d7eSJed Brown ) 1722*656ef1e5SJeremy L Thompson })?; 17231142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 17241142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 17251142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 17269df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 17279df49d7eSJed Brown } 17289df49d7eSJed Brown 17299df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 17309df49d7eSJed Brown /// given Operator with a tensor basis for the active basis 17319df49d7eSJed Brown /// 17329df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 17339df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 17349df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 17359df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 17369df49d7eSJed Brown /// 17379df49d7eSJed Brown /// ``` 17389df49d7eSJed Brown /// # use libceed::prelude::*; 17394d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 17409df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 17419df49d7eSJed Brown /// let ne = 15; 17429df49d7eSJed Brown /// let p_coarse = 3; 17439df49d7eSJed Brown /// let p_fine = 5; 17449df49d7eSJed Brown /// let q = 6; 17459df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 17469df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 17479df49d7eSJed Brown /// 17489df49d7eSJed Brown /// // Vectors 17499df49d7eSJed Brown /// let x_array = (0..ne + 1) 175080a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 175180a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1752c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1753c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 17549df49d7eSJed Brown /// qdata.set_value(0.0); 1755c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 17569df49d7eSJed Brown /// u_coarse.set_value(1.0); 1757c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 17589df49d7eSJed Brown /// u_fine.set_value(1.0); 1759c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 17609df49d7eSJed Brown /// v_coarse.set_value(0.0); 1761c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 17629df49d7eSJed Brown /// v_fine.set_value(0.0); 1763c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 17649df49d7eSJed Brown /// multiplicity.set_value(1.0); 17659df49d7eSJed Brown /// 17669df49d7eSJed Brown /// // Restrictions 17679df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1768c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 17699df49d7eSJed Brown /// 17709df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 17719df49d7eSJed Brown /// for i in 0..ne { 17729df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 17739df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 17749df49d7eSJed Brown /// } 1775c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 17769df49d7eSJed Brown /// 17779df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 17789df49d7eSJed Brown /// for i in 0..ne { 17799df49d7eSJed Brown /// for j in 0..p_coarse { 17809df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 17819df49d7eSJed Brown /// } 17829df49d7eSJed Brown /// } 1783c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 17849df49d7eSJed Brown /// ne, 17859df49d7eSJed Brown /// p_coarse, 17869df49d7eSJed Brown /// 1, 17879df49d7eSJed Brown /// 1, 17889df49d7eSJed Brown /// ndofs_coarse, 17899df49d7eSJed Brown /// MemType::Host, 17909df49d7eSJed Brown /// &indu_coarse, 1791c68be7a2SJeremy L Thompson /// )?; 17929df49d7eSJed Brown /// 17939df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 17949df49d7eSJed Brown /// for i in 0..ne { 17959df49d7eSJed Brown /// for j in 0..p_fine { 17969df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 17979df49d7eSJed Brown /// } 17989df49d7eSJed Brown /// } 1799c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 18009df49d7eSJed Brown /// 18019df49d7eSJed Brown /// // Bases 1802c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1803c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1804c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 18059df49d7eSJed Brown /// 18069df49d7eSJed Brown /// // Build quadrature data 1807c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1808c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1809c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1810c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1811356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1812c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 18139df49d7eSJed Brown /// 18149df49d7eSJed Brown /// // Mass operator 1815c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 18169df49d7eSJed Brown /// let op_mass_fine = ceed 1817c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1818c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1819356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1820c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 18219df49d7eSJed Brown /// 18229df49d7eSJed Brown /// // Multigrid setup 182380a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 18249df49d7eSJed Brown /// { 1825c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 1826c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 1827c68be7a2SJeremy L Thompson /// let basis_c_to_f = 1828c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 18299df49d7eSJed Brown /// for i in 0..p_coarse { 18309df49d7eSJed Brown /// coarse.set_value(0.0); 18319df49d7eSJed Brown /// { 1832e78171edSJeremy L Thompson /// let mut array = coarse.view_mut()?; 18339df49d7eSJed Brown /// array[i] = 1.; 18349df49d7eSJed Brown /// } 1835c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 18369df49d7eSJed Brown /// 1, 18379df49d7eSJed Brown /// TransposeMode::NoTranspose, 18389df49d7eSJed Brown /// EvalMode::Interp, 18399df49d7eSJed Brown /// &coarse, 18409df49d7eSJed Brown /// &mut fine, 1841c68be7a2SJeremy L Thompson /// )?; 1842e78171edSJeremy L Thompson /// let array = fine.view()?; 18439df49d7eSJed Brown /// for j in 0..p_fine { 18449df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 18459df49d7eSJed Brown /// } 18469df49d7eSJed Brown /// } 18479df49d7eSJed Brown /// } 1848c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_tensor_H1( 1849c68be7a2SJeremy L Thompson /// &multiplicity, 1850c68be7a2SJeremy L Thompson /// &ru_coarse, 1851c68be7a2SJeremy L Thompson /// &bu_coarse, 1852c68be7a2SJeremy L Thompson /// &interp_c_to_f, 1853c68be7a2SJeremy L Thompson /// )?; 18549df49d7eSJed Brown /// 18559df49d7eSJed Brown /// // Coarse problem 18569df49d7eSJed Brown /// u_coarse.set_value(1.0); 1857c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 18589df49d7eSJed Brown /// 18599df49d7eSJed Brown /// // Check 1860e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 18619df49d7eSJed Brown /// assert!( 186280a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 18639df49d7eSJed Brown /// "Incorrect interval length computed" 18649df49d7eSJed Brown /// ); 18659df49d7eSJed Brown /// 18669df49d7eSJed Brown /// // Prolong 1867c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 18689df49d7eSJed Brown /// 18699df49d7eSJed Brown /// // Fine problem 1870c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 18719df49d7eSJed Brown /// 18729df49d7eSJed Brown /// // Check 1873e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 18749df49d7eSJed Brown /// assert!( 1875392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 18769df49d7eSJed Brown /// "Incorrect interval length computed" 18779df49d7eSJed Brown /// ); 18789df49d7eSJed Brown /// 18799df49d7eSJed Brown /// // Restrict 1880c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 18819df49d7eSJed Brown /// 18829df49d7eSJed Brown /// // Check 1883e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 18849df49d7eSJed Brown /// assert!( 1885392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 18869df49d7eSJed Brown /// "Incorrect interval length computed" 18879df49d7eSJed Brown /// ); 1888c68be7a2SJeremy L Thompson /// # Ok(()) 1889c68be7a2SJeremy L Thompson /// # } 18909df49d7eSJed Brown /// ``` 1891594ef120SJeremy L Thompson pub fn create_multigrid_level_tensor_H1<'b>( 18929df49d7eSJed Brown &self, 18939df49d7eSJed Brown p_mult_fine: &Vector, 18949df49d7eSJed Brown rstr_coarse: &ElemRestriction, 18959df49d7eSJed Brown basis_coarse: &Basis, 189680a9ef05SNatalie Beams interpCtoF: &Vec<Scalar>, 1897594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 18989df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 18999df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 19009df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 1901*656ef1e5SJeremy L Thompson self.op_core.check_error(unsafe { 19029df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateTensorH1( 19039df49d7eSJed Brown self.op_core.ptr, 19049df49d7eSJed Brown p_mult_fine.ptr, 19059df49d7eSJed Brown rstr_coarse.ptr, 19069df49d7eSJed Brown basis_coarse.ptr, 19079df49d7eSJed Brown interpCtoF.as_ptr(), 19089df49d7eSJed Brown &mut ptr_coarse, 19099df49d7eSJed Brown &mut ptr_prolong, 19109df49d7eSJed Brown &mut ptr_restrict, 19119df49d7eSJed Brown ) 1912*656ef1e5SJeremy L Thompson })?; 19131142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 19141142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 19151142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 19169df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 19179df49d7eSJed Brown } 19189df49d7eSJed Brown 19199df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 19209df49d7eSJed Brown /// given Operator with a non-tensor basis for the active basis 19219df49d7eSJed Brown /// 19229df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 19239df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 19249df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 19259df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 19269df49d7eSJed Brown /// 19279df49d7eSJed Brown /// ``` 19289df49d7eSJed Brown /// # use libceed::prelude::*; 19294d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 19309df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 19319df49d7eSJed Brown /// let ne = 15; 19329df49d7eSJed Brown /// let p_coarse = 3; 19339df49d7eSJed Brown /// let p_fine = 5; 19349df49d7eSJed Brown /// let q = 6; 19359df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 19369df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 19379df49d7eSJed Brown /// 19389df49d7eSJed Brown /// // Vectors 19399df49d7eSJed Brown /// let x_array = (0..ne + 1) 194080a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 194180a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1942c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1943c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 19449df49d7eSJed Brown /// qdata.set_value(0.0); 1945c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 19469df49d7eSJed Brown /// u_coarse.set_value(1.0); 1947c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 19489df49d7eSJed Brown /// u_fine.set_value(1.0); 1949c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 19509df49d7eSJed Brown /// v_coarse.set_value(0.0); 1951c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 19529df49d7eSJed Brown /// v_fine.set_value(0.0); 1953c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 19549df49d7eSJed Brown /// multiplicity.set_value(1.0); 19559df49d7eSJed Brown /// 19569df49d7eSJed Brown /// // Restrictions 19579df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1958c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 19599df49d7eSJed Brown /// 19609df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 19619df49d7eSJed Brown /// for i in 0..ne { 19629df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 19639df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 19649df49d7eSJed Brown /// } 1965c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 19669df49d7eSJed Brown /// 19679df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 19689df49d7eSJed Brown /// for i in 0..ne { 19699df49d7eSJed Brown /// for j in 0..p_coarse { 19709df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 19719df49d7eSJed Brown /// } 19729df49d7eSJed Brown /// } 1973c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 19749df49d7eSJed Brown /// ne, 19759df49d7eSJed Brown /// p_coarse, 19769df49d7eSJed Brown /// 1, 19779df49d7eSJed Brown /// 1, 19789df49d7eSJed Brown /// ndofs_coarse, 19799df49d7eSJed Brown /// MemType::Host, 19809df49d7eSJed Brown /// &indu_coarse, 1981c68be7a2SJeremy L Thompson /// )?; 19829df49d7eSJed Brown /// 19839df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 19849df49d7eSJed Brown /// for i in 0..ne { 19859df49d7eSJed Brown /// for j in 0..p_fine { 19869df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 19879df49d7eSJed Brown /// } 19889df49d7eSJed Brown /// } 1989c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 19909df49d7eSJed Brown /// 19919df49d7eSJed Brown /// // Bases 1992c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1993c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1994c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 19959df49d7eSJed Brown /// 19969df49d7eSJed Brown /// // Build quadrature data 1997c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1998c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1999c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2000c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2001356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 2002c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 20039df49d7eSJed Brown /// 20049df49d7eSJed Brown /// // Mass operator 2005c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 20069df49d7eSJed Brown /// let op_mass_fine = ceed 2007c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2008c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 2009356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 2010c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 20119df49d7eSJed Brown /// 20129df49d7eSJed Brown /// // Multigrid setup 201380a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 20149df49d7eSJed Brown /// { 2015c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 2016c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 2017c68be7a2SJeremy L Thompson /// let basis_c_to_f = 2018c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 20199df49d7eSJed Brown /// for i in 0..p_coarse { 20209df49d7eSJed Brown /// coarse.set_value(0.0); 20219df49d7eSJed Brown /// { 2022e78171edSJeremy L Thompson /// let mut array = coarse.view_mut()?; 20239df49d7eSJed Brown /// array[i] = 1.; 20249df49d7eSJed Brown /// } 2025c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 20269df49d7eSJed Brown /// 1, 20279df49d7eSJed Brown /// TransposeMode::NoTranspose, 20289df49d7eSJed Brown /// EvalMode::Interp, 20299df49d7eSJed Brown /// &coarse, 20309df49d7eSJed Brown /// &mut fine, 2031c68be7a2SJeremy L Thompson /// )?; 2032e78171edSJeremy L Thompson /// let array = fine.view()?; 20339df49d7eSJed Brown /// for j in 0..p_fine { 20349df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 20359df49d7eSJed Brown /// } 20369df49d7eSJed Brown /// } 20379df49d7eSJed Brown /// } 2038c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_H1( 2039c68be7a2SJeremy L Thompson /// &multiplicity, 2040c68be7a2SJeremy L Thompson /// &ru_coarse, 2041c68be7a2SJeremy L Thompson /// &bu_coarse, 2042c68be7a2SJeremy L Thompson /// &interp_c_to_f, 2043c68be7a2SJeremy L Thompson /// )?; 20449df49d7eSJed Brown /// 20459df49d7eSJed Brown /// // Coarse problem 20469df49d7eSJed Brown /// u_coarse.set_value(1.0); 2047c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 20489df49d7eSJed Brown /// 20499df49d7eSJed Brown /// // Check 2050e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 20519df49d7eSJed Brown /// assert!( 205280a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 20539df49d7eSJed Brown /// "Incorrect interval length computed" 20549df49d7eSJed Brown /// ); 20559df49d7eSJed Brown /// 20569df49d7eSJed Brown /// // Prolong 2057c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 20589df49d7eSJed Brown /// 20599df49d7eSJed Brown /// // Fine problem 2060c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 20619df49d7eSJed Brown /// 20629df49d7eSJed Brown /// // Check 2063e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 20649df49d7eSJed Brown /// assert!( 2065392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 20669df49d7eSJed Brown /// "Incorrect interval length computed" 20679df49d7eSJed Brown /// ); 20689df49d7eSJed Brown /// 20699df49d7eSJed Brown /// // Restrict 2070c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 20719df49d7eSJed Brown /// 20729df49d7eSJed Brown /// // Check 2073e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 20749df49d7eSJed Brown /// assert!( 2075392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 20769df49d7eSJed Brown /// "Incorrect interval length computed" 20779df49d7eSJed Brown /// ); 2078c68be7a2SJeremy L Thompson /// # Ok(()) 2079c68be7a2SJeremy L Thompson /// # } 20809df49d7eSJed Brown /// ``` 2081594ef120SJeremy L Thompson pub fn create_multigrid_level_H1<'b>( 20829df49d7eSJed Brown &self, 20839df49d7eSJed Brown p_mult_fine: &Vector, 20849df49d7eSJed Brown rstr_coarse: &ElemRestriction, 20859df49d7eSJed Brown basis_coarse: &Basis, 208680a9ef05SNatalie Beams interpCtoF: &[Scalar], 2087594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 20889df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 20899df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 20909df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 2091*656ef1e5SJeremy L Thompson self.op_core.check_error(unsafe { 20929df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateH1( 20939df49d7eSJed Brown self.op_core.ptr, 20949df49d7eSJed Brown p_mult_fine.ptr, 20959df49d7eSJed Brown rstr_coarse.ptr, 20969df49d7eSJed Brown basis_coarse.ptr, 20979df49d7eSJed Brown interpCtoF.as_ptr(), 20989df49d7eSJed Brown &mut ptr_coarse, 20999df49d7eSJed Brown &mut ptr_prolong, 21009df49d7eSJed Brown &mut ptr_restrict, 21019df49d7eSJed Brown ) 2102*656ef1e5SJeremy L Thompson })?; 21031142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 21041142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 21051142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 21069df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 21079df49d7eSJed Brown } 21089df49d7eSJed Brown } 21099df49d7eSJed Brown 21109df49d7eSJed Brown // ----------------------------------------------------------------------------- 21119df49d7eSJed Brown // Composite Operator 21129df49d7eSJed Brown // ----------------------------------------------------------------------------- 21139df49d7eSJed Brown impl<'a> CompositeOperator<'a> { 21149df49d7eSJed Brown // Constructor 2115594ef120SJeremy L Thompson pub fn create(ceed: &crate::Ceed) -> crate::Result<Self> { 21169df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 2117*656ef1e5SJeremy L Thompson ceed.check_error(unsafe { bind_ceed::CeedCompositeOperatorCreate(ceed.ptr, &mut ptr) })?; 21189df49d7eSJed Brown Ok(Self { 21191142270cSJeremy L Thompson op_core: OperatorCore { 21201142270cSJeremy L Thompson ptr, 21211142270cSJeremy L Thompson _lifeline: PhantomData, 21221142270cSJeremy L Thompson }, 21239df49d7eSJed Brown }) 21249df49d7eSJed Brown } 21259df49d7eSJed Brown 2126ea6b5821SJeremy L Thompson /// Set name for CompositeOperator printing 2127ea6b5821SJeremy L Thompson /// 2128ea6b5821SJeremy L Thompson /// * 'name' - Name to set 2129ea6b5821SJeremy L Thompson /// 2130ea6b5821SJeremy L Thompson /// ``` 2131ea6b5821SJeremy L Thompson /// # use libceed::prelude::*; 2132ea6b5821SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 2133ea6b5821SJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 2134ea6b5821SJeremy L Thompson /// 2135ea6b5821SJeremy L Thompson /// // Sub operator field arguments 2136ea6b5821SJeremy L Thompson /// let ne = 3; 2137ea6b5821SJeremy L Thompson /// let q = 4 as usize; 2138ea6b5821SJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 2139ea6b5821SJeremy L Thompson /// for i in 0..ne { 2140ea6b5821SJeremy L Thompson /// ind[2 * i + 0] = i as i32; 2141ea6b5821SJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 2142ea6b5821SJeremy L Thompson /// } 2143ea6b5821SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 2144ea6b5821SJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2145d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 2146ea6b5821SJeremy L Thompson /// 2147ea6b5821SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2148ea6b5821SJeremy L Thompson /// 2149ea6b5821SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?; 2150ea6b5821SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?; 2151ea6b5821SJeremy L Thompson /// 2152ea6b5821SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 2153ea6b5821SJeremy L Thompson /// let op_mass = ceed 2154ea6b5821SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2155ea6b5821SJeremy L Thompson /// .name("Mass term")? 2156ea6b5821SJeremy L Thompson /// .field("u", &r, &b, VectorOpt::Active)? 2157356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_mass)? 2158ea6b5821SJeremy L Thompson /// .field("v", &r, &b, VectorOpt::Active)?; 2159ea6b5821SJeremy L Thompson /// 2160ea6b5821SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 2161ea6b5821SJeremy L Thompson /// let op_diff = ceed 2162ea6b5821SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2163ea6b5821SJeremy L Thompson /// .name("Poisson term")? 2164ea6b5821SJeremy L Thompson /// .field("du", &r, &b, VectorOpt::Active)? 2165356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_diff)? 2166ea6b5821SJeremy L Thompson /// .field("dv", &r, &b, VectorOpt::Active)?; 2167ea6b5821SJeremy L Thompson /// 2168ea6b5821SJeremy L Thompson /// let op = ceed 2169ea6b5821SJeremy L Thompson /// .composite_operator()? 2170ea6b5821SJeremy L Thompson /// .name("Screened Poisson")? 2171ea6b5821SJeremy L Thompson /// .sub_operator(&op_mass)? 2172ea6b5821SJeremy L Thompson /// .sub_operator(&op_diff)?; 2173ea6b5821SJeremy L Thompson /// # Ok(()) 2174ea6b5821SJeremy L Thompson /// # } 2175ea6b5821SJeremy L Thompson /// ``` 2176ea6b5821SJeremy L Thompson #[allow(unused_mut)] 2177ea6b5821SJeremy L Thompson pub fn name(mut self, name: &str) -> crate::Result<Self> { 2178ea6b5821SJeremy L Thompson self.op_core.name(name)?; 2179ea6b5821SJeremy L Thompson Ok(self) 2180ea6b5821SJeremy L Thompson } 2181ea6b5821SJeremy L Thompson 21829df49d7eSJed Brown /// Apply Operator to a vector 21839df49d7eSJed Brown /// 2184ea6b5821SJeremy L Thompson /// * `input` - Inpuht Vector 21859df49d7eSJed Brown /// * `output` - Output Vector 21869df49d7eSJed Brown /// 21879df49d7eSJed Brown /// ``` 21889df49d7eSJed Brown /// # use libceed::prelude::*; 21894d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 21909df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 21919df49d7eSJed Brown /// let ne = 4; 21929df49d7eSJed Brown /// let p = 3; 21939df49d7eSJed Brown /// let q = 4; 21949df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 21959df49d7eSJed Brown /// 21969df49d7eSJed Brown /// // Vectors 2197c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 2198c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 21999df49d7eSJed Brown /// qdata_mass.set_value(0.0); 2200c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 22019df49d7eSJed Brown /// qdata_diff.set_value(0.0); 2202c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 22039df49d7eSJed Brown /// u.set_value(1.0); 2204c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 22059df49d7eSJed Brown /// v.set_value(0.0); 22069df49d7eSJed Brown /// 22079df49d7eSJed Brown /// // Restrictions 22089df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 22099df49d7eSJed Brown /// for i in 0..ne { 22109df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 22119df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 22129df49d7eSJed Brown /// } 2213c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 22149df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 22159df49d7eSJed Brown /// for i in 0..ne { 22169df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 22179df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 22189df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 22199df49d7eSJed Brown /// } 2220c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 22219df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2222c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 22239df49d7eSJed Brown /// 22249df49d7eSJed Brown /// // Bases 2225c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2226c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 22279df49d7eSJed Brown /// 22289df49d7eSJed Brown /// // Build quadrature data 2229c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 2230c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 2231c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2232c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2233356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 2234c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 22359df49d7eSJed Brown /// 2236c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 2237c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 2238c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2239c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2240356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 2241c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 22429df49d7eSJed Brown /// 22439df49d7eSJed Brown /// // Application operator 2244c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 22459df49d7eSJed Brown /// let op_mass = ceed 2246c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2247c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 2248356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_mass)? 2249c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 22509df49d7eSJed Brown /// 2251c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 22529df49d7eSJed Brown /// let op_diff = ceed 2253c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2254c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 2255356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_diff)? 2256c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 22579df49d7eSJed Brown /// 22589df49d7eSJed Brown /// let op_composite = ceed 2259c68be7a2SJeremy L Thompson /// .composite_operator()? 2260c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 2261c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 22629df49d7eSJed Brown /// 22639df49d7eSJed Brown /// v.set_value(0.0); 2264c68be7a2SJeremy L Thompson /// op_composite.apply(&u, &mut v)?; 22659df49d7eSJed Brown /// 22669df49d7eSJed Brown /// // Check 2267e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 22689df49d7eSJed Brown /// assert!( 226980a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 22709df49d7eSJed Brown /// "Incorrect interval length computed" 22719df49d7eSJed Brown /// ); 2272c68be7a2SJeremy L Thompson /// # Ok(()) 2273c68be7a2SJeremy L Thompson /// # } 22749df49d7eSJed Brown /// ``` 22759df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 22769df49d7eSJed Brown self.op_core.apply(input, output) 22779df49d7eSJed Brown } 22789df49d7eSJed Brown 22799df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 22809df49d7eSJed Brown /// 22819df49d7eSJed Brown /// * `input` - Input Vector 22829df49d7eSJed Brown /// * `output` - Output Vector 22839df49d7eSJed Brown /// 22849df49d7eSJed Brown /// ``` 22859df49d7eSJed Brown /// # use libceed::prelude::*; 22864d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 22879df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 22889df49d7eSJed Brown /// let ne = 4; 22899df49d7eSJed Brown /// let p = 3; 22909df49d7eSJed Brown /// let q = 4; 22919df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 22929df49d7eSJed Brown /// 22939df49d7eSJed Brown /// // Vectors 2294c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 2295c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 22969df49d7eSJed Brown /// qdata_mass.set_value(0.0); 2297c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 22989df49d7eSJed Brown /// qdata_diff.set_value(0.0); 2299c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 23009df49d7eSJed Brown /// u.set_value(1.0); 2301c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 23029df49d7eSJed Brown /// v.set_value(0.0); 23039df49d7eSJed Brown /// 23049df49d7eSJed Brown /// // Restrictions 23059df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 23069df49d7eSJed Brown /// for i in 0..ne { 23079df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 23089df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 23099df49d7eSJed Brown /// } 2310c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 23119df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 23129df49d7eSJed Brown /// for i in 0..ne { 23139df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 23149df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 23159df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 23169df49d7eSJed Brown /// } 2317c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 23189df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2319c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 23209df49d7eSJed Brown /// 23219df49d7eSJed Brown /// // Bases 2322c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2323c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 23249df49d7eSJed Brown /// 23259df49d7eSJed Brown /// // Build quadrature data 2326c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 2327c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 2328c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2329c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2330356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 2331c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 23329df49d7eSJed Brown /// 2333c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 2334c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 2335c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2336c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2337356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 2338c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 23399df49d7eSJed Brown /// 23409df49d7eSJed Brown /// // Application operator 2341c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 23429df49d7eSJed Brown /// let op_mass = ceed 2343c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2344c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 2345356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_mass)? 2346c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 23479df49d7eSJed Brown /// 2348c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 23499df49d7eSJed Brown /// let op_diff = ceed 2350c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2351c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 2352356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_diff)? 2353c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 23549df49d7eSJed Brown /// 23559df49d7eSJed Brown /// let op_composite = ceed 2356c68be7a2SJeremy L Thompson /// .composite_operator()? 2357c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 2358c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 23599df49d7eSJed Brown /// 23609df49d7eSJed Brown /// v.set_value(1.0); 2361c68be7a2SJeremy L Thompson /// op_composite.apply_add(&u, &mut v)?; 23629df49d7eSJed Brown /// 23639df49d7eSJed Brown /// // Check 2364e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 23659df49d7eSJed Brown /// assert!( 236680a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 23679df49d7eSJed Brown /// "Incorrect interval length computed" 23689df49d7eSJed Brown /// ); 2369c68be7a2SJeremy L Thompson /// # Ok(()) 2370c68be7a2SJeremy L Thompson /// # } 23719df49d7eSJed Brown /// ``` 23729df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 23739df49d7eSJed Brown self.op_core.apply_add(input, output) 23749df49d7eSJed Brown } 23759df49d7eSJed Brown 23769df49d7eSJed Brown /// Add a sub-Operator to a Composite Operator 23779df49d7eSJed Brown /// 23789df49d7eSJed Brown /// * `subop` - Sub-Operator 23799df49d7eSJed Brown /// 23809df49d7eSJed Brown /// ``` 23819df49d7eSJed Brown /// # use libceed::prelude::*; 23824d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 23839df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 2384c68be7a2SJeremy L Thompson /// let mut op = ceed.composite_operator()?; 23859df49d7eSJed Brown /// 2386c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 2387c68be7a2SJeremy L Thompson /// let op_mass = ceed.operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?; 2388c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_mass)?; 23899df49d7eSJed Brown /// 2390c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 2391c68be7a2SJeremy L Thompson /// let op_diff = ceed.operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?; 2392c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_diff)?; 2393c68be7a2SJeremy L Thompson /// # Ok(()) 2394c68be7a2SJeremy L Thompson /// # } 23959df49d7eSJed Brown /// ``` 23969df49d7eSJed Brown #[allow(unused_mut)] 23979df49d7eSJed Brown pub fn sub_operator(mut self, subop: &Operator) -> crate::Result<Self> { 2398*656ef1e5SJeremy L Thompson self.op_core.check_error(unsafe { 2399*656ef1e5SJeremy L Thompson bind_ceed::CeedCompositeOperatorAddSub(self.op_core.ptr, subop.op_core.ptr) 2400*656ef1e5SJeremy L Thompson })?; 24019df49d7eSJed Brown Ok(self) 24029df49d7eSJed Brown } 24039df49d7eSJed Brown 24046f97ff0aSJeremy L Thompson /// Check if CompositeOperator is setup correctly 24056f97ff0aSJeremy L Thompson /// 24066f97ff0aSJeremy L Thompson /// ``` 24076f97ff0aSJeremy L Thompson /// # use libceed::prelude::*; 24086f97ff0aSJeremy L Thompson /// # fn main() -> libceed::Result<()> { 24096f97ff0aSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 24106f97ff0aSJeremy L Thompson /// let ne = 4; 24116f97ff0aSJeremy L Thompson /// let p = 3; 24126f97ff0aSJeremy L Thompson /// let q = 4; 24136f97ff0aSJeremy L Thompson /// let ndofs = p * ne - ne + 1; 24146f97ff0aSJeremy L Thompson /// 24156f97ff0aSJeremy L Thompson /// // Restrictions 24166f97ff0aSJeremy L Thompson /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 24176f97ff0aSJeremy L Thompson /// for i in 0..ne { 24186f97ff0aSJeremy L Thompson /// indx[2 * i + 0] = i as i32; 24196f97ff0aSJeremy L Thompson /// indx[2 * i + 1] = (i + 1) as i32; 24206f97ff0aSJeremy L Thompson /// } 24216f97ff0aSJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 24226f97ff0aSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 24236f97ff0aSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 24246f97ff0aSJeremy L Thompson /// 24256f97ff0aSJeremy L Thompson /// // Bases 24266f97ff0aSJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 24276f97ff0aSJeremy L Thompson /// 24286f97ff0aSJeremy L Thompson /// // Build quadrature data 24296f97ff0aSJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 24306f97ff0aSJeremy L Thompson /// let op_build_mass = ceed 24316f97ff0aSJeremy L Thompson /// .operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 24326f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 24336f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2434356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 24356f97ff0aSJeremy L Thompson /// 24366f97ff0aSJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 24376f97ff0aSJeremy L Thompson /// let op_build_diff = ceed 24386f97ff0aSJeremy L Thompson /// .operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 24396f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 24406f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2441356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 24426f97ff0aSJeremy L Thompson /// 24436f97ff0aSJeremy L Thompson /// let op_build = ceed 24446f97ff0aSJeremy L Thompson /// .composite_operator()? 24456f97ff0aSJeremy L Thompson /// .sub_operator(&op_build_mass)? 24466f97ff0aSJeremy L Thompson /// .sub_operator(&op_build_diff)?; 24476f97ff0aSJeremy L Thompson /// 24486f97ff0aSJeremy L Thompson /// // Check 24496f97ff0aSJeremy L Thompson /// assert!(op_build.check().is_ok(), "Operator setup incorrectly"); 24506f97ff0aSJeremy L Thompson /// # Ok(()) 24516f97ff0aSJeremy L Thompson /// # } 24526f97ff0aSJeremy L Thompson /// ``` 24536f97ff0aSJeremy L Thompson pub fn check(self) -> crate::Result<Self> { 24546f97ff0aSJeremy L Thompson self.op_core.check()?; 24556f97ff0aSJeremy L Thompson Ok(self) 24566f97ff0aSJeremy L Thompson } 24576f97ff0aSJeremy L Thompson 24589df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 24599df49d7eSJed Brown /// 24609df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 24619df49d7eSJed Brown /// 24629df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 24639df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 24649df49d7eSJed Brown /// 24659df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 24669df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 2467b748b478SJeremy L Thompson pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 24689df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 24699df49d7eSJed Brown } 24709df49d7eSJed Brown 24719df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 24729df49d7eSJed Brown /// 24739df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 24749df49d7eSJed Brown /// Operator. 24759df49d7eSJed Brown /// 24769df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 24779df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 24789df49d7eSJed Brown /// 24799df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 24809df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 24819df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 24829df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 24839df49d7eSJed Brown } 24849df49d7eSJed Brown 24859df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 24869df49d7eSJed Brown /// 24879df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 24889df49d7eSJed Brown /// 24899df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 24909df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 24919df49d7eSJed Brown /// 24929df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 24939df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 24949df49d7eSJed Brown /// diagonal, provided in row-major form with an 24959df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 24969df49d7eSJed Brown /// this vector are derived from the active vector for 24979df49d7eSJed Brown /// the CeedOperator. The array has shape 24989df49d7eSJed Brown /// `[nodes, component out, component in]`. 24999df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 25009df49d7eSJed Brown &self, 25019df49d7eSJed Brown assembled: &mut Vector, 25029df49d7eSJed Brown ) -> crate::Result<i32> { 25039df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 25049df49d7eSJed Brown } 25059df49d7eSJed Brown 25069df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 25079df49d7eSJed Brown /// 25089df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 25099df49d7eSJed Brown /// 25109df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 25119df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 25129df49d7eSJed Brown /// 25139df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 25149df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 25159df49d7eSJed Brown /// diagonal, provided in row-major form with an 25169df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 25179df49d7eSJed Brown /// this vector are derived from the active vector for 25189df49d7eSJed Brown /// the CeedOperator. The array has shape 25199df49d7eSJed Brown /// `[nodes, component out, component in]`. 25209df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 25219df49d7eSJed Brown &self, 25229df49d7eSJed Brown assembled: &mut Vector, 25239df49d7eSJed Brown ) -> crate::Result<i32> { 25249df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 25259df49d7eSJed Brown } 25269df49d7eSJed Brown } 25279df49d7eSJed Brown 25289df49d7eSJed Brown // ----------------------------------------------------------------------------- 2529