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, 20*e03fef56SJeremy L Thompson pub(crate) vector: crate::Vector<'a>, 21*e03fef56SJeremy L Thompson pub(crate) elem_restriction: crate::ElemRestriction<'a>, 22*e03fef56SJeremy 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> { 30*e03fef56SJeremy L Thompson pub(crate) fn from_raw( 31*e03fef56SJeremy L Thompson ptr: bind_ceed::CeedOperatorField, 32*e03fef56SJeremy L Thompson ceed: crate::Ceed, 33*e03fef56SJeremy L Thompson ) -> crate::Result<Self> { 34*e03fef56SJeremy L Thompson let vector = { 35*e03fef56SJeremy L Thompson let mut vector_ptr = std::ptr::null_mut(); 36*e03fef56SJeremy L Thompson let ierr = unsafe { bind_ceed::CeedOperatorFieldGetVector(ptr, &mut vector_ptr) }; 37*e03fef56SJeremy L Thompson ceed.check_error(ierr)?; 38*e03fef56SJeremy L Thompson crate::Vector::from_raw(vector_ptr)? 39*e03fef56SJeremy L Thompson }; 40*e03fef56SJeremy L Thompson let elem_restriction = { 41*e03fef56SJeremy L Thompson let mut elem_restriction_ptr = std::ptr::null_mut(); 42*e03fef56SJeremy L Thompson let ierr = unsafe { 43*e03fef56SJeremy L Thompson bind_ceed::CeedOperatorFieldGetElemRestriction(ptr, &mut elem_restriction_ptr) 44*e03fef56SJeremy L Thompson }; 45*e03fef56SJeremy L Thompson ceed.check_error(ierr)?; 46*e03fef56SJeremy L Thompson crate::ElemRestriction::from_raw(elem_restriction_ptr)? 47*e03fef56SJeremy L Thompson }; 48*e03fef56SJeremy L Thompson let basis = { 49*e03fef56SJeremy L Thompson let mut basis_ptr = std::ptr::null_mut(); 50*e03fef56SJeremy L Thompson let ierr = unsafe { bind_ceed::CeedOperatorFieldGetBasis(ptr, &mut basis_ptr) }; 51*e03fef56SJeremy L Thompson ceed.check_error(ierr)?; 52*e03fef56SJeremy L Thompson crate::Basis::from_raw(basis_ptr)? 53*e03fef56SJeremy L Thompson }; 54*e03fef56SJeremy L Thompson Ok(Self { 55*e03fef56SJeremy L Thompson ptr, 56*e03fef56SJeremy L Thompson vector, 57*e03fef56SJeremy L Thompson elem_restriction, 58*e03fef56SJeremy L Thompson basis, 59*e03fef56SJeremy L Thompson _lifeline: PhantomData, 60*e03fef56SJeremy L Thompson }) 61*e03fef56SJeremy L Thompson } 62*e03fef56SJeremy L Thompson 6308778c6fSJeremy L Thompson /// Get the name of an OperatorField 6408778c6fSJeremy L Thompson /// 6508778c6fSJeremy L Thompson /// ``` 6608778c6fSJeremy L Thompson /// # use libceed::prelude::*; 674d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 6808778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 6908778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 7008778c6fSJeremy L Thompson /// 7108778c6fSJeremy L Thompson /// // Operator field arguments 7208778c6fSJeremy L Thompson /// let ne = 3; 7308778c6fSJeremy L Thompson /// let q = 4 as usize; 7408778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 7508778c6fSJeremy L Thompson /// for i in 0..ne { 7608778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 7708778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 7808778c6fSJeremy L Thompson /// } 7908778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 8008778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 81d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 8208778c6fSJeremy L Thompson /// 8308778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 8408778c6fSJeremy L Thompson /// 8508778c6fSJeremy L Thompson /// // Operator fields 8608778c6fSJeremy L Thompson /// let op = ceed 8708778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 8808778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 8908778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 90356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 9108778c6fSJeremy L Thompson /// 9208778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 9308778c6fSJeremy L Thompson /// 9408778c6fSJeremy L Thompson /// assert_eq!(inputs[0].name(), "dx", "Incorrect input name"); 9508778c6fSJeremy L Thompson /// assert_eq!(inputs[1].name(), "weights", "Incorrect input name"); 9608778c6fSJeremy L Thompson /// # Ok(()) 9708778c6fSJeremy L Thompson /// # } 9808778c6fSJeremy L Thompson /// ``` 9908778c6fSJeremy L Thompson pub fn name(&self) -> &str { 10008778c6fSJeremy L Thompson let mut name_ptr: *mut std::os::raw::c_char = std::ptr::null_mut(); 10108778c6fSJeremy L Thompson unsafe { 1026f8994e9SJeremy L Thompson bind_ceed::CeedOperatorFieldGetName( 1036f8994e9SJeremy L Thompson self.ptr, 1046f8994e9SJeremy L Thompson &mut name_ptr as *const _ as *mut *const _, 1056f8994e9SJeremy L Thompson ); 10608778c6fSJeremy L Thompson } 10708778c6fSJeremy L Thompson unsafe { CStr::from_ptr(name_ptr) }.to_str().unwrap() 10808778c6fSJeremy L Thompson } 10908778c6fSJeremy L Thompson 11008778c6fSJeremy L Thompson /// Get the ElemRestriction of an OperatorField 11108778c6fSJeremy L Thompson /// 11208778c6fSJeremy L Thompson /// ``` 11308778c6fSJeremy L Thompson /// # use libceed::prelude::*; 1144d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 11508778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 11608778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 11708778c6fSJeremy L Thompson /// 11808778c6fSJeremy L Thompson /// // Operator field arguments 11908778c6fSJeremy L Thompson /// let ne = 3; 12008778c6fSJeremy L Thompson /// let q = 4 as usize; 12108778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 12208778c6fSJeremy L Thompson /// for i in 0..ne { 12308778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 12408778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 12508778c6fSJeremy L Thompson /// } 12608778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 12708778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 128d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 12908778c6fSJeremy L Thompson /// 13008778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 13108778c6fSJeremy L Thompson /// 13208778c6fSJeremy L Thompson /// // Operator fields 13308778c6fSJeremy L Thompson /// let op = ceed 13408778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 13508778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 13608778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 137356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 13808778c6fSJeremy L Thompson /// 13908778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 14008778c6fSJeremy L Thompson /// 14108778c6fSJeremy L Thompson /// assert!( 14208778c6fSJeremy L Thompson /// inputs[0].elem_restriction().is_some(), 14308778c6fSJeremy L Thompson /// "Incorrect field ElemRestriction" 14408778c6fSJeremy L Thompson /// ); 14508778c6fSJeremy L Thompson /// assert!( 14608778c6fSJeremy L Thompson /// inputs[1].elem_restriction().is_none(), 14708778c6fSJeremy L Thompson /// "Incorrect field ElemRestriction" 14808778c6fSJeremy L Thompson /// ); 149*e03fef56SJeremy L Thompson /// 150*e03fef56SJeremy L Thompson /// let outputs = op.outputs()?; 151*e03fef56SJeremy L Thompson /// 152*e03fef56SJeremy L Thompson /// assert!( 153*e03fef56SJeremy L Thompson /// outputs[0].elem_restriction().is_some(), 154*e03fef56SJeremy L Thompson /// "Incorrect field ElemRestriction" 155*e03fef56SJeremy L Thompson /// ); 15608778c6fSJeremy L Thompson /// # Ok(()) 15708778c6fSJeremy L Thompson /// # } 15808778c6fSJeremy L Thompson /// ``` 15908778c6fSJeremy L Thompson pub fn elem_restriction(&self) -> ElemRestrictionOpt { 160*e03fef56SJeremy L Thompson if self.elem_restriction.ptr == unsafe { bind_ceed::CEED_ELEMRESTRICTION_NONE } { 16108778c6fSJeremy L Thompson ElemRestrictionOpt::None 16208778c6fSJeremy L Thompson } else { 163*e03fef56SJeremy L Thompson ElemRestrictionOpt::Some(&self.elem_restriction) 16408778c6fSJeremy L Thompson } 16508778c6fSJeremy L Thompson } 16608778c6fSJeremy L Thompson 16708778c6fSJeremy L Thompson /// Get the Basis of an OperatorField 16808778c6fSJeremy L Thompson /// 16908778c6fSJeremy L Thompson /// ``` 17008778c6fSJeremy L Thompson /// # use libceed::prelude::*; 1714d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 17208778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 17308778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 17408778c6fSJeremy L Thompson /// 17508778c6fSJeremy L Thompson /// // Operator field arguments 17608778c6fSJeremy L Thompson /// let ne = 3; 17708778c6fSJeremy L Thompson /// let q = 4 as usize; 17808778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 17908778c6fSJeremy L Thompson /// for i in 0..ne { 18008778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 18108778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 18208778c6fSJeremy L Thompson /// } 18308778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 18408778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 185d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 18608778c6fSJeremy L Thompson /// 18708778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 18808778c6fSJeremy L Thompson /// 18908778c6fSJeremy L Thompson /// // Operator fields 19008778c6fSJeremy L Thompson /// let op = ceed 19108778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 19208778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 19308778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 194356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 19508778c6fSJeremy L Thompson /// 19608778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 19708778c6fSJeremy L Thompson /// 19808778c6fSJeremy L Thompson /// assert!(inputs[0].basis().is_some(), "Incorrect field Basis"); 19908778c6fSJeremy L Thompson /// assert!(inputs[1].basis().is_some(), "Incorrect field Basis"); 20008778c6fSJeremy L Thompson /// 20108778c6fSJeremy L Thompson /// let outputs = op.outputs()?; 20208778c6fSJeremy L Thompson /// 203356036faSJeremy L Thompson /// assert!(outputs[0].basis().is_none(), "Incorrect field Basis"); 20408778c6fSJeremy L Thompson /// # Ok(()) 20508778c6fSJeremy L Thompson /// # } 20608778c6fSJeremy L Thompson /// ``` 20708778c6fSJeremy L Thompson pub fn basis(&self) -> BasisOpt { 208*e03fef56SJeremy L Thompson if self.basis.ptr == unsafe { bind_ceed::CEED_BASIS_NONE } { 209356036faSJeremy L Thompson BasisOpt::None 21008778c6fSJeremy L Thompson } else { 211*e03fef56SJeremy L Thompson BasisOpt::Some(&self.basis) 21208778c6fSJeremy L Thompson } 21308778c6fSJeremy L Thompson } 21408778c6fSJeremy L Thompson 21508778c6fSJeremy L Thompson /// Get the Vector of an OperatorField 21608778c6fSJeremy L Thompson /// 21708778c6fSJeremy L Thompson /// ``` 21808778c6fSJeremy L Thompson /// # use libceed::prelude::*; 2194d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 22008778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 22108778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 22208778c6fSJeremy L Thompson /// 22308778c6fSJeremy L Thompson /// // Operator field arguments 22408778c6fSJeremy L Thompson /// let ne = 3; 22508778c6fSJeremy L Thompson /// let q = 4 as usize; 22608778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 22708778c6fSJeremy L Thompson /// for i in 0..ne { 22808778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 22908778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 23008778c6fSJeremy L Thompson /// } 23108778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 23208778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 233d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 23408778c6fSJeremy L Thompson /// 23508778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 23608778c6fSJeremy L Thompson /// 23708778c6fSJeremy L Thompson /// // Operator fields 23808778c6fSJeremy L Thompson /// let op = ceed 23908778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 24008778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 24108778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 242356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 24308778c6fSJeremy L Thompson /// 24408778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 24508778c6fSJeremy L Thompson /// 24608778c6fSJeremy L Thompson /// assert!(inputs[0].vector().is_active(), "Incorrect field Vector"); 24708778c6fSJeremy L Thompson /// assert!(inputs[1].vector().is_none(), "Incorrect field Vector"); 248*e03fef56SJeremy L Thompson /// 249*e03fef56SJeremy L Thompson /// let outputs = op.outputs()?; 250*e03fef56SJeremy L Thompson /// 251*e03fef56SJeremy L Thompson /// assert!(outputs[0].vector().is_active(), "Incorrect field Vector"); 25208778c6fSJeremy L Thompson /// # Ok(()) 25308778c6fSJeremy L Thompson /// # } 25408778c6fSJeremy L Thompson /// ``` 25508778c6fSJeremy L Thompson pub fn vector(&self) -> VectorOpt { 256*e03fef56SJeremy L Thompson if self.vector.ptr == unsafe { bind_ceed::CEED_VECTOR_ACTIVE } { 25708778c6fSJeremy L Thompson VectorOpt::Active 258*e03fef56SJeremy L Thompson } else if self.vector.ptr == unsafe { bind_ceed::CEED_VECTOR_NONE } { 25908778c6fSJeremy L Thompson VectorOpt::None 26008778c6fSJeremy L Thompson } else { 261*e03fef56SJeremy L Thompson VectorOpt::Some(&self.vector) 26208778c6fSJeremy L Thompson } 26308778c6fSJeremy L Thompson } 26408778c6fSJeremy L Thompson } 26508778c6fSJeremy L Thompson 26608778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 2677ed177dbSJed Brown // Operator context wrapper 2689df49d7eSJed Brown // ----------------------------------------------------------------------------- 269c68be7a2SJeremy L Thompson #[derive(Debug)] 2709df49d7eSJed Brown pub(crate) struct OperatorCore<'a> { 2719df49d7eSJed Brown ptr: bind_ceed::CeedOperator, 2721142270cSJeremy L Thompson _lifeline: PhantomData<&'a ()>, 2739df49d7eSJed Brown } 2749df49d7eSJed Brown 275c68be7a2SJeremy L Thompson #[derive(Debug)] 2769df49d7eSJed Brown pub struct Operator<'a> { 2779df49d7eSJed Brown op_core: OperatorCore<'a>, 2789df49d7eSJed Brown } 2799df49d7eSJed Brown 280c68be7a2SJeremy L Thompson #[derive(Debug)] 2819df49d7eSJed Brown pub struct CompositeOperator<'a> { 2829df49d7eSJed Brown op_core: OperatorCore<'a>, 2839df49d7eSJed Brown } 2849df49d7eSJed Brown 2859df49d7eSJed Brown // ----------------------------------------------------------------------------- 2869df49d7eSJed Brown // Destructor 2879df49d7eSJed Brown // ----------------------------------------------------------------------------- 2889df49d7eSJed Brown impl<'a> Drop for OperatorCore<'a> { 2899df49d7eSJed Brown fn drop(&mut self) { 2909df49d7eSJed Brown unsafe { 2919df49d7eSJed Brown bind_ceed::CeedOperatorDestroy(&mut self.ptr); 2929df49d7eSJed Brown } 2939df49d7eSJed Brown } 2949df49d7eSJed Brown } 2959df49d7eSJed Brown 2969df49d7eSJed Brown // ----------------------------------------------------------------------------- 2979df49d7eSJed Brown // Display 2989df49d7eSJed Brown // ----------------------------------------------------------------------------- 2999df49d7eSJed Brown impl<'a> fmt::Display for OperatorCore<'a> { 3009df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 3019df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 3029df49d7eSJed Brown let mut sizeloc = crate::MAX_BUFFER_LENGTH; 3039df49d7eSJed Brown let cstring = unsafe { 3049df49d7eSJed Brown let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc); 3059df49d7eSJed Brown bind_ceed::CeedOperatorView(self.ptr, file); 3069df49d7eSJed Brown bind_ceed::fclose(file); 3079df49d7eSJed Brown CString::from_raw(ptr) 3089df49d7eSJed Brown }; 3099df49d7eSJed Brown cstring.to_string_lossy().fmt(f) 3109df49d7eSJed Brown } 3119df49d7eSJed Brown } 3129df49d7eSJed Brown 3139df49d7eSJed Brown /// View an Operator 3149df49d7eSJed Brown /// 3159df49d7eSJed Brown /// ``` 3169df49d7eSJed Brown /// # use libceed::prelude::*; 3174d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 3189df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 319c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 3209df49d7eSJed Brown /// 3219df49d7eSJed Brown /// // Operator field arguments 3229df49d7eSJed Brown /// let ne = 3; 3239df49d7eSJed Brown /// let q = 4 as usize; 3249df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 3259df49d7eSJed Brown /// for i in 0..ne { 3269df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 3279df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 3289df49d7eSJed Brown /// } 329c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 3309df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 331d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 3329df49d7eSJed Brown /// 333c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 3349df49d7eSJed Brown /// 3359df49d7eSJed Brown /// // Operator fields 3369df49d7eSJed Brown /// let op = ceed 337c68be7a2SJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 338ea6b5821SJeremy L Thompson /// .name("mass")? 339c68be7a2SJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 340c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 341356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 3429df49d7eSJed Brown /// 3439df49d7eSJed Brown /// println!("{}", op); 344c68be7a2SJeremy L Thompson /// # Ok(()) 345c68be7a2SJeremy L Thompson /// # } 3469df49d7eSJed Brown /// ``` 3479df49d7eSJed Brown impl<'a> fmt::Display for Operator<'a> { 3489df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 3499df49d7eSJed Brown self.op_core.fmt(f) 3509df49d7eSJed Brown } 3519df49d7eSJed Brown } 3529df49d7eSJed Brown 3539df49d7eSJed Brown /// View a composite Operator 3549df49d7eSJed Brown /// 3559df49d7eSJed Brown /// ``` 3569df49d7eSJed Brown /// # use libceed::prelude::*; 3574d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 3589df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 3599df49d7eSJed Brown /// 3609df49d7eSJed Brown /// // Sub operator field arguments 3619df49d7eSJed Brown /// let ne = 3; 3629df49d7eSJed Brown /// let q = 4 as usize; 3639df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 3649df49d7eSJed Brown /// for i in 0..ne { 3659df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 3669df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 3679df49d7eSJed Brown /// } 368c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 3699df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 370d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 3719df49d7eSJed Brown /// 372c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 3739df49d7eSJed Brown /// 374c68be7a2SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?; 375c68be7a2SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?; 3769df49d7eSJed Brown /// 377c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 3789df49d7eSJed Brown /// let op_mass = ceed 379c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 380ea6b5821SJeremy L Thompson /// .name("Mass term")? 381c68be7a2SJeremy L Thompson /// .field("u", &r, &b, VectorOpt::Active)? 382356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_mass)? 383c68be7a2SJeremy L Thompson /// .field("v", &r, &b, VectorOpt::Active)?; 3849df49d7eSJed Brown /// 385c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 3869df49d7eSJed Brown /// let op_diff = ceed 387c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 388ea6b5821SJeremy L Thompson /// .name("Poisson term")? 389c68be7a2SJeremy L Thompson /// .field("du", &r, &b, VectorOpt::Active)? 390356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_diff)? 391c68be7a2SJeremy L Thompson /// .field("dv", &r, &b, VectorOpt::Active)?; 3929df49d7eSJed Brown /// 3939df49d7eSJed Brown /// let op = ceed 394c68be7a2SJeremy L Thompson /// .composite_operator()? 395ea6b5821SJeremy L Thompson /// .name("Screened Poisson")? 396c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 397c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 3989df49d7eSJed Brown /// 3999df49d7eSJed Brown /// println!("{}", op); 400c68be7a2SJeremy L Thompson /// # Ok(()) 401c68be7a2SJeremy L Thompson /// # } 4029df49d7eSJed Brown /// ``` 4039df49d7eSJed Brown impl<'a> fmt::Display for CompositeOperator<'a> { 4049df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 4059df49d7eSJed Brown self.op_core.fmt(f) 4069df49d7eSJed Brown } 4079df49d7eSJed Brown } 4089df49d7eSJed Brown 4099df49d7eSJed Brown // ----------------------------------------------------------------------------- 4109df49d7eSJed Brown // Core functionality 4119df49d7eSJed Brown // ----------------------------------------------------------------------------- 4129df49d7eSJed Brown impl<'a> OperatorCore<'a> { 4131142270cSJeremy L Thompson // Error handling 4141142270cSJeremy L Thompson #[doc(hidden)] 4151142270cSJeremy L Thompson fn check_error(&self, ierr: i32) -> crate::Result<i32> { 4161142270cSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 4171142270cSJeremy L Thompson unsafe { 4181142270cSJeremy L Thompson bind_ceed::CeedOperatorGetCeed(self.ptr, &mut ptr); 4191142270cSJeremy L Thompson } 4201142270cSJeremy L Thompson crate::check_error(ptr, ierr) 4211142270cSJeremy L Thompson } 4221142270cSJeremy L Thompson 4239df49d7eSJed Brown // Common implementations 4246f97ff0aSJeremy L Thompson pub fn check(&self) -> crate::Result<i32> { 4256f97ff0aSJeremy L Thompson let ierr = unsafe { bind_ceed::CeedOperatorCheckReady(self.ptr) }; 4266f97ff0aSJeremy L Thompson self.check_error(ierr) 4276f97ff0aSJeremy L Thompson } 4286f97ff0aSJeremy L Thompson 429ea6b5821SJeremy L Thompson pub fn name(&self, name: &str) -> crate::Result<i32> { 430ea6b5821SJeremy L Thompson let name_c = CString::new(name).expect("CString::new failed"); 431ea6b5821SJeremy L Thompson let ierr = unsafe { bind_ceed::CeedOperatorSetName(self.ptr, name_c.as_ptr()) }; 432ea6b5821SJeremy L Thompson self.check_error(ierr) 433ea6b5821SJeremy L Thompson } 434ea6b5821SJeremy L Thompson 4359df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 4369df49d7eSJed Brown let ierr = unsafe { 4379df49d7eSJed Brown bind_ceed::CeedOperatorApply( 4389df49d7eSJed Brown self.ptr, 4399df49d7eSJed Brown input.ptr, 4409df49d7eSJed Brown output.ptr, 4419df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4429df49d7eSJed Brown ) 4439df49d7eSJed Brown }; 4441142270cSJeremy L Thompson self.check_error(ierr) 4459df49d7eSJed Brown } 4469df49d7eSJed Brown 4479df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 4489df49d7eSJed Brown let ierr = unsafe { 4499df49d7eSJed Brown bind_ceed::CeedOperatorApplyAdd( 4509df49d7eSJed Brown self.ptr, 4519df49d7eSJed Brown input.ptr, 4529df49d7eSJed Brown output.ptr, 4539df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4549df49d7eSJed Brown ) 4559df49d7eSJed Brown }; 4561142270cSJeremy L Thompson self.check_error(ierr) 4579df49d7eSJed Brown } 4589df49d7eSJed Brown 4599df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 4609df49d7eSJed Brown let ierr = unsafe { 4619df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleDiagonal( 4629df49d7eSJed Brown self.ptr, 4639df49d7eSJed Brown assembled.ptr, 4649df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4659df49d7eSJed Brown ) 4669df49d7eSJed Brown }; 4671142270cSJeremy L Thompson self.check_error(ierr) 4689df49d7eSJed Brown } 4699df49d7eSJed Brown 4709df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 4719df49d7eSJed Brown let ierr = unsafe { 4729df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddDiagonal( 4739df49d7eSJed Brown self.ptr, 4749df49d7eSJed Brown assembled.ptr, 4759df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4769df49d7eSJed Brown ) 4779df49d7eSJed Brown }; 4781142270cSJeremy L Thompson self.check_error(ierr) 4799df49d7eSJed Brown } 4809df49d7eSJed Brown 4819df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 4829df49d7eSJed Brown &self, 4839df49d7eSJed Brown assembled: &mut Vector, 4849df49d7eSJed Brown ) -> crate::Result<i32> { 4859df49d7eSJed Brown let ierr = unsafe { 4869df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssemblePointBlockDiagonal( 4879df49d7eSJed Brown self.ptr, 4889df49d7eSJed Brown assembled.ptr, 4899df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4909df49d7eSJed Brown ) 4919df49d7eSJed Brown }; 4921142270cSJeremy L Thompson self.check_error(ierr) 4939df49d7eSJed Brown } 4949df49d7eSJed Brown 4959df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 4969df49d7eSJed Brown &self, 4979df49d7eSJed Brown assembled: &mut Vector, 4989df49d7eSJed Brown ) -> crate::Result<i32> { 4999df49d7eSJed Brown let ierr = unsafe { 5009df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddPointBlockDiagonal( 5019df49d7eSJed Brown self.ptr, 5029df49d7eSJed Brown assembled.ptr, 5039df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 5049df49d7eSJed Brown ) 5059df49d7eSJed Brown }; 5061142270cSJeremy L Thompson self.check_error(ierr) 5079df49d7eSJed Brown } 5089df49d7eSJed Brown } 5099df49d7eSJed Brown 5109df49d7eSJed Brown // ----------------------------------------------------------------------------- 5119df49d7eSJed Brown // Operator 5129df49d7eSJed Brown // ----------------------------------------------------------------------------- 5139df49d7eSJed Brown impl<'a> Operator<'a> { 5149df49d7eSJed Brown // Constructor 5159df49d7eSJed Brown pub fn create<'b>( 516594ef120SJeremy L Thompson ceed: &crate::Ceed, 5179df49d7eSJed Brown qf: impl Into<QFunctionOpt<'b>>, 5189df49d7eSJed Brown dqf: impl Into<QFunctionOpt<'b>>, 5199df49d7eSJed Brown dqfT: impl Into<QFunctionOpt<'b>>, 5209df49d7eSJed Brown ) -> crate::Result<Self> { 5219df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 5229df49d7eSJed Brown let ierr = unsafe { 5239df49d7eSJed Brown bind_ceed::CeedOperatorCreate( 5249df49d7eSJed Brown ceed.ptr, 5259df49d7eSJed Brown qf.into().to_raw(), 5269df49d7eSJed Brown dqf.into().to_raw(), 5279df49d7eSJed Brown dqfT.into().to_raw(), 5289df49d7eSJed Brown &mut ptr, 5299df49d7eSJed Brown ) 5309df49d7eSJed Brown }; 5319df49d7eSJed Brown ceed.check_error(ierr)?; 5329df49d7eSJed Brown Ok(Self { 5331142270cSJeremy L Thompson op_core: OperatorCore { 5341142270cSJeremy L Thompson ptr, 5351142270cSJeremy L Thompson _lifeline: PhantomData, 5361142270cSJeremy L Thompson }, 5379df49d7eSJed Brown }) 5389df49d7eSJed Brown } 5399df49d7eSJed Brown 5401142270cSJeremy L Thompson fn from_raw(ptr: bind_ceed::CeedOperator) -> crate::Result<Self> { 5419df49d7eSJed Brown Ok(Self { 5421142270cSJeremy L Thompson op_core: OperatorCore { 5431142270cSJeremy L Thompson ptr, 5441142270cSJeremy L Thompson _lifeline: PhantomData, 5451142270cSJeremy L Thompson }, 5469df49d7eSJed Brown }) 5479df49d7eSJed Brown } 5489df49d7eSJed Brown 549ea6b5821SJeremy L Thompson /// Set name for Operator printing 550ea6b5821SJeremy L Thompson /// 551ea6b5821SJeremy L Thompson /// * 'name' - Name to set 552ea6b5821SJeremy L Thompson /// 553ea6b5821SJeremy L Thompson /// ``` 554ea6b5821SJeremy L Thompson /// # use libceed::prelude::*; 555ea6b5821SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 556ea6b5821SJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 557ea6b5821SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 558ea6b5821SJeremy L Thompson /// 559ea6b5821SJeremy L Thompson /// // Operator field arguments 560ea6b5821SJeremy L Thompson /// let ne = 3; 561ea6b5821SJeremy L Thompson /// let q = 4 as usize; 562ea6b5821SJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 563ea6b5821SJeremy L Thompson /// for i in 0..ne { 564ea6b5821SJeremy L Thompson /// ind[2 * i + 0] = i as i32; 565ea6b5821SJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 566ea6b5821SJeremy L Thompson /// } 567ea6b5821SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 568ea6b5821SJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 569d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 570ea6b5821SJeremy L Thompson /// 571ea6b5821SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 572ea6b5821SJeremy L Thompson /// 573ea6b5821SJeremy L Thompson /// // Operator fields 574ea6b5821SJeremy L Thompson /// let op = ceed 575ea6b5821SJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 576ea6b5821SJeremy L Thompson /// .name("mass")? 577ea6b5821SJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 578ea6b5821SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 579356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 580ea6b5821SJeremy L Thompson /// # Ok(()) 581ea6b5821SJeremy L Thompson /// # } 582ea6b5821SJeremy L Thompson /// ``` 583ea6b5821SJeremy L Thompson #[allow(unused_mut)] 584ea6b5821SJeremy L Thompson pub fn name(mut self, name: &str) -> crate::Result<Self> { 585ea6b5821SJeremy L Thompson self.op_core.name(name)?; 586ea6b5821SJeremy L Thompson Ok(self) 587ea6b5821SJeremy L Thompson } 588ea6b5821SJeremy L Thompson 5899df49d7eSJed Brown /// Apply Operator to a vector 5909df49d7eSJed Brown /// 5919df49d7eSJed Brown /// * `input` - Input Vector 5929df49d7eSJed Brown /// * `output` - Output Vector 5939df49d7eSJed Brown /// 5949df49d7eSJed Brown /// ``` 5959df49d7eSJed Brown /// # use libceed::prelude::*; 5964d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 5979df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 5989df49d7eSJed Brown /// let ne = 4; 5999df49d7eSJed Brown /// let p = 3; 6009df49d7eSJed Brown /// let q = 4; 6019df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 6029df49d7eSJed Brown /// 6039df49d7eSJed Brown /// // Vectors 604c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 605c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 6069df49d7eSJed Brown /// qdata.set_value(0.0); 607c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 608c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 6099df49d7eSJed Brown /// v.set_value(0.0); 6109df49d7eSJed Brown /// 6119df49d7eSJed Brown /// // Restrictions 6129df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 6139df49d7eSJed Brown /// for i in 0..ne { 6149df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 6159df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 6169df49d7eSJed Brown /// } 617c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 6189df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 6199df49d7eSJed Brown /// for i in 0..ne { 6209df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 6219df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 6229df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 6239df49d7eSJed Brown /// } 624c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 6259df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 626c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 6279df49d7eSJed Brown /// 6289df49d7eSJed Brown /// // Bases 629c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 630c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 6319df49d7eSJed Brown /// 6329df49d7eSJed Brown /// // Build quadrature data 633c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 634c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 635c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 636c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 637356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 638c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 6399df49d7eSJed Brown /// 6409df49d7eSJed Brown /// // Mass operator 641c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 6429df49d7eSJed Brown /// let op_mass = ceed 643c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 644c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 645356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 646c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 6479df49d7eSJed Brown /// 6489df49d7eSJed Brown /// v.set_value(0.0); 649c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 6509df49d7eSJed Brown /// 6519df49d7eSJed Brown /// // Check 652e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 6534b61a5a0SRezgar Shakeri /// let error: Scalar = (sum - 2.0).abs(); 6549df49d7eSJed Brown /// assert!( 6554b61a5a0SRezgar Shakeri /// error < 50.0 * libceed::EPSILON, 6564b61a5a0SRezgar Shakeri /// "Incorrect interval length computed. Expected: 2.0, Found: {}, Error: {:.12e}", 6574b61a5a0SRezgar Shakeri /// sum, 6584b61a5a0SRezgar Shakeri /// error 6599df49d7eSJed Brown /// ); 660c68be7a2SJeremy L Thompson /// # Ok(()) 661c68be7a2SJeremy L Thompson /// # } 6629df49d7eSJed Brown /// ``` 6639df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 6649df49d7eSJed Brown self.op_core.apply(input, output) 6659df49d7eSJed Brown } 6669df49d7eSJed Brown 6679df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 6689df49d7eSJed Brown /// 6699df49d7eSJed Brown /// * `input` - Input Vector 6709df49d7eSJed Brown /// * `output` - Output Vector 6719df49d7eSJed Brown /// 6729df49d7eSJed Brown /// ``` 6739df49d7eSJed Brown /// # use libceed::prelude::*; 6744d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 6759df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 6769df49d7eSJed Brown /// let ne = 4; 6779df49d7eSJed Brown /// let p = 3; 6789df49d7eSJed Brown /// let q = 4; 6799df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 6809df49d7eSJed Brown /// 6819df49d7eSJed Brown /// // Vectors 682c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 683c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 6849df49d7eSJed Brown /// qdata.set_value(0.0); 685c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 686c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 6879df49d7eSJed Brown /// 6889df49d7eSJed Brown /// // Restrictions 6899df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 6909df49d7eSJed Brown /// for i in 0..ne { 6919df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 6929df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 6939df49d7eSJed Brown /// } 694c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 6959df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 6969df49d7eSJed Brown /// for i in 0..ne { 6979df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 6989df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 6999df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 7009df49d7eSJed Brown /// } 701c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 7029df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 703c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 7049df49d7eSJed Brown /// 7059df49d7eSJed Brown /// // Bases 706c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 707c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 7089df49d7eSJed Brown /// 7099df49d7eSJed Brown /// // Build quadrature data 710c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 711c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 712c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 713c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 714356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 715c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 7169df49d7eSJed Brown /// 7179df49d7eSJed Brown /// // Mass operator 718c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 7199df49d7eSJed Brown /// let op_mass = ceed 720c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 721c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 722356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 723c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 7249df49d7eSJed Brown /// 7259df49d7eSJed Brown /// v.set_value(1.0); 726c68be7a2SJeremy L Thompson /// op_mass.apply_add(&u, &mut v)?; 7279df49d7eSJed Brown /// 7289df49d7eSJed Brown /// // Check 729e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 7309df49d7eSJed Brown /// assert!( 73180a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 7329df49d7eSJed Brown /// "Incorrect interval length computed and added" 7339df49d7eSJed Brown /// ); 734c68be7a2SJeremy L Thompson /// # Ok(()) 735c68be7a2SJeremy L Thompson /// # } 7369df49d7eSJed Brown /// ``` 7379df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 7389df49d7eSJed Brown self.op_core.apply_add(input, output) 7399df49d7eSJed Brown } 7409df49d7eSJed Brown 7419df49d7eSJed Brown /// Provide a field to a Operator for use by its QFunction 7429df49d7eSJed Brown /// 7439df49d7eSJed Brown /// * `fieldname` - Name of the field (to be matched with the name used by 7449df49d7eSJed Brown /// the QFunction) 7459df49d7eSJed Brown /// * `r` - ElemRestriction 746356036faSJeremy L Thompson /// * `b` - Basis in which the field resides or `BasisOpt::None` 747356036faSJeremy L Thompson /// * `v` - Vector to be used by Operator or `VectorOpt::Active` if field 748356036faSJeremy L Thompson /// is active or `VectorOpt::None` if using `Weight` with the 7499df49d7eSJed Brown /// QFunction 7509df49d7eSJed Brown /// 7519df49d7eSJed Brown /// 7529df49d7eSJed Brown /// ``` 7539df49d7eSJed Brown /// # use libceed::prelude::*; 7544d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 7559df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 756c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 757c68be7a2SJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 7589df49d7eSJed Brown /// 7599df49d7eSJed Brown /// // Operator field arguments 7609df49d7eSJed Brown /// let ne = 3; 7619df49d7eSJed Brown /// let q = 4; 7629df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 7639df49d7eSJed Brown /// for i in 0..ne { 7649df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 7659df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 7669df49d7eSJed Brown /// } 767c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 7689df49d7eSJed Brown /// 769c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 7709df49d7eSJed Brown /// 7719df49d7eSJed Brown /// // Operator field 772c68be7a2SJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 773c68be7a2SJeremy L Thompson /// # Ok(()) 774c68be7a2SJeremy L Thompson /// # } 7759df49d7eSJed Brown /// ``` 7769df49d7eSJed Brown #[allow(unused_mut)] 7779df49d7eSJed Brown pub fn field<'b>( 7789df49d7eSJed Brown mut self, 7799df49d7eSJed Brown fieldname: &str, 7809df49d7eSJed Brown r: impl Into<ElemRestrictionOpt<'b>>, 7819df49d7eSJed Brown b: impl Into<BasisOpt<'b>>, 7829df49d7eSJed Brown v: impl Into<VectorOpt<'b>>, 7839df49d7eSJed Brown ) -> crate::Result<Self> { 7849df49d7eSJed Brown let fieldname = CString::new(fieldname).expect("CString::new failed"); 7859df49d7eSJed Brown let fieldname = fieldname.as_ptr() as *const i8; 7869df49d7eSJed Brown let ierr = unsafe { 7879df49d7eSJed Brown bind_ceed::CeedOperatorSetField( 7889df49d7eSJed Brown self.op_core.ptr, 7899df49d7eSJed Brown fieldname, 7909df49d7eSJed Brown r.into().to_raw(), 7919df49d7eSJed Brown b.into().to_raw(), 7929df49d7eSJed Brown v.into().to_raw(), 7939df49d7eSJed Brown ) 7949df49d7eSJed Brown }; 7951142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 7969df49d7eSJed Brown Ok(self) 7979df49d7eSJed Brown } 7989df49d7eSJed Brown 79908778c6fSJeremy L Thompson /// Get a slice of Operator inputs 80008778c6fSJeremy L Thompson /// 80108778c6fSJeremy L Thompson /// ``` 80208778c6fSJeremy L Thompson /// # use libceed::prelude::*; 8034d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 80408778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 80508778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 80608778c6fSJeremy L Thompson /// 80708778c6fSJeremy L Thompson /// // Operator field arguments 80808778c6fSJeremy L Thompson /// let ne = 3; 80908778c6fSJeremy L Thompson /// let q = 4 as usize; 81008778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 81108778c6fSJeremy L Thompson /// for i in 0..ne { 81208778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 81308778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 81408778c6fSJeremy L Thompson /// } 81508778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 81608778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 817d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 81808778c6fSJeremy L Thompson /// 81908778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 82008778c6fSJeremy L Thompson /// 82108778c6fSJeremy L Thompson /// // Operator fields 82208778c6fSJeremy L Thompson /// let op = ceed 82308778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 82408778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 82508778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 826356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 82708778c6fSJeremy L Thompson /// 82808778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 82908778c6fSJeremy L Thompson /// 83008778c6fSJeremy L Thompson /// assert_eq!(inputs.len(), 2, "Incorrect inputs array"); 83108778c6fSJeremy L Thompson /// # Ok(()) 83208778c6fSJeremy L Thompson /// # } 83308778c6fSJeremy L Thompson /// ``` 834*e03fef56SJeremy L Thompson pub fn inputs(&self) -> crate::Result<Vec<crate::OperatorField>> { 83508778c6fSJeremy L Thompson // Get array of raw C pointers for inputs 83608778c6fSJeremy L Thompson let mut num_inputs = 0; 83708778c6fSJeremy L Thompson let mut inputs_ptr = std::ptr::null_mut(); 83808778c6fSJeremy L Thompson let ierr = unsafe { 83908778c6fSJeremy L Thompson bind_ceed::CeedOperatorGetFields( 84008778c6fSJeremy L Thompson self.op_core.ptr, 84108778c6fSJeremy L Thompson &mut num_inputs, 84208778c6fSJeremy L Thompson &mut inputs_ptr, 84308778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt, 84408778c6fSJeremy L Thompson std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField, 84508778c6fSJeremy L Thompson ) 84608778c6fSJeremy L Thompson }; 84708778c6fSJeremy L Thompson self.op_core.check_error(ierr)?; 84808778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice 84908778c6fSJeremy L Thompson let inputs_slice = unsafe { 85008778c6fSJeremy L Thompson std::slice::from_raw_parts( 851*e03fef56SJeremy L Thompson inputs_ptr as *mut bind_ceed::CeedOperatorField, 85208778c6fSJeremy L Thompson num_inputs as usize, 85308778c6fSJeremy L Thompson ) 85408778c6fSJeremy L Thompson }; 855*e03fef56SJeremy L Thompson // And finally build vec 856*e03fef56SJeremy L Thompson let ceed = { 857*e03fef56SJeremy L Thompson let mut ptr = std::ptr::null_mut(); 858*e03fef56SJeremy L Thompson let mut ptr_copy = std::ptr::null_mut(); 859*e03fef56SJeremy L Thompson unsafe { 860*e03fef56SJeremy L Thompson bind_ceed::CeedOperatorGetCeed(self.op_core.ptr, &mut ptr); 861*e03fef56SJeremy L Thompson bind_ceed::CeedReferenceCopy(ptr, &mut ptr_copy); // refcount 862*e03fef56SJeremy L Thompson } 863*e03fef56SJeremy L Thompson crate::Ceed { ptr } 864*e03fef56SJeremy L Thompson }; 865*e03fef56SJeremy L Thompson let inputs = (0..num_inputs as usize) 866*e03fef56SJeremy L Thompson .map(|i| crate::OperatorField::from_raw(inputs_slice[i], ceed.clone())) 867*e03fef56SJeremy L Thompson .collect::<crate::Result<Vec<_>>>()?; 868*e03fef56SJeremy L Thompson Ok(inputs) 86908778c6fSJeremy L Thompson } 87008778c6fSJeremy L Thompson 87108778c6fSJeremy L Thompson /// Get a slice of Operator outputs 87208778c6fSJeremy L Thompson /// 87308778c6fSJeremy L Thompson /// ``` 87408778c6fSJeremy L Thompson /// # use libceed::prelude::*; 8754d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 87608778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 87708778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 87808778c6fSJeremy L Thompson /// 87908778c6fSJeremy L Thompson /// // Operator field arguments 88008778c6fSJeremy L Thompson /// let ne = 3; 88108778c6fSJeremy L Thompson /// let q = 4 as usize; 88208778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 88308778c6fSJeremy L Thompson /// for i in 0..ne { 88408778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 88508778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 88608778c6fSJeremy L Thompson /// } 88708778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 88808778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 889d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 89008778c6fSJeremy L Thompson /// 89108778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 89208778c6fSJeremy L Thompson /// 89308778c6fSJeremy L Thompson /// // Operator fields 89408778c6fSJeremy L Thompson /// let op = ceed 89508778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 89608778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 89708778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 898356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 89908778c6fSJeremy L Thompson /// 90008778c6fSJeremy L Thompson /// let outputs = op.outputs()?; 90108778c6fSJeremy L Thompson /// 90208778c6fSJeremy L Thompson /// assert_eq!(outputs.len(), 1, "Incorrect outputs array"); 90308778c6fSJeremy L Thompson /// # Ok(()) 90408778c6fSJeremy L Thompson /// # } 90508778c6fSJeremy L Thompson /// ``` 906*e03fef56SJeremy L Thompson pub fn outputs(&self) -> crate::Result<Vec<crate::OperatorField>> { 90708778c6fSJeremy L Thompson // Get array of raw C pointers for outputs 90808778c6fSJeremy L Thompson let mut num_outputs = 0; 90908778c6fSJeremy L Thompson let mut outputs_ptr = std::ptr::null_mut(); 91008778c6fSJeremy L Thompson let ierr = unsafe { 91108778c6fSJeremy L Thompson bind_ceed::CeedOperatorGetFields( 91208778c6fSJeremy L Thompson self.op_core.ptr, 91308778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt, 91408778c6fSJeremy L Thompson std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField, 91508778c6fSJeremy L Thompson &mut num_outputs, 91608778c6fSJeremy L Thompson &mut outputs_ptr, 91708778c6fSJeremy L Thompson ) 91808778c6fSJeremy L Thompson }; 91908778c6fSJeremy L Thompson self.op_core.check_error(ierr)?; 92008778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice 92108778c6fSJeremy L Thompson let outputs_slice = unsafe { 92208778c6fSJeremy L Thompson std::slice::from_raw_parts( 923*e03fef56SJeremy L Thompson outputs_ptr as *mut bind_ceed::CeedOperatorField, 92408778c6fSJeremy L Thompson num_outputs as usize, 92508778c6fSJeremy L Thompson ) 92608778c6fSJeremy L Thompson }; 927*e03fef56SJeremy L Thompson // And finally build vec 928*e03fef56SJeremy L Thompson let ceed = { 929*e03fef56SJeremy L Thompson let mut ptr = std::ptr::null_mut(); 930*e03fef56SJeremy L Thompson let mut ptr_copy = std::ptr::null_mut(); 931*e03fef56SJeremy L Thompson unsafe { 932*e03fef56SJeremy L Thompson bind_ceed::CeedOperatorGetCeed(self.op_core.ptr, &mut ptr); 933*e03fef56SJeremy L Thompson bind_ceed::CeedReferenceCopy(ptr, &mut ptr_copy); // refcount 934*e03fef56SJeremy L Thompson } 935*e03fef56SJeremy L Thompson crate::Ceed { ptr } 936*e03fef56SJeremy L Thompson }; 937*e03fef56SJeremy L Thompson let outputs = (0..num_outputs as usize) 938*e03fef56SJeremy L Thompson .map(|i| crate::OperatorField::from_raw(outputs_slice[i], ceed.clone())) 939*e03fef56SJeremy L Thompson .collect::<crate::Result<Vec<_>>>()?; 940*e03fef56SJeremy L Thompson Ok(outputs) 94108778c6fSJeremy L Thompson } 94208778c6fSJeremy L Thompson 9436f97ff0aSJeremy L Thompson /// Check if Operator is setup correctly 9446f97ff0aSJeremy L Thompson /// 9456f97ff0aSJeremy L Thompson /// ``` 9466f97ff0aSJeremy L Thompson /// # use libceed::prelude::*; 9476f97ff0aSJeremy L Thompson /// # fn main() -> libceed::Result<()> { 9486f97ff0aSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 9496f97ff0aSJeremy L Thompson /// let ne = 4; 9506f97ff0aSJeremy L Thompson /// let p = 3; 9516f97ff0aSJeremy L Thompson /// let q = 4; 9526f97ff0aSJeremy L Thompson /// let ndofs = p * ne - ne + 1; 9536f97ff0aSJeremy L Thompson /// 9546f97ff0aSJeremy L Thompson /// // Restrictions 9556f97ff0aSJeremy L Thompson /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 9566f97ff0aSJeremy L Thompson /// for i in 0..ne { 9576f97ff0aSJeremy L Thompson /// indx[2 * i + 0] = i as i32; 9586f97ff0aSJeremy L Thompson /// indx[2 * i + 1] = (i + 1) as i32; 9596f97ff0aSJeremy L Thompson /// } 9606f97ff0aSJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 9616f97ff0aSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 9626f97ff0aSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 9636f97ff0aSJeremy L Thompson /// 9646f97ff0aSJeremy L Thompson /// // Bases 9656f97ff0aSJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 9666f97ff0aSJeremy L Thompson /// 9676f97ff0aSJeremy L Thompson /// // Build quadrature data 9686f97ff0aSJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 9696f97ff0aSJeremy L Thompson /// let op_build = ceed 9706f97ff0aSJeremy L Thompson /// .operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 9716f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 9726f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 973356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 9746f97ff0aSJeremy L Thompson /// 9756f97ff0aSJeremy L Thompson /// // Check 9766f97ff0aSJeremy L Thompson /// assert!(op_build.check().is_ok(), "Operator setup incorrectly"); 9776f97ff0aSJeremy L Thompson /// # Ok(()) 9786f97ff0aSJeremy L Thompson /// # } 9796f97ff0aSJeremy L Thompson /// ``` 9806f97ff0aSJeremy L Thompson pub fn check(self) -> crate::Result<Self> { 9816f97ff0aSJeremy L Thompson self.op_core.check()?; 9826f97ff0aSJeremy L Thompson Ok(self) 9836f97ff0aSJeremy L Thompson } 9846f97ff0aSJeremy L Thompson 9853f2759cfSJeremy L Thompson /// Get the number of elements associated with an Operator 9863f2759cfSJeremy L Thompson /// 9873f2759cfSJeremy L Thompson /// 9883f2759cfSJeremy L Thompson /// ``` 9893f2759cfSJeremy L Thompson /// # use libceed::prelude::*; 9904d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 9913f2759cfSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 9923f2759cfSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 9933f2759cfSJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 9943f2759cfSJeremy L Thompson /// 9953f2759cfSJeremy L Thompson /// // Operator field arguments 9963f2759cfSJeremy L Thompson /// let ne = 3; 9973f2759cfSJeremy L Thompson /// let q = 4; 9983f2759cfSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 9993f2759cfSJeremy L Thompson /// for i in 0..ne { 10003f2759cfSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 10013f2759cfSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 10023f2759cfSJeremy L Thompson /// } 10033f2759cfSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 10043f2759cfSJeremy L Thompson /// 10053f2759cfSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 10063f2759cfSJeremy L Thompson /// 10073f2759cfSJeremy L Thompson /// // Operator field 10083f2759cfSJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 10093f2759cfSJeremy L Thompson /// 10103f2759cfSJeremy L Thompson /// // Check number of elements 10113f2759cfSJeremy L Thompson /// assert_eq!(op.num_elements(), ne, "Incorrect number of elements"); 10123f2759cfSJeremy L Thompson /// # Ok(()) 10133f2759cfSJeremy L Thompson /// # } 10143f2759cfSJeremy L Thompson /// ``` 10153f2759cfSJeremy L Thompson pub fn num_elements(&self) -> usize { 10163f2759cfSJeremy L Thompson let mut nelem = 0; 10173f2759cfSJeremy L Thompson unsafe { bind_ceed::CeedOperatorGetNumElements(self.op_core.ptr, &mut nelem) }; 10183f2759cfSJeremy L Thompson usize::try_from(nelem).unwrap() 10193f2759cfSJeremy L Thompson } 10203f2759cfSJeremy L Thompson 10213f2759cfSJeremy L Thompson /// Get the number of quadrature points associated with each element of 10223f2759cfSJeremy L Thompson /// an Operator 10233f2759cfSJeremy L Thompson /// 10243f2759cfSJeremy L Thompson /// 10253f2759cfSJeremy L Thompson /// ``` 10263f2759cfSJeremy L Thompson /// # use libceed::prelude::*; 10274d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 10283f2759cfSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 10293f2759cfSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 10303f2759cfSJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 10313f2759cfSJeremy L Thompson /// 10323f2759cfSJeremy L Thompson /// // Operator field arguments 10333f2759cfSJeremy L Thompson /// let ne = 3; 10343f2759cfSJeremy L Thompson /// let q = 4; 10353f2759cfSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 10363f2759cfSJeremy L Thompson /// for i in 0..ne { 10373f2759cfSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 10383f2759cfSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 10393f2759cfSJeremy L Thompson /// } 10403f2759cfSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 10413f2759cfSJeremy L Thompson /// 10423f2759cfSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 10433f2759cfSJeremy L Thompson /// 10443f2759cfSJeremy L Thompson /// // Operator field 10453f2759cfSJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 10463f2759cfSJeremy L Thompson /// 10473f2759cfSJeremy L Thompson /// // Check number of quadrature points 10483f2759cfSJeremy L Thompson /// assert_eq!( 10493f2759cfSJeremy L Thompson /// op.num_quadrature_points(), 10503f2759cfSJeremy L Thompson /// q, 10513f2759cfSJeremy L Thompson /// "Incorrect number of quadrature points" 10523f2759cfSJeremy L Thompson /// ); 10533f2759cfSJeremy L Thompson /// # Ok(()) 10543f2759cfSJeremy L Thompson /// # } 10553f2759cfSJeremy L Thompson /// ``` 10563f2759cfSJeremy L Thompson pub fn num_quadrature_points(&self) -> usize { 10573f2759cfSJeremy L Thompson let mut Q = 0; 10583f2759cfSJeremy L Thompson unsafe { bind_ceed::CeedOperatorGetNumQuadraturePoints(self.op_core.ptr, &mut Q) }; 10593f2759cfSJeremy L Thompson usize::try_from(Q).unwrap() 10603f2759cfSJeremy L Thompson } 10613f2759cfSJeremy L Thompson 10629df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 10639df49d7eSJed Brown /// 10649df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 10659df49d7eSJed Brown /// 10669df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 10679df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 10689df49d7eSJed Brown /// 10699df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 10709df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 10719df49d7eSJed Brown /// 10729df49d7eSJed Brown /// ``` 10739df49d7eSJed Brown /// # use libceed::prelude::*; 10744d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 10759df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 10769df49d7eSJed Brown /// let ne = 4; 10779df49d7eSJed Brown /// let p = 3; 10789df49d7eSJed Brown /// let q = 4; 10799df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 10809df49d7eSJed Brown /// 10819df49d7eSJed Brown /// // Vectors 1082c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1083c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 10849df49d7eSJed Brown /// qdata.set_value(0.0); 1085c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 10869df49d7eSJed Brown /// u.set_value(1.0); 1087c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 10889df49d7eSJed Brown /// v.set_value(0.0); 10899df49d7eSJed Brown /// 10909df49d7eSJed Brown /// // Restrictions 10919df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 10929df49d7eSJed Brown /// for i in 0..ne { 10939df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 10949df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 10959df49d7eSJed Brown /// } 1096c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 10979df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 10989df49d7eSJed Brown /// for i in 0..ne { 10999df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 11009df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 11019df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 11029df49d7eSJed Brown /// } 1103c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 11049df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1105c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 11069df49d7eSJed Brown /// 11079df49d7eSJed Brown /// // Bases 1108c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1109c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 11109df49d7eSJed Brown /// 11119df49d7eSJed Brown /// // Build quadrature data 1112c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1113c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1114c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1115c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1116356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1117c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 11189df49d7eSJed Brown /// 11199df49d7eSJed Brown /// // Mass operator 1120c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 11219df49d7eSJed Brown /// let op_mass = ceed 1122c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1123c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1124356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1125c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 11269df49d7eSJed Brown /// 11279df49d7eSJed Brown /// // Diagonal 1128c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 11299df49d7eSJed Brown /// diag.set_value(0.0); 1130c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_diagonal(&mut diag)?; 11319df49d7eSJed Brown /// 11329df49d7eSJed Brown /// // Manual diagonal computation 1133c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 11349c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 11359df49d7eSJed Brown /// for i in 0..ndofs { 11369df49d7eSJed Brown /// u.set_value(0.0); 11379df49d7eSJed Brown /// { 1138e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 11399df49d7eSJed Brown /// u_array[i] = 1.; 11409df49d7eSJed Brown /// } 11419df49d7eSJed Brown /// 1142c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 11439df49d7eSJed Brown /// 11449df49d7eSJed Brown /// { 11459c774eddSJeremy L Thompson /// let v_array = v.view()?; 1146e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 11479df49d7eSJed Brown /// true_array[i] = v_array[i]; 11489df49d7eSJed Brown /// } 11499df49d7eSJed Brown /// } 11509df49d7eSJed Brown /// 11519df49d7eSJed Brown /// // Check 1152e78171edSJeremy L Thompson /// diag.view()? 11539df49d7eSJed Brown /// .iter() 1154e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 11559df49d7eSJed Brown /// .for_each(|(computed, actual)| { 11569df49d7eSJed Brown /// assert!( 115780a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 11589df49d7eSJed Brown /// "Diagonal entry incorrect" 11599df49d7eSJed Brown /// ); 11609df49d7eSJed Brown /// }); 1161c68be7a2SJeremy L Thompson /// # Ok(()) 1162c68be7a2SJeremy L Thompson /// # } 11639df49d7eSJed Brown /// ``` 11649df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 11659df49d7eSJed Brown self.op_core.linear_assemble_diagonal(assembled) 11669df49d7eSJed Brown } 11679df49d7eSJed Brown 11689df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 11699df49d7eSJed Brown /// 11709df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 11719df49d7eSJed Brown /// 11729df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 11739df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 11749df49d7eSJed Brown /// 11759df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 11769df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 11779df49d7eSJed Brown /// 11789df49d7eSJed Brown /// 11799df49d7eSJed Brown /// ``` 11809df49d7eSJed Brown /// # use libceed::prelude::*; 11814d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 11829df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 11839df49d7eSJed Brown /// let ne = 4; 11849df49d7eSJed Brown /// let p = 3; 11859df49d7eSJed Brown /// let q = 4; 11869df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 11879df49d7eSJed Brown /// 11889df49d7eSJed Brown /// // Vectors 1189c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1190c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 11919df49d7eSJed Brown /// qdata.set_value(0.0); 1192c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 11939df49d7eSJed Brown /// u.set_value(1.0); 1194c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 11959df49d7eSJed Brown /// v.set_value(0.0); 11969df49d7eSJed Brown /// 11979df49d7eSJed Brown /// // Restrictions 11989df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 11999df49d7eSJed Brown /// for i in 0..ne { 12009df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 12019df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 12029df49d7eSJed Brown /// } 1203c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 12049df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 12059df49d7eSJed Brown /// for i in 0..ne { 12069df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 12079df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 12089df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 12099df49d7eSJed Brown /// } 1210c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 12119df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1212c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 12139df49d7eSJed Brown /// 12149df49d7eSJed Brown /// // Bases 1215c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1216c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 12179df49d7eSJed Brown /// 12189df49d7eSJed Brown /// // Build quadrature data 1219c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1220c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1221c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1222c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1223356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1224c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 12259df49d7eSJed Brown /// 12269df49d7eSJed Brown /// // Mass operator 1227c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 12289df49d7eSJed Brown /// let op_mass = ceed 1229c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1230c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1231356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1232c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 12339df49d7eSJed Brown /// 12349df49d7eSJed Brown /// // Diagonal 1235c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 12369df49d7eSJed Brown /// diag.set_value(1.0); 1237c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_diagonal(&mut diag)?; 12389df49d7eSJed Brown /// 12399df49d7eSJed Brown /// // Manual diagonal computation 1240c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 12419c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 12429df49d7eSJed Brown /// for i in 0..ndofs { 12439df49d7eSJed Brown /// u.set_value(0.0); 12449df49d7eSJed Brown /// { 1245e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 12469df49d7eSJed Brown /// u_array[i] = 1.; 12479df49d7eSJed Brown /// } 12489df49d7eSJed Brown /// 1249c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 12509df49d7eSJed Brown /// 12519df49d7eSJed Brown /// { 12529c774eddSJeremy L Thompson /// let v_array = v.view()?; 1253e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 12549df49d7eSJed Brown /// true_array[i] = v_array[i] + 1.0; 12559df49d7eSJed Brown /// } 12569df49d7eSJed Brown /// } 12579df49d7eSJed Brown /// 12589df49d7eSJed Brown /// // Check 1259e78171edSJeremy L Thompson /// diag.view()? 12609df49d7eSJed Brown /// .iter() 1261e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 12629df49d7eSJed Brown /// .for_each(|(computed, actual)| { 12639df49d7eSJed Brown /// assert!( 126480a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 12659df49d7eSJed Brown /// "Diagonal entry incorrect" 12669df49d7eSJed Brown /// ); 12679df49d7eSJed Brown /// }); 1268c68be7a2SJeremy L Thompson /// # Ok(()) 1269c68be7a2SJeremy L Thompson /// # } 12709df49d7eSJed Brown /// ``` 12719df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 12729df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 12739df49d7eSJed Brown } 12749df49d7eSJed Brown 12759df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 12769df49d7eSJed Brown /// 12779df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 12789df49d7eSJed Brown /// Operator. 12799df49d7eSJed Brown /// 12809df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 12819df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 12829df49d7eSJed Brown /// 12839df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 12849df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 12859df49d7eSJed Brown /// diagonal, provided in row-major form with an 12869df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 12879df49d7eSJed Brown /// this vector are derived from the active vector for 12889df49d7eSJed Brown /// the CeedOperator. The array has shape 12899df49d7eSJed Brown /// `[nodes, component out, component in]`. 12909df49d7eSJed Brown /// 12919df49d7eSJed Brown /// ``` 12929df49d7eSJed Brown /// # use libceed::prelude::*; 12934d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 12949df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 12959df49d7eSJed Brown /// let ne = 4; 12969df49d7eSJed Brown /// let p = 3; 12979df49d7eSJed Brown /// let q = 4; 12989df49d7eSJed Brown /// let ncomp = 2; 12999df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 13009df49d7eSJed Brown /// 13019df49d7eSJed Brown /// // Vectors 1302c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1303c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 13049df49d7eSJed Brown /// qdata.set_value(0.0); 1305c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 13069df49d7eSJed Brown /// u.set_value(1.0); 1307c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 13089df49d7eSJed Brown /// v.set_value(0.0); 13099df49d7eSJed Brown /// 13109df49d7eSJed Brown /// // Restrictions 13119df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 13129df49d7eSJed Brown /// for i in 0..ne { 13139df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 13149df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 13159df49d7eSJed Brown /// } 1316c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 13179df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 13189df49d7eSJed Brown /// for i in 0..ne { 13199df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 13209df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 13219df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 13229df49d7eSJed Brown /// } 1323c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 13249df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1325c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 13269df49d7eSJed Brown /// 13279df49d7eSJed Brown /// // Bases 1328c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1329c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 13309df49d7eSJed Brown /// 13319df49d7eSJed Brown /// // Build quadrature data 1332c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1333c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1334c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1335c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1336356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1337c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 13389df49d7eSJed Brown /// 13399df49d7eSJed Brown /// // Mass operator 13409df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 13419df49d7eSJed Brown /// // Number of quadrature points 13429df49d7eSJed Brown /// let q = qdata.len(); 13439df49d7eSJed Brown /// 13449df49d7eSJed Brown /// // Iterate over quadrature points 13459df49d7eSJed Brown /// for i in 0..q { 13469df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 13479df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 13489df49d7eSJed Brown /// } 13499df49d7eSJed Brown /// 13509df49d7eSJed Brown /// // Return clean error code 13519df49d7eSJed Brown /// 0 13529df49d7eSJed Brown /// }; 13539df49d7eSJed Brown /// 13549df49d7eSJed Brown /// let qf_mass = ceed 1355c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 1356c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 1357c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 1358c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 13599df49d7eSJed Brown /// 13609df49d7eSJed Brown /// let op_mass = ceed 1361c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1362c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1363356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1364c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 13659df49d7eSJed Brown /// 13669df49d7eSJed Brown /// // Diagonal 1367c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 13689df49d7eSJed Brown /// diag.set_value(0.0); 1369c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_point_block_diagonal(&mut diag)?; 13709df49d7eSJed Brown /// 13719df49d7eSJed Brown /// // Manual diagonal computation 1372c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 13739c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 13749df49d7eSJed Brown /// for i in 0..ndofs { 13759df49d7eSJed Brown /// for j in 0..ncomp { 13769df49d7eSJed Brown /// u.set_value(0.0); 13779df49d7eSJed Brown /// { 1378e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 13799df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 13809df49d7eSJed Brown /// } 13819df49d7eSJed Brown /// 1382c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 13839df49d7eSJed Brown /// 13849df49d7eSJed Brown /// { 13859c774eddSJeremy L Thompson /// let v_array = v.view()?; 1386e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 13879df49d7eSJed Brown /// for k in 0..ncomp { 13889df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 13899df49d7eSJed Brown /// } 13909df49d7eSJed Brown /// } 13919df49d7eSJed Brown /// } 13929df49d7eSJed Brown /// } 13939df49d7eSJed Brown /// 13949df49d7eSJed Brown /// // Check 1395e78171edSJeremy L Thompson /// diag.view()? 13969df49d7eSJed Brown /// .iter() 1397e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 13989df49d7eSJed Brown /// .for_each(|(computed, actual)| { 13999df49d7eSJed Brown /// assert!( 140080a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 14019df49d7eSJed Brown /// "Diagonal entry incorrect" 14029df49d7eSJed Brown /// ); 14039df49d7eSJed Brown /// }); 1404c68be7a2SJeremy L Thompson /// # Ok(()) 1405c68be7a2SJeremy L Thompson /// # } 14069df49d7eSJed Brown /// ``` 14079df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 14089df49d7eSJed Brown &self, 14099df49d7eSJed Brown assembled: &mut Vector, 14109df49d7eSJed Brown ) -> crate::Result<i32> { 14119df49d7eSJed Brown self.op_core.linear_assemble_point_block_diagonal(assembled) 14129df49d7eSJed Brown } 14139df49d7eSJed Brown 14149df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 14159df49d7eSJed Brown /// 14169df49d7eSJed Brown /// This sums into a Vector with the point block diagonal of a linear 14179df49d7eSJed Brown /// Operator. 14189df49d7eSJed Brown /// 14199df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 14209df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 14219df49d7eSJed Brown /// 14229df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 14239df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 14249df49d7eSJed Brown /// diagonal, provided in row-major form with an 14259df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 14269df49d7eSJed Brown /// this vector are derived from the active vector for 14279df49d7eSJed Brown /// the CeedOperator. The array has shape 14289df49d7eSJed Brown /// `[nodes, component out, component in]`. 14299df49d7eSJed Brown /// 14309df49d7eSJed Brown /// ``` 14319df49d7eSJed Brown /// # use libceed::prelude::*; 14324d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 14339df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 14349df49d7eSJed Brown /// let ne = 4; 14359df49d7eSJed Brown /// let p = 3; 14369df49d7eSJed Brown /// let q = 4; 14379df49d7eSJed Brown /// let ncomp = 2; 14389df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 14399df49d7eSJed Brown /// 14409df49d7eSJed Brown /// // Vectors 1441c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1442c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 14439df49d7eSJed Brown /// qdata.set_value(0.0); 1444c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 14459df49d7eSJed Brown /// u.set_value(1.0); 1446c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 14479df49d7eSJed Brown /// v.set_value(0.0); 14489df49d7eSJed Brown /// 14499df49d7eSJed Brown /// // Restrictions 14509df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 14519df49d7eSJed Brown /// for i in 0..ne { 14529df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 14539df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 14549df49d7eSJed Brown /// } 1455c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 14569df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 14579df49d7eSJed Brown /// for i in 0..ne { 14589df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 14599df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 14609df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 14619df49d7eSJed Brown /// } 1462c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 14639df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1464c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 14659df49d7eSJed Brown /// 14669df49d7eSJed Brown /// // Bases 1467c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1468c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 14699df49d7eSJed Brown /// 14709df49d7eSJed Brown /// // Build quadrature data 1471c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1472c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1473c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1474c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1475356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1476c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 14779df49d7eSJed Brown /// 14789df49d7eSJed Brown /// // Mass operator 14799df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 14809df49d7eSJed Brown /// // Number of quadrature points 14819df49d7eSJed Brown /// let q = qdata.len(); 14829df49d7eSJed Brown /// 14839df49d7eSJed Brown /// // Iterate over quadrature points 14849df49d7eSJed Brown /// for i in 0..q { 14859df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 14869df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 14879df49d7eSJed Brown /// } 14889df49d7eSJed Brown /// 14899df49d7eSJed Brown /// // Return clean error code 14909df49d7eSJed Brown /// 0 14919df49d7eSJed Brown /// }; 14929df49d7eSJed Brown /// 14939df49d7eSJed Brown /// let qf_mass = ceed 1494c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 1495c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 1496c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 1497c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 14989df49d7eSJed Brown /// 14999df49d7eSJed Brown /// let op_mass = ceed 1500c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1501c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1502356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1503c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 15049df49d7eSJed Brown /// 15059df49d7eSJed Brown /// // Diagonal 1506c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 15079df49d7eSJed Brown /// diag.set_value(1.0); 1508c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_point_block_diagonal(&mut diag)?; 15099df49d7eSJed Brown /// 15109df49d7eSJed Brown /// // Manual diagonal computation 1511c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 15129c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 15139df49d7eSJed Brown /// for i in 0..ndofs { 15149df49d7eSJed Brown /// for j in 0..ncomp { 15159df49d7eSJed Brown /// u.set_value(0.0); 15169df49d7eSJed Brown /// { 1517e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 15189df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 15199df49d7eSJed Brown /// } 15209df49d7eSJed Brown /// 1521c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 15229df49d7eSJed Brown /// 15239df49d7eSJed Brown /// { 15249c774eddSJeremy L Thompson /// let v_array = v.view()?; 1525e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 15269df49d7eSJed Brown /// for k in 0..ncomp { 15279df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 15289df49d7eSJed Brown /// } 15299df49d7eSJed Brown /// } 15309df49d7eSJed Brown /// } 15319df49d7eSJed Brown /// } 15329df49d7eSJed Brown /// 15339df49d7eSJed Brown /// // Check 1534e78171edSJeremy L Thompson /// diag.view()? 15359df49d7eSJed Brown /// .iter() 1536e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 15379df49d7eSJed Brown /// .for_each(|(computed, actual)| { 15389df49d7eSJed Brown /// assert!( 153980a9ef05SNatalie Beams /// (*computed - 1.0 - *actual).abs() < 10.0 * libceed::EPSILON, 15409df49d7eSJed Brown /// "Diagonal entry incorrect" 15419df49d7eSJed Brown /// ); 15429df49d7eSJed Brown /// }); 1543c68be7a2SJeremy L Thompson /// # Ok(()) 1544c68be7a2SJeremy L Thompson /// # } 15459df49d7eSJed Brown /// ``` 15469df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 15479df49d7eSJed Brown &self, 15489df49d7eSJed Brown assembled: &mut Vector, 15499df49d7eSJed Brown ) -> crate::Result<i32> { 15509df49d7eSJed Brown self.op_core 15519df49d7eSJed Brown .linear_assemble_add_point_block_diagonal(assembled) 15529df49d7eSJed Brown } 15539df49d7eSJed Brown 15549df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 15559df49d7eSJed Brown /// given Operator, creating the prolongation basis from the fine and 15569df49d7eSJed Brown /// coarse grid interpolation 15579df49d7eSJed Brown /// 15589df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 15599df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 15609df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 15619df49d7eSJed Brown /// 15629df49d7eSJed Brown /// ``` 15639df49d7eSJed Brown /// # use libceed::prelude::*; 15644d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 15659df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 15669df49d7eSJed Brown /// let ne = 15; 15679df49d7eSJed Brown /// let p_coarse = 3; 15689df49d7eSJed Brown /// let p_fine = 5; 15699df49d7eSJed Brown /// let q = 6; 15709df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 15719df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 15729df49d7eSJed Brown /// 15739df49d7eSJed Brown /// // Vectors 15749df49d7eSJed Brown /// let x_array = (0..ne + 1) 157580a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 157680a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1577c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1578c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 15799df49d7eSJed Brown /// qdata.set_value(0.0); 1580c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 15819df49d7eSJed Brown /// u_coarse.set_value(1.0); 1582c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 15839df49d7eSJed Brown /// u_fine.set_value(1.0); 1584c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 15859df49d7eSJed Brown /// v_coarse.set_value(0.0); 1586c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 15879df49d7eSJed Brown /// v_fine.set_value(0.0); 1588c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 15899df49d7eSJed Brown /// multiplicity.set_value(1.0); 15909df49d7eSJed Brown /// 15919df49d7eSJed Brown /// // Restrictions 15929df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1593c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 15949df49d7eSJed Brown /// 15959df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 15969df49d7eSJed Brown /// for i in 0..ne { 15979df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 15989df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 15999df49d7eSJed Brown /// } 1600c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 16019df49d7eSJed Brown /// 16029df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 16039df49d7eSJed Brown /// for i in 0..ne { 16049df49d7eSJed Brown /// for j in 0..p_coarse { 16059df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 16069df49d7eSJed Brown /// } 16079df49d7eSJed Brown /// } 1608c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 16099df49d7eSJed Brown /// ne, 16109df49d7eSJed Brown /// p_coarse, 16119df49d7eSJed Brown /// 1, 16129df49d7eSJed Brown /// 1, 16139df49d7eSJed Brown /// ndofs_coarse, 16149df49d7eSJed Brown /// MemType::Host, 16159df49d7eSJed Brown /// &indu_coarse, 1616c68be7a2SJeremy L Thompson /// )?; 16179df49d7eSJed Brown /// 16189df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 16199df49d7eSJed Brown /// for i in 0..ne { 16209df49d7eSJed Brown /// for j in 0..p_fine { 16219df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 16229df49d7eSJed Brown /// } 16239df49d7eSJed Brown /// } 1624c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 16259df49d7eSJed Brown /// 16269df49d7eSJed Brown /// // Bases 1627c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1628c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1629c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 16309df49d7eSJed Brown /// 16319df49d7eSJed Brown /// // Build quadrature data 1632c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1633c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1634c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1635c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1636356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1637c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 16389df49d7eSJed Brown /// 16399df49d7eSJed Brown /// // Mass operator 1640c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 16419df49d7eSJed Brown /// let op_mass_fine = ceed 1642c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1643c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1644356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1645c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 16469df49d7eSJed Brown /// 16479df49d7eSJed Brown /// // Multigrid setup 1648c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = 1649c68be7a2SJeremy L Thompson /// op_mass_fine.create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)?; 16509df49d7eSJed Brown /// 16519df49d7eSJed Brown /// // Coarse problem 16529df49d7eSJed Brown /// u_coarse.set_value(1.0); 1653c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 16549df49d7eSJed Brown /// 16559df49d7eSJed Brown /// // Check 1656e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 16579df49d7eSJed Brown /// assert!( 165880a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 16599df49d7eSJed Brown /// "Incorrect interval length computed" 16609df49d7eSJed Brown /// ); 16619df49d7eSJed Brown /// 16629df49d7eSJed Brown /// // Prolong 1663c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 16649df49d7eSJed Brown /// 16659df49d7eSJed Brown /// // Fine problem 1666c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 16679df49d7eSJed Brown /// 16689df49d7eSJed Brown /// // Check 1669e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 16709df49d7eSJed Brown /// assert!( 1671392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 16729df49d7eSJed Brown /// "Incorrect interval length computed" 16739df49d7eSJed Brown /// ); 16749df49d7eSJed Brown /// 16759df49d7eSJed Brown /// // Restrict 1676c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 16779df49d7eSJed Brown /// 16789df49d7eSJed Brown /// // Check 1679e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 16809df49d7eSJed Brown /// assert!( 1681392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 16829df49d7eSJed Brown /// "Incorrect interval length computed" 16839df49d7eSJed Brown /// ); 1684c68be7a2SJeremy L Thompson /// # Ok(()) 1685c68be7a2SJeremy L Thompson /// # } 16869df49d7eSJed Brown /// ``` 1687594ef120SJeremy L Thompson pub fn create_multigrid_level<'b>( 16889df49d7eSJed Brown &self, 16899df49d7eSJed Brown p_mult_fine: &Vector, 16909df49d7eSJed Brown rstr_coarse: &ElemRestriction, 16919df49d7eSJed Brown basis_coarse: &Basis, 1692594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 16939df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 16949df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 16959df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 16969df49d7eSJed Brown let ierr = unsafe { 16979df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreate( 16989df49d7eSJed Brown self.op_core.ptr, 16999df49d7eSJed Brown p_mult_fine.ptr, 17009df49d7eSJed Brown rstr_coarse.ptr, 17019df49d7eSJed Brown basis_coarse.ptr, 17029df49d7eSJed Brown &mut ptr_coarse, 17039df49d7eSJed Brown &mut ptr_prolong, 17049df49d7eSJed Brown &mut ptr_restrict, 17059df49d7eSJed Brown ) 17069df49d7eSJed Brown }; 17071142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 17081142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 17091142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 17101142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 17119df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 17129df49d7eSJed Brown } 17139df49d7eSJed Brown 17149df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 17159df49d7eSJed Brown /// given Operator with a tensor basis for the active basis 17169df49d7eSJed Brown /// 17179df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 17189df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 17199df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 17209df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 17219df49d7eSJed Brown /// 17229df49d7eSJed Brown /// ``` 17239df49d7eSJed Brown /// # use libceed::prelude::*; 17244d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 17259df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 17269df49d7eSJed Brown /// let ne = 15; 17279df49d7eSJed Brown /// let p_coarse = 3; 17289df49d7eSJed Brown /// let p_fine = 5; 17299df49d7eSJed Brown /// let q = 6; 17309df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 17319df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 17329df49d7eSJed Brown /// 17339df49d7eSJed Brown /// // Vectors 17349df49d7eSJed Brown /// let x_array = (0..ne + 1) 173580a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 173680a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1737c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1738c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 17399df49d7eSJed Brown /// qdata.set_value(0.0); 1740c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 17419df49d7eSJed Brown /// u_coarse.set_value(1.0); 1742c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 17439df49d7eSJed Brown /// u_fine.set_value(1.0); 1744c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 17459df49d7eSJed Brown /// v_coarse.set_value(0.0); 1746c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 17479df49d7eSJed Brown /// v_fine.set_value(0.0); 1748c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 17499df49d7eSJed Brown /// multiplicity.set_value(1.0); 17509df49d7eSJed Brown /// 17519df49d7eSJed Brown /// // Restrictions 17529df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1753c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 17549df49d7eSJed Brown /// 17559df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 17569df49d7eSJed Brown /// for i in 0..ne { 17579df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 17589df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 17599df49d7eSJed Brown /// } 1760c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 17619df49d7eSJed Brown /// 17629df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 17639df49d7eSJed Brown /// for i in 0..ne { 17649df49d7eSJed Brown /// for j in 0..p_coarse { 17659df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 17669df49d7eSJed Brown /// } 17679df49d7eSJed Brown /// } 1768c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 17699df49d7eSJed Brown /// ne, 17709df49d7eSJed Brown /// p_coarse, 17719df49d7eSJed Brown /// 1, 17729df49d7eSJed Brown /// 1, 17739df49d7eSJed Brown /// ndofs_coarse, 17749df49d7eSJed Brown /// MemType::Host, 17759df49d7eSJed Brown /// &indu_coarse, 1776c68be7a2SJeremy L Thompson /// )?; 17779df49d7eSJed Brown /// 17789df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 17799df49d7eSJed Brown /// for i in 0..ne { 17809df49d7eSJed Brown /// for j in 0..p_fine { 17819df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 17829df49d7eSJed Brown /// } 17839df49d7eSJed Brown /// } 1784c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 17859df49d7eSJed Brown /// 17869df49d7eSJed Brown /// // Bases 1787c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1788c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1789c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 17909df49d7eSJed Brown /// 17919df49d7eSJed Brown /// // Build quadrature data 1792c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1793c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1794c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1795c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1796356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1797c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 17989df49d7eSJed Brown /// 17999df49d7eSJed Brown /// // Mass operator 1800c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 18019df49d7eSJed Brown /// let op_mass_fine = ceed 1802c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1803c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1804356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1805c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 18069df49d7eSJed Brown /// 18079df49d7eSJed Brown /// // Multigrid setup 180880a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 18099df49d7eSJed Brown /// { 1810c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 1811c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 1812c68be7a2SJeremy L Thompson /// let basis_c_to_f = 1813c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 18149df49d7eSJed Brown /// for i in 0..p_coarse { 18159df49d7eSJed Brown /// coarse.set_value(0.0); 18169df49d7eSJed Brown /// { 1817e78171edSJeremy L Thompson /// let mut array = coarse.view_mut()?; 18189df49d7eSJed Brown /// array[i] = 1.; 18199df49d7eSJed Brown /// } 1820c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 18219df49d7eSJed Brown /// 1, 18229df49d7eSJed Brown /// TransposeMode::NoTranspose, 18239df49d7eSJed Brown /// EvalMode::Interp, 18249df49d7eSJed Brown /// &coarse, 18259df49d7eSJed Brown /// &mut fine, 1826c68be7a2SJeremy L Thompson /// )?; 1827e78171edSJeremy L Thompson /// let array = fine.view()?; 18289df49d7eSJed Brown /// for j in 0..p_fine { 18299df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 18309df49d7eSJed Brown /// } 18319df49d7eSJed Brown /// } 18329df49d7eSJed Brown /// } 1833c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_tensor_H1( 1834c68be7a2SJeremy L Thompson /// &multiplicity, 1835c68be7a2SJeremy L Thompson /// &ru_coarse, 1836c68be7a2SJeremy L Thompson /// &bu_coarse, 1837c68be7a2SJeremy L Thompson /// &interp_c_to_f, 1838c68be7a2SJeremy L Thompson /// )?; 18399df49d7eSJed Brown /// 18409df49d7eSJed Brown /// // Coarse problem 18419df49d7eSJed Brown /// u_coarse.set_value(1.0); 1842c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 18439df49d7eSJed Brown /// 18449df49d7eSJed Brown /// // Check 1845e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 18469df49d7eSJed Brown /// assert!( 184780a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 18489df49d7eSJed Brown /// "Incorrect interval length computed" 18499df49d7eSJed Brown /// ); 18509df49d7eSJed Brown /// 18519df49d7eSJed Brown /// // Prolong 1852c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 18539df49d7eSJed Brown /// 18549df49d7eSJed Brown /// // Fine problem 1855c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 18569df49d7eSJed Brown /// 18579df49d7eSJed Brown /// // Check 1858e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 18599df49d7eSJed Brown /// assert!( 1860392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 18619df49d7eSJed Brown /// "Incorrect interval length computed" 18629df49d7eSJed Brown /// ); 18639df49d7eSJed Brown /// 18649df49d7eSJed Brown /// // Restrict 1865c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 18669df49d7eSJed Brown /// 18679df49d7eSJed Brown /// // Check 1868e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 18699df49d7eSJed Brown /// assert!( 1870392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 18719df49d7eSJed Brown /// "Incorrect interval length computed" 18729df49d7eSJed Brown /// ); 1873c68be7a2SJeremy L Thompson /// # Ok(()) 1874c68be7a2SJeremy L Thompson /// # } 18759df49d7eSJed Brown /// ``` 1876594ef120SJeremy L Thompson pub fn create_multigrid_level_tensor_H1<'b>( 18779df49d7eSJed Brown &self, 18789df49d7eSJed Brown p_mult_fine: &Vector, 18799df49d7eSJed Brown rstr_coarse: &ElemRestriction, 18809df49d7eSJed Brown basis_coarse: &Basis, 188180a9ef05SNatalie Beams interpCtoF: &Vec<Scalar>, 1882594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 18839df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 18849df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 18859df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 18869df49d7eSJed Brown let ierr = unsafe { 18879df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateTensorH1( 18889df49d7eSJed Brown self.op_core.ptr, 18899df49d7eSJed Brown p_mult_fine.ptr, 18909df49d7eSJed Brown rstr_coarse.ptr, 18919df49d7eSJed Brown basis_coarse.ptr, 18929df49d7eSJed Brown interpCtoF.as_ptr(), 18939df49d7eSJed Brown &mut ptr_coarse, 18949df49d7eSJed Brown &mut ptr_prolong, 18959df49d7eSJed Brown &mut ptr_restrict, 18969df49d7eSJed Brown ) 18979df49d7eSJed Brown }; 18981142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 18991142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 19001142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 19011142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 19029df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 19039df49d7eSJed Brown } 19049df49d7eSJed Brown 19059df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 19069df49d7eSJed Brown /// given Operator with a non-tensor basis for the active basis 19079df49d7eSJed Brown /// 19089df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 19099df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 19109df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 19119df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 19129df49d7eSJed Brown /// 19139df49d7eSJed Brown /// ``` 19149df49d7eSJed Brown /// # use libceed::prelude::*; 19154d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 19169df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 19179df49d7eSJed Brown /// let ne = 15; 19189df49d7eSJed Brown /// let p_coarse = 3; 19199df49d7eSJed Brown /// let p_fine = 5; 19209df49d7eSJed Brown /// let q = 6; 19219df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 19229df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 19239df49d7eSJed Brown /// 19249df49d7eSJed Brown /// // Vectors 19259df49d7eSJed Brown /// let x_array = (0..ne + 1) 192680a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 192780a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1928c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1929c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 19309df49d7eSJed Brown /// qdata.set_value(0.0); 1931c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 19329df49d7eSJed Brown /// u_coarse.set_value(1.0); 1933c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 19349df49d7eSJed Brown /// u_fine.set_value(1.0); 1935c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 19369df49d7eSJed Brown /// v_coarse.set_value(0.0); 1937c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 19389df49d7eSJed Brown /// v_fine.set_value(0.0); 1939c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 19409df49d7eSJed Brown /// multiplicity.set_value(1.0); 19419df49d7eSJed Brown /// 19429df49d7eSJed Brown /// // Restrictions 19439df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1944c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 19459df49d7eSJed Brown /// 19469df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 19479df49d7eSJed Brown /// for i in 0..ne { 19489df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 19499df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 19509df49d7eSJed Brown /// } 1951c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 19529df49d7eSJed Brown /// 19539df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 19549df49d7eSJed Brown /// for i in 0..ne { 19559df49d7eSJed Brown /// for j in 0..p_coarse { 19569df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 19579df49d7eSJed Brown /// } 19589df49d7eSJed Brown /// } 1959c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 19609df49d7eSJed Brown /// ne, 19619df49d7eSJed Brown /// p_coarse, 19629df49d7eSJed Brown /// 1, 19639df49d7eSJed Brown /// 1, 19649df49d7eSJed Brown /// ndofs_coarse, 19659df49d7eSJed Brown /// MemType::Host, 19669df49d7eSJed Brown /// &indu_coarse, 1967c68be7a2SJeremy L Thompson /// )?; 19689df49d7eSJed Brown /// 19699df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 19709df49d7eSJed Brown /// for i in 0..ne { 19719df49d7eSJed Brown /// for j in 0..p_fine { 19729df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 19739df49d7eSJed Brown /// } 19749df49d7eSJed Brown /// } 1975c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 19769df49d7eSJed Brown /// 19779df49d7eSJed Brown /// // Bases 1978c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1979c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1980c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 19819df49d7eSJed Brown /// 19829df49d7eSJed Brown /// // Build quadrature data 1983c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1984c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1985c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1986c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1987356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 1988c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 19899df49d7eSJed Brown /// 19909df49d7eSJed Brown /// // Mass operator 1991c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 19929df49d7eSJed Brown /// let op_mass_fine = ceed 1993c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1994c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1995356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata)? 1996c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 19979df49d7eSJed Brown /// 19989df49d7eSJed Brown /// // Multigrid setup 199980a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 20009df49d7eSJed Brown /// { 2001c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 2002c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 2003c68be7a2SJeremy L Thompson /// let basis_c_to_f = 2004c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 20059df49d7eSJed Brown /// for i in 0..p_coarse { 20069df49d7eSJed Brown /// coarse.set_value(0.0); 20079df49d7eSJed Brown /// { 2008e78171edSJeremy L Thompson /// let mut array = coarse.view_mut()?; 20099df49d7eSJed Brown /// array[i] = 1.; 20109df49d7eSJed Brown /// } 2011c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 20129df49d7eSJed Brown /// 1, 20139df49d7eSJed Brown /// TransposeMode::NoTranspose, 20149df49d7eSJed Brown /// EvalMode::Interp, 20159df49d7eSJed Brown /// &coarse, 20169df49d7eSJed Brown /// &mut fine, 2017c68be7a2SJeremy L Thompson /// )?; 2018e78171edSJeremy L Thompson /// let array = fine.view()?; 20199df49d7eSJed Brown /// for j in 0..p_fine { 20209df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 20219df49d7eSJed Brown /// } 20229df49d7eSJed Brown /// } 20239df49d7eSJed Brown /// } 2024c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_H1( 2025c68be7a2SJeremy L Thompson /// &multiplicity, 2026c68be7a2SJeremy L Thompson /// &ru_coarse, 2027c68be7a2SJeremy L Thompson /// &bu_coarse, 2028c68be7a2SJeremy L Thompson /// &interp_c_to_f, 2029c68be7a2SJeremy L Thompson /// )?; 20309df49d7eSJed Brown /// 20319df49d7eSJed Brown /// // Coarse problem 20329df49d7eSJed Brown /// u_coarse.set_value(1.0); 2033c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 20349df49d7eSJed Brown /// 20359df49d7eSJed Brown /// // Check 2036e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 20379df49d7eSJed Brown /// assert!( 203880a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 20399df49d7eSJed Brown /// "Incorrect interval length computed" 20409df49d7eSJed Brown /// ); 20419df49d7eSJed Brown /// 20429df49d7eSJed Brown /// // Prolong 2043c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 20449df49d7eSJed Brown /// 20459df49d7eSJed Brown /// // Fine problem 2046c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 20479df49d7eSJed Brown /// 20489df49d7eSJed Brown /// // Check 2049e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 20509df49d7eSJed Brown /// assert!( 2051392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 20529df49d7eSJed Brown /// "Incorrect interval length computed" 20539df49d7eSJed Brown /// ); 20549df49d7eSJed Brown /// 20559df49d7eSJed Brown /// // Restrict 2056c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 20579df49d7eSJed Brown /// 20589df49d7eSJed Brown /// // Check 2059e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 20609df49d7eSJed Brown /// assert!( 2061392d940cSJeremy L Thompson /// (sum - 2.0).abs() < 200.0 * libceed::EPSILON, 20629df49d7eSJed Brown /// "Incorrect interval length computed" 20639df49d7eSJed Brown /// ); 2064c68be7a2SJeremy L Thompson /// # Ok(()) 2065c68be7a2SJeremy L Thompson /// # } 20669df49d7eSJed Brown /// ``` 2067594ef120SJeremy L Thompson pub fn create_multigrid_level_H1<'b>( 20689df49d7eSJed Brown &self, 20699df49d7eSJed Brown p_mult_fine: &Vector, 20709df49d7eSJed Brown rstr_coarse: &ElemRestriction, 20719df49d7eSJed Brown basis_coarse: &Basis, 207280a9ef05SNatalie Beams interpCtoF: &[Scalar], 2073594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 20749df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 20759df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 20769df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 20779df49d7eSJed Brown let ierr = unsafe { 20789df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateH1( 20799df49d7eSJed Brown self.op_core.ptr, 20809df49d7eSJed Brown p_mult_fine.ptr, 20819df49d7eSJed Brown rstr_coarse.ptr, 20829df49d7eSJed Brown basis_coarse.ptr, 20839df49d7eSJed Brown interpCtoF.as_ptr(), 20849df49d7eSJed Brown &mut ptr_coarse, 20859df49d7eSJed Brown &mut ptr_prolong, 20869df49d7eSJed Brown &mut ptr_restrict, 20879df49d7eSJed Brown ) 20889df49d7eSJed Brown }; 20891142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 20901142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 20911142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 20921142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 20939df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 20949df49d7eSJed Brown } 20959df49d7eSJed Brown } 20969df49d7eSJed Brown 20979df49d7eSJed Brown // ----------------------------------------------------------------------------- 20989df49d7eSJed Brown // Composite Operator 20999df49d7eSJed Brown // ----------------------------------------------------------------------------- 21009df49d7eSJed Brown impl<'a> CompositeOperator<'a> { 21019df49d7eSJed Brown // Constructor 2102594ef120SJeremy L Thompson pub fn create(ceed: &crate::Ceed) -> crate::Result<Self> { 21039df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 21049df49d7eSJed Brown let ierr = unsafe { bind_ceed::CeedCompositeOperatorCreate(ceed.ptr, &mut ptr) }; 21059df49d7eSJed Brown ceed.check_error(ierr)?; 21069df49d7eSJed Brown Ok(Self { 21071142270cSJeremy L Thompson op_core: OperatorCore { 21081142270cSJeremy L Thompson ptr, 21091142270cSJeremy L Thompson _lifeline: PhantomData, 21101142270cSJeremy L Thompson }, 21119df49d7eSJed Brown }) 21129df49d7eSJed Brown } 21139df49d7eSJed Brown 2114ea6b5821SJeremy L Thompson /// Set name for CompositeOperator printing 2115ea6b5821SJeremy L Thompson /// 2116ea6b5821SJeremy L Thompson /// * 'name' - Name to set 2117ea6b5821SJeremy L Thompson /// 2118ea6b5821SJeremy L Thompson /// ``` 2119ea6b5821SJeremy L Thompson /// # use libceed::prelude::*; 2120ea6b5821SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 2121ea6b5821SJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 2122ea6b5821SJeremy L Thompson /// 2123ea6b5821SJeremy L Thompson /// // Sub operator field arguments 2124ea6b5821SJeremy L Thompson /// let ne = 3; 2125ea6b5821SJeremy L Thompson /// let q = 4 as usize; 2126ea6b5821SJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 2127ea6b5821SJeremy L Thompson /// for i in 0..ne { 2128ea6b5821SJeremy L Thompson /// ind[2 * i + 0] = i as i32; 2129ea6b5821SJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 2130ea6b5821SJeremy L Thompson /// } 2131ea6b5821SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 2132ea6b5821SJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2133d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 2134ea6b5821SJeremy L Thompson /// 2135ea6b5821SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2136ea6b5821SJeremy L Thompson /// 2137ea6b5821SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?; 2138ea6b5821SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?; 2139ea6b5821SJeremy L Thompson /// 2140ea6b5821SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 2141ea6b5821SJeremy L Thompson /// let op_mass = ceed 2142ea6b5821SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2143ea6b5821SJeremy L Thompson /// .name("Mass term")? 2144ea6b5821SJeremy L Thompson /// .field("u", &r, &b, VectorOpt::Active)? 2145356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_mass)? 2146ea6b5821SJeremy L Thompson /// .field("v", &r, &b, VectorOpt::Active)?; 2147ea6b5821SJeremy L Thompson /// 2148ea6b5821SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 2149ea6b5821SJeremy L Thompson /// let op_diff = ceed 2150ea6b5821SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2151ea6b5821SJeremy L Thompson /// .name("Poisson term")? 2152ea6b5821SJeremy L Thompson /// .field("du", &r, &b, VectorOpt::Active)? 2153356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_diff)? 2154ea6b5821SJeremy L Thompson /// .field("dv", &r, &b, VectorOpt::Active)?; 2155ea6b5821SJeremy L Thompson /// 2156ea6b5821SJeremy L Thompson /// let op = ceed 2157ea6b5821SJeremy L Thompson /// .composite_operator()? 2158ea6b5821SJeremy L Thompson /// .name("Screened Poisson")? 2159ea6b5821SJeremy L Thompson /// .sub_operator(&op_mass)? 2160ea6b5821SJeremy L Thompson /// .sub_operator(&op_diff)?; 2161ea6b5821SJeremy L Thompson /// # Ok(()) 2162ea6b5821SJeremy L Thompson /// # } 2163ea6b5821SJeremy L Thompson /// ``` 2164ea6b5821SJeremy L Thompson #[allow(unused_mut)] 2165ea6b5821SJeremy L Thompson pub fn name(mut self, name: &str) -> crate::Result<Self> { 2166ea6b5821SJeremy L Thompson self.op_core.name(name)?; 2167ea6b5821SJeremy L Thompson Ok(self) 2168ea6b5821SJeremy L Thompson } 2169ea6b5821SJeremy L Thompson 21709df49d7eSJed Brown /// Apply Operator to a vector 21719df49d7eSJed Brown /// 2172ea6b5821SJeremy L Thompson /// * `input` - Inpuht Vector 21739df49d7eSJed Brown /// * `output` - Output Vector 21749df49d7eSJed Brown /// 21759df49d7eSJed Brown /// ``` 21769df49d7eSJed Brown /// # use libceed::prelude::*; 21774d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 21789df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 21799df49d7eSJed Brown /// let ne = 4; 21809df49d7eSJed Brown /// let p = 3; 21819df49d7eSJed Brown /// let q = 4; 21829df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 21839df49d7eSJed Brown /// 21849df49d7eSJed Brown /// // Vectors 2185c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 2186c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 21879df49d7eSJed Brown /// qdata_mass.set_value(0.0); 2188c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 21899df49d7eSJed Brown /// qdata_diff.set_value(0.0); 2190c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 21919df49d7eSJed Brown /// u.set_value(1.0); 2192c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 21939df49d7eSJed Brown /// v.set_value(0.0); 21949df49d7eSJed Brown /// 21959df49d7eSJed Brown /// // Restrictions 21969df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 21979df49d7eSJed Brown /// for i in 0..ne { 21989df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 21999df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 22009df49d7eSJed Brown /// } 2201c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 22029df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 22039df49d7eSJed Brown /// for i in 0..ne { 22049df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 22059df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 22069df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 22079df49d7eSJed Brown /// } 2208c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 22099df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2210c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 22119df49d7eSJed Brown /// 22129df49d7eSJed Brown /// // Bases 2213c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2214c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 22159df49d7eSJed Brown /// 22169df49d7eSJed Brown /// // Build quadrature data 2217c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 2218c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 2219c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2220c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2221356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 2222c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 22239df49d7eSJed Brown /// 2224c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 2225c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 2226c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2227c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2228356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 2229c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 22309df49d7eSJed Brown /// 22319df49d7eSJed Brown /// // Application operator 2232c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 22339df49d7eSJed Brown /// let op_mass = ceed 2234c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2235c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 2236356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_mass)? 2237c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 22389df49d7eSJed Brown /// 2239c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 22409df49d7eSJed Brown /// let op_diff = ceed 2241c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2242c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 2243356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_diff)? 2244c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 22459df49d7eSJed Brown /// 22469df49d7eSJed Brown /// let op_composite = ceed 2247c68be7a2SJeremy L Thompson /// .composite_operator()? 2248c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 2249c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 22509df49d7eSJed Brown /// 22519df49d7eSJed Brown /// v.set_value(0.0); 2252c68be7a2SJeremy L Thompson /// op_composite.apply(&u, &mut v)?; 22539df49d7eSJed Brown /// 22549df49d7eSJed Brown /// // Check 2255e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 22569df49d7eSJed Brown /// assert!( 225780a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 22589df49d7eSJed Brown /// "Incorrect interval length computed" 22599df49d7eSJed Brown /// ); 2260c68be7a2SJeremy L Thompson /// # Ok(()) 2261c68be7a2SJeremy L Thompson /// # } 22629df49d7eSJed Brown /// ``` 22639df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 22649df49d7eSJed Brown self.op_core.apply(input, output) 22659df49d7eSJed Brown } 22669df49d7eSJed Brown 22679df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 22689df49d7eSJed Brown /// 22699df49d7eSJed Brown /// * `input` - Input Vector 22709df49d7eSJed Brown /// * `output` - Output Vector 22719df49d7eSJed Brown /// 22729df49d7eSJed Brown /// ``` 22739df49d7eSJed Brown /// # use libceed::prelude::*; 22744d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 22759df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 22769df49d7eSJed Brown /// let ne = 4; 22779df49d7eSJed Brown /// let p = 3; 22789df49d7eSJed Brown /// let q = 4; 22799df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 22809df49d7eSJed Brown /// 22819df49d7eSJed Brown /// // Vectors 2282c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 2283c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 22849df49d7eSJed Brown /// qdata_mass.set_value(0.0); 2285c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 22869df49d7eSJed Brown /// qdata_diff.set_value(0.0); 2287c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 22889df49d7eSJed Brown /// u.set_value(1.0); 2289c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 22909df49d7eSJed Brown /// v.set_value(0.0); 22919df49d7eSJed Brown /// 22929df49d7eSJed Brown /// // Restrictions 22939df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 22949df49d7eSJed Brown /// for i in 0..ne { 22959df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 22969df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 22979df49d7eSJed Brown /// } 2298c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 22999df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 23009df49d7eSJed Brown /// for i in 0..ne { 23019df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 23029df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 23039df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 23049df49d7eSJed Brown /// } 2305c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 23069df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2307c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 23089df49d7eSJed Brown /// 23099df49d7eSJed Brown /// // Bases 2310c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2311c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 23129df49d7eSJed Brown /// 23139df49d7eSJed Brown /// // Build quadrature data 2314c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 2315c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 2316c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2317c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2318356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 2319c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 23209df49d7eSJed Brown /// 2321c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 2322c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 2323c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2324c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2325356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)? 2326c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 23279df49d7eSJed Brown /// 23289df49d7eSJed Brown /// // Application operator 2329c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 23309df49d7eSJed Brown /// let op_mass = ceed 2331c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2332c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 2333356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_mass)? 2334c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 23359df49d7eSJed Brown /// 2336c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 23379df49d7eSJed Brown /// let op_diff = ceed 2338c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2339c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 2340356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, &qdata_diff)? 2341c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 23429df49d7eSJed Brown /// 23439df49d7eSJed Brown /// let op_composite = ceed 2344c68be7a2SJeremy L Thompson /// .composite_operator()? 2345c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 2346c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 23479df49d7eSJed Brown /// 23489df49d7eSJed Brown /// v.set_value(1.0); 2349c68be7a2SJeremy L Thompson /// op_composite.apply_add(&u, &mut v)?; 23509df49d7eSJed Brown /// 23519df49d7eSJed Brown /// // Check 2352e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 23539df49d7eSJed Brown /// assert!( 235480a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 23559df49d7eSJed Brown /// "Incorrect interval length computed" 23569df49d7eSJed Brown /// ); 2357c68be7a2SJeremy L Thompson /// # Ok(()) 2358c68be7a2SJeremy L Thompson /// # } 23599df49d7eSJed Brown /// ``` 23609df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 23619df49d7eSJed Brown self.op_core.apply_add(input, output) 23629df49d7eSJed Brown } 23639df49d7eSJed Brown 23649df49d7eSJed Brown /// Add a sub-Operator to a Composite Operator 23659df49d7eSJed Brown /// 23669df49d7eSJed Brown /// * `subop` - Sub-Operator 23679df49d7eSJed Brown /// 23689df49d7eSJed Brown /// ``` 23699df49d7eSJed Brown /// # use libceed::prelude::*; 23704d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 23719df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 2372c68be7a2SJeremy L Thompson /// let mut op = ceed.composite_operator()?; 23739df49d7eSJed Brown /// 2374c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 2375c68be7a2SJeremy L Thompson /// let op_mass = ceed.operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?; 2376c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_mass)?; 23779df49d7eSJed Brown /// 2378c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 2379c68be7a2SJeremy L Thompson /// let op_diff = ceed.operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?; 2380c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_diff)?; 2381c68be7a2SJeremy L Thompson /// # Ok(()) 2382c68be7a2SJeremy L Thompson /// # } 23839df49d7eSJed Brown /// ``` 23849df49d7eSJed Brown #[allow(unused_mut)] 23859df49d7eSJed Brown pub fn sub_operator(mut self, subop: &Operator) -> crate::Result<Self> { 23869df49d7eSJed Brown let ierr = 23879df49d7eSJed Brown unsafe { bind_ceed::CeedCompositeOperatorAddSub(self.op_core.ptr, subop.op_core.ptr) }; 23881142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 23899df49d7eSJed Brown Ok(self) 23909df49d7eSJed Brown } 23919df49d7eSJed Brown 23926f97ff0aSJeremy L Thompson /// Check if CompositeOperator is setup correctly 23936f97ff0aSJeremy L Thompson /// 23946f97ff0aSJeremy L Thompson /// ``` 23956f97ff0aSJeremy L Thompson /// # use libceed::prelude::*; 23966f97ff0aSJeremy L Thompson /// # fn main() -> libceed::Result<()> { 23976f97ff0aSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 23986f97ff0aSJeremy L Thompson /// let ne = 4; 23996f97ff0aSJeremy L Thompson /// let p = 3; 24006f97ff0aSJeremy L Thompson /// let q = 4; 24016f97ff0aSJeremy L Thompson /// let ndofs = p * ne - ne + 1; 24026f97ff0aSJeremy L Thompson /// 24036f97ff0aSJeremy L Thompson /// // Restrictions 24046f97ff0aSJeremy L Thompson /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 24056f97ff0aSJeremy L Thompson /// for i in 0..ne { 24066f97ff0aSJeremy L Thompson /// indx[2 * i + 0] = i as i32; 24076f97ff0aSJeremy L Thompson /// indx[2 * i + 1] = (i + 1) as i32; 24086f97ff0aSJeremy L Thompson /// } 24096f97ff0aSJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 24106f97ff0aSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 24116f97ff0aSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 24126f97ff0aSJeremy L Thompson /// 24136f97ff0aSJeremy L Thompson /// // Bases 24146f97ff0aSJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 24156f97ff0aSJeremy L Thompson /// 24166f97ff0aSJeremy L Thompson /// // Build quadrature data 24176f97ff0aSJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 24186f97ff0aSJeremy L Thompson /// let op_build_mass = ceed 24196f97ff0aSJeremy L Thompson /// .operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 24206f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 24216f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2422356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 24236f97ff0aSJeremy L Thompson /// 24246f97ff0aSJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 24256f97ff0aSJeremy L Thompson /// let op_build_diff = ceed 24266f97ff0aSJeremy L Thompson /// .operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 24276f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 24286f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2429356036faSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?; 24306f97ff0aSJeremy L Thompson /// 24316f97ff0aSJeremy L Thompson /// let op_build = ceed 24326f97ff0aSJeremy L Thompson /// .composite_operator()? 24336f97ff0aSJeremy L Thompson /// .sub_operator(&op_build_mass)? 24346f97ff0aSJeremy L Thompson /// .sub_operator(&op_build_diff)?; 24356f97ff0aSJeremy L Thompson /// 24366f97ff0aSJeremy L Thompson /// // Check 24376f97ff0aSJeremy L Thompson /// assert!(op_build.check().is_ok(), "Operator setup incorrectly"); 24386f97ff0aSJeremy L Thompson /// # Ok(()) 24396f97ff0aSJeremy L Thompson /// # } 24406f97ff0aSJeremy L Thompson /// ``` 24416f97ff0aSJeremy L Thompson pub fn check(self) -> crate::Result<Self> { 24426f97ff0aSJeremy L Thompson self.op_core.check()?; 24436f97ff0aSJeremy L Thompson Ok(self) 24446f97ff0aSJeremy L Thompson } 24456f97ff0aSJeremy L Thompson 24469df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 24479df49d7eSJed Brown /// 24489df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 24499df49d7eSJed Brown /// 24509df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 24519df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 24529df49d7eSJed Brown /// 24539df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 24549df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 2455b748b478SJeremy L Thompson pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 24569df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 24579df49d7eSJed Brown } 24589df49d7eSJed Brown 24599df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 24609df49d7eSJed Brown /// 24619df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 24629df49d7eSJed Brown /// Operator. 24639df49d7eSJed Brown /// 24649df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 24659df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 24669df49d7eSJed Brown /// 24679df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 24689df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 24699df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 24709df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 24719df49d7eSJed Brown } 24729df49d7eSJed Brown 24739df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 24749df49d7eSJed Brown /// 24759df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 24769df49d7eSJed Brown /// 24779df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 24789df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 24799df49d7eSJed Brown /// 24809df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 24819df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 24829df49d7eSJed Brown /// diagonal, provided in row-major form with an 24839df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 24849df49d7eSJed Brown /// this vector are derived from the active vector for 24859df49d7eSJed Brown /// the CeedOperator. The array has shape 24869df49d7eSJed Brown /// `[nodes, component out, component in]`. 24879df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 24889df49d7eSJed Brown &self, 24899df49d7eSJed Brown assembled: &mut Vector, 24909df49d7eSJed Brown ) -> crate::Result<i32> { 24919df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 24929df49d7eSJed Brown } 24939df49d7eSJed Brown 24949df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 24959df49d7eSJed Brown /// 24969df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 24979df49d7eSJed Brown /// 24989df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 24999df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 25009df49d7eSJed Brown /// 25019df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 25029df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 25039df49d7eSJed Brown /// diagonal, provided in row-major form with an 25049df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 25059df49d7eSJed Brown /// this vector are derived from the active vector for 25069df49d7eSJed Brown /// the CeedOperator. The array has shape 25079df49d7eSJed Brown /// `[nodes, component out, component in]`. 25089df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 25099df49d7eSJed Brown &self, 25109df49d7eSJed Brown assembled: &mut Vector, 25119df49d7eSJed Brown ) -> crate::Result<i32> { 25129df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 25139df49d7eSJed Brown } 25149df49d7eSJed Brown } 25159df49d7eSJed Brown 25169df49d7eSJed Brown // ----------------------------------------------------------------------------- 2517