19df49d7eSJed Brown // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 29df49d7eSJed Brown // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 39df49d7eSJed Brown // reserved. See files LICENSE and NOTICE for details. 49df49d7eSJed Brown // 59df49d7eSJed Brown // This file is part of CEED, a collection of benchmarks, miniapps, software 69df49d7eSJed Brown // libraries and APIs for efficient high-order finite element and spectral 79df49d7eSJed Brown // element discretizations for exascale applications. For more information and 89df49d7eSJed Brown // source code availability see http://github.com/ceed. 99df49d7eSJed Brown // 109df49d7eSJed Brown // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 119df49d7eSJed Brown // a collaborative effort of two U.S. Department of Energy organizations (Office 129df49d7eSJed Brown // of Science and the National Nuclear Security Administration) responsible for 139df49d7eSJed Brown // the planning and preparation of a capable exascale ecosystem, including 149df49d7eSJed Brown // software, applications, hardware, advanced system engineering and early 159df49d7eSJed Brown // testbed platforms, in support of the nation's exascale computing imperative 169df49d7eSJed Brown 179df49d7eSJed Brown //! A Ceed Operator defines the finite/spectral element operator associated to a 189df49d7eSJed Brown //! Ceed QFunction. A Ceed Operator connects Ceed ElemRestrictions, 199df49d7eSJed Brown //! Ceed Bases, and Ceed QFunctions. 209df49d7eSJed Brown 219df49d7eSJed Brown use crate::prelude::*; 229df49d7eSJed Brown 239df49d7eSJed Brown // ----------------------------------------------------------------------------- 2408778c6fSJeremy L Thompson // CeedOperator Field context wrapper 2508778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 2608778c6fSJeremy L Thompson #[derive(Debug)] 2708778c6fSJeremy L Thompson pub struct OperatorField<'a> { 2808778c6fSJeremy L Thompson pub(crate) ptr: bind_ceed::CeedOperatorField, 2908778c6fSJeremy L Thompson _lifeline: PhantomData<&'a ()>, 3008778c6fSJeremy L Thompson } 3108778c6fSJeremy L Thompson 3208778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 3308778c6fSJeremy L Thompson // Implementations 3408778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 3508778c6fSJeremy L Thompson impl<'a> OperatorField<'a> { 3608778c6fSJeremy L Thompson /// Get the name of an OperatorField 3708778c6fSJeremy L Thompson /// 3808778c6fSJeremy L Thompson /// ``` 3908778c6fSJeremy L Thompson /// # use libceed::prelude::*; 40*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 4108778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 4208778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 4308778c6fSJeremy L Thompson /// 4408778c6fSJeremy L Thompson /// // Operator field arguments 4508778c6fSJeremy L Thompson /// let ne = 3; 4608778c6fSJeremy L Thompson /// let q = 4 as usize; 4708778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 4808778c6fSJeremy L Thompson /// for i in 0..ne { 4908778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 5008778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 5108778c6fSJeremy L Thompson /// } 5208778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 5308778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 5408778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 5508778c6fSJeremy L Thompson /// 5608778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 5708778c6fSJeremy L Thompson /// 5808778c6fSJeremy L Thompson /// // Operator fields 5908778c6fSJeremy L Thompson /// let op = ceed 6008778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 6108778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 6208778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 6308778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 6408778c6fSJeremy L Thompson /// 6508778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 6608778c6fSJeremy L Thompson /// 6708778c6fSJeremy L Thompson /// assert_eq!(inputs[0].name(), "dx", "Incorrect input name"); 6808778c6fSJeremy L Thompson /// assert_eq!(inputs[1].name(), "weights", "Incorrect input name"); 6908778c6fSJeremy L Thompson /// # Ok(()) 7008778c6fSJeremy L Thompson /// # } 7108778c6fSJeremy L Thompson /// ``` 7208778c6fSJeremy L Thompson pub fn name(&self) -> &str { 7308778c6fSJeremy L Thompson let mut name_ptr: *mut std::os::raw::c_char = std::ptr::null_mut(); 7408778c6fSJeremy L Thompson unsafe { 7508778c6fSJeremy L Thompson bind_ceed::CeedOperatorFieldGetName(self.ptr, &mut name_ptr); 7608778c6fSJeremy L Thompson } 7708778c6fSJeremy L Thompson unsafe { CStr::from_ptr(name_ptr) }.to_str().unwrap() 7808778c6fSJeremy L Thompson } 7908778c6fSJeremy L Thompson 8008778c6fSJeremy L Thompson /// Get the ElemRestriction of an OperatorField 8108778c6fSJeremy L Thompson /// 8208778c6fSJeremy L Thompson /// ``` 8308778c6fSJeremy L Thompson /// # use libceed::prelude::*; 84*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 8508778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 8608778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 8708778c6fSJeremy L Thompson /// 8808778c6fSJeremy L Thompson /// // Operator field arguments 8908778c6fSJeremy L Thompson /// let ne = 3; 9008778c6fSJeremy L Thompson /// let q = 4 as usize; 9108778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 9208778c6fSJeremy L Thompson /// for i in 0..ne { 9308778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 9408778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 9508778c6fSJeremy L Thompson /// } 9608778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 9708778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 9808778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 9908778c6fSJeremy L Thompson /// 10008778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 10108778c6fSJeremy L Thompson /// 10208778c6fSJeremy L Thompson /// // Operator fields 10308778c6fSJeremy L Thompson /// let op = ceed 10408778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 10508778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 10608778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 10708778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 10808778c6fSJeremy L Thompson /// 10908778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 11008778c6fSJeremy L Thompson /// 11108778c6fSJeremy L Thompson /// assert!( 11208778c6fSJeremy L Thompson /// inputs[0].elem_restriction().is_some(), 11308778c6fSJeremy L Thompson /// "Incorrect field ElemRestriction" 11408778c6fSJeremy L Thompson /// ); 11508778c6fSJeremy L Thompson /// if let ElemRestrictionOpt::Some(r) = inputs[0].elem_restriction() { 11608778c6fSJeremy L Thompson /// assert_eq!( 11708778c6fSJeremy L Thompson /// r.num_elements(), 11808778c6fSJeremy L Thompson /// ne, 11908778c6fSJeremy L Thompson /// "Incorrect field ElemRestriction number of elements" 12008778c6fSJeremy L Thompson /// ); 12108778c6fSJeremy L Thompson /// } 12208778c6fSJeremy L Thompson /// 12308778c6fSJeremy L Thompson /// assert!( 12408778c6fSJeremy L Thompson /// inputs[1].elem_restriction().is_none(), 12508778c6fSJeremy L Thompson /// "Incorrect field ElemRestriction" 12608778c6fSJeremy L Thompson /// ); 12708778c6fSJeremy L Thompson /// # Ok(()) 12808778c6fSJeremy L Thompson /// # } 12908778c6fSJeremy L Thompson /// ``` 13008778c6fSJeremy L Thompson pub fn elem_restriction(&self) -> ElemRestrictionOpt { 13108778c6fSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 13208778c6fSJeremy L Thompson unsafe { 13308778c6fSJeremy L Thompson bind_ceed::CeedOperatorFieldGetElemRestriction(self.ptr, &mut ptr); 13408778c6fSJeremy L Thompson } 13508778c6fSJeremy L Thompson if ptr == unsafe { bind_ceed::CEED_ELEMRESTRICTION_NONE } { 13608778c6fSJeremy L Thompson ElemRestrictionOpt::None 13708778c6fSJeremy L Thompson } else { 13808778c6fSJeremy L Thompson let slice = unsafe { 13908778c6fSJeremy L Thompson std::slice::from_raw_parts( 14008778c6fSJeremy L Thompson &ptr as *const bind_ceed::CeedElemRestriction as *const crate::ElemRestriction, 14108778c6fSJeremy L Thompson 1 as usize, 14208778c6fSJeremy L Thompson ) 14308778c6fSJeremy L Thompson }; 14408778c6fSJeremy L Thompson ElemRestrictionOpt::Some(&slice[0]) 14508778c6fSJeremy L Thompson } 14608778c6fSJeremy L Thompson } 14708778c6fSJeremy L Thompson 14808778c6fSJeremy L Thompson /// Get the Basis of an OperatorField 14908778c6fSJeremy L Thompson /// 15008778c6fSJeremy L Thompson /// ``` 15108778c6fSJeremy L Thompson /// # use libceed::prelude::*; 152*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 15308778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 15408778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 15508778c6fSJeremy L Thompson /// 15608778c6fSJeremy L Thompson /// // Operator field arguments 15708778c6fSJeremy L Thompson /// let ne = 3; 15808778c6fSJeremy L Thompson /// let q = 4 as usize; 15908778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 16008778c6fSJeremy L Thompson /// for i in 0..ne { 16108778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 16208778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 16308778c6fSJeremy L Thompson /// } 16408778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 16508778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 16608778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 16708778c6fSJeremy L Thompson /// 16808778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 16908778c6fSJeremy L Thompson /// 17008778c6fSJeremy L Thompson /// // Operator fields 17108778c6fSJeremy L Thompson /// let op = ceed 17208778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 17308778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 17408778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 17508778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 17608778c6fSJeremy L Thompson /// 17708778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 17808778c6fSJeremy L Thompson /// 17908778c6fSJeremy L Thompson /// assert!(inputs[0].basis().is_some(), "Incorrect field Basis"); 18008778c6fSJeremy L Thompson /// if let BasisOpt::Some(b) = inputs[0].basis() { 18108778c6fSJeremy L Thompson /// assert_eq!( 18208778c6fSJeremy L Thompson /// b.num_quadrature_points(), 18308778c6fSJeremy L Thompson /// q, 18408778c6fSJeremy L Thompson /// "Incorrect field Basis number of quadrature points" 18508778c6fSJeremy L Thompson /// ); 18608778c6fSJeremy L Thompson /// } 18708778c6fSJeremy L Thompson /// assert!(inputs[1].basis().is_some(), "Incorrect field Basis"); 18808778c6fSJeremy L Thompson /// if let BasisOpt::Some(b) = inputs[0].basis() { 18908778c6fSJeremy L Thompson /// assert_eq!( 19008778c6fSJeremy L Thompson /// b.num_quadrature_points(), 19108778c6fSJeremy L Thompson /// q, 19208778c6fSJeremy L Thompson /// "Incorrect field Basis number of quadrature points" 19308778c6fSJeremy L Thompson /// ); 19408778c6fSJeremy L Thompson /// } 19508778c6fSJeremy L Thompson /// 19608778c6fSJeremy L Thompson /// let outputs = op.outputs()?; 19708778c6fSJeremy L Thompson /// 19808778c6fSJeremy L Thompson /// assert!(outputs[0].basis().is_collocated(), "Incorrect field Basis"); 19908778c6fSJeremy L Thompson /// # Ok(()) 20008778c6fSJeremy L Thompson /// # } 20108778c6fSJeremy L Thompson /// ``` 20208778c6fSJeremy L Thompson pub fn basis(&self) -> BasisOpt { 20308778c6fSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 20408778c6fSJeremy L Thompson unsafe { 20508778c6fSJeremy L Thompson bind_ceed::CeedOperatorFieldGetBasis(self.ptr, &mut ptr); 20608778c6fSJeremy L Thompson } 20708778c6fSJeremy L Thompson if ptr == unsafe { bind_ceed::CEED_BASIS_COLLOCATED } { 20808778c6fSJeremy L Thompson BasisOpt::Collocated 20908778c6fSJeremy L Thompson } else { 21008778c6fSJeremy L Thompson let slice = unsafe { 21108778c6fSJeremy L Thompson std::slice::from_raw_parts( 21208778c6fSJeremy L Thompson &ptr as *const bind_ceed::CeedBasis as *const crate::Basis, 21308778c6fSJeremy L Thompson 1 as usize, 21408778c6fSJeremy L Thompson ) 21508778c6fSJeremy L Thompson }; 21608778c6fSJeremy L Thompson BasisOpt::Some(&slice[0]) 21708778c6fSJeremy L Thompson } 21808778c6fSJeremy L Thompson } 21908778c6fSJeremy L Thompson 22008778c6fSJeremy L Thompson /// Get the Vector of an OperatorField 22108778c6fSJeremy L Thompson /// 22208778c6fSJeremy L Thompson /// ``` 22308778c6fSJeremy L Thompson /// # use libceed::prelude::*; 224*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 22508778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 22608778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 22708778c6fSJeremy L Thompson /// 22808778c6fSJeremy L Thompson /// // Operator field arguments 22908778c6fSJeremy L Thompson /// let ne = 3; 23008778c6fSJeremy L Thompson /// let q = 4 as usize; 23108778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 23208778c6fSJeremy L Thompson /// for i in 0..ne { 23308778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 23408778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 23508778c6fSJeremy L Thompson /// } 23608778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 23708778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 23808778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 23908778c6fSJeremy L Thompson /// 24008778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 24108778c6fSJeremy L Thompson /// 24208778c6fSJeremy L Thompson /// // Operator fields 24308778c6fSJeremy L Thompson /// let op = ceed 24408778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 24508778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 24608778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 24708778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 24808778c6fSJeremy L Thompson /// 24908778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 25008778c6fSJeremy L Thompson /// 25108778c6fSJeremy L Thompson /// assert!(inputs[0].vector().is_active(), "Incorrect field Vector"); 25208778c6fSJeremy L Thompson /// assert!(inputs[1].vector().is_none(), "Incorrect field Vector"); 25308778c6fSJeremy L Thompson /// # Ok(()) 25408778c6fSJeremy L Thompson /// # } 25508778c6fSJeremy L Thompson /// ``` 25608778c6fSJeremy L Thompson pub fn vector(&self) -> VectorOpt { 25708778c6fSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 25808778c6fSJeremy L Thompson unsafe { 25908778c6fSJeremy L Thompson bind_ceed::CeedOperatorFieldGetVector(self.ptr, &mut ptr); 26008778c6fSJeremy L Thompson } 26108778c6fSJeremy L Thompson if ptr == unsafe { bind_ceed::CEED_VECTOR_ACTIVE } { 26208778c6fSJeremy L Thompson VectorOpt::Active 26308778c6fSJeremy L Thompson } else if ptr == unsafe { bind_ceed::CEED_VECTOR_NONE } { 26408778c6fSJeremy L Thompson VectorOpt::None 26508778c6fSJeremy L Thompson } else { 26608778c6fSJeremy L Thompson let slice = unsafe { 26708778c6fSJeremy L Thompson std::slice::from_raw_parts( 26808778c6fSJeremy L Thompson &ptr as *const bind_ceed::CeedVector as *const crate::Vector, 26908778c6fSJeremy L Thompson 1 as usize, 27008778c6fSJeremy L Thompson ) 27108778c6fSJeremy L Thompson }; 27208778c6fSJeremy L Thompson VectorOpt::Some(&slice[0]) 27308778c6fSJeremy L Thompson } 27408778c6fSJeremy L Thompson } 27508778c6fSJeremy L Thompson } 27608778c6fSJeremy L Thompson 27708778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 2789df49d7eSJed Brown // CeedOperator context wrapper 2799df49d7eSJed Brown // ----------------------------------------------------------------------------- 280c68be7a2SJeremy L Thompson #[derive(Debug)] 2819df49d7eSJed Brown pub(crate) struct OperatorCore<'a> { 2829df49d7eSJed Brown ptr: bind_ceed::CeedOperator, 2831142270cSJeremy L Thompson _lifeline: PhantomData<&'a ()>, 2849df49d7eSJed Brown } 2859df49d7eSJed Brown 286c68be7a2SJeremy L Thompson #[derive(Debug)] 2879df49d7eSJed Brown pub struct Operator<'a> { 2889df49d7eSJed Brown op_core: OperatorCore<'a>, 2899df49d7eSJed Brown } 2909df49d7eSJed Brown 291c68be7a2SJeremy L Thompson #[derive(Debug)] 2929df49d7eSJed Brown pub struct CompositeOperator<'a> { 2939df49d7eSJed Brown op_core: OperatorCore<'a>, 2949df49d7eSJed Brown } 2959df49d7eSJed Brown 2969df49d7eSJed Brown // ----------------------------------------------------------------------------- 2979df49d7eSJed Brown // Destructor 2989df49d7eSJed Brown // ----------------------------------------------------------------------------- 2999df49d7eSJed Brown impl<'a> Drop for OperatorCore<'a> { 3009df49d7eSJed Brown fn drop(&mut self) { 3019df49d7eSJed Brown unsafe { 3029df49d7eSJed Brown bind_ceed::CeedOperatorDestroy(&mut self.ptr); 3039df49d7eSJed Brown } 3049df49d7eSJed Brown } 3059df49d7eSJed Brown } 3069df49d7eSJed Brown 3079df49d7eSJed Brown // ----------------------------------------------------------------------------- 3089df49d7eSJed Brown // Display 3099df49d7eSJed Brown // ----------------------------------------------------------------------------- 3109df49d7eSJed Brown impl<'a> fmt::Display for OperatorCore<'a> { 3119df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 3129df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 3139df49d7eSJed Brown let mut sizeloc = crate::MAX_BUFFER_LENGTH; 3149df49d7eSJed Brown let cstring = unsafe { 3159df49d7eSJed Brown let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc); 3169df49d7eSJed Brown bind_ceed::CeedOperatorView(self.ptr, file); 3179df49d7eSJed Brown bind_ceed::fclose(file); 3189df49d7eSJed Brown CString::from_raw(ptr) 3199df49d7eSJed Brown }; 3209df49d7eSJed Brown cstring.to_string_lossy().fmt(f) 3219df49d7eSJed Brown } 3229df49d7eSJed Brown } 3239df49d7eSJed Brown 3249df49d7eSJed Brown /// View an Operator 3259df49d7eSJed Brown /// 3269df49d7eSJed Brown /// ``` 3279df49d7eSJed Brown /// # use libceed::prelude::*; 328*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 3299df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 330c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 3319df49d7eSJed Brown /// 3329df49d7eSJed Brown /// // Operator field arguments 3339df49d7eSJed Brown /// let ne = 3; 3349df49d7eSJed Brown /// let q = 4 as usize; 3359df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 3369df49d7eSJed Brown /// for i in 0..ne { 3379df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 3389df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 3399df49d7eSJed Brown /// } 340c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 3419df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 342c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 3439df49d7eSJed Brown /// 344c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 3459df49d7eSJed Brown /// 3469df49d7eSJed Brown /// // Operator fields 3479df49d7eSJed Brown /// let op = ceed 348c68be7a2SJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 349c68be7a2SJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 350c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 351c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 3529df49d7eSJed Brown /// 3539df49d7eSJed Brown /// println!("{}", op); 354c68be7a2SJeremy L Thompson /// # Ok(()) 355c68be7a2SJeremy L Thompson /// # } 3569df49d7eSJed Brown /// ``` 3579df49d7eSJed Brown impl<'a> fmt::Display for Operator<'a> { 3589df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 3599df49d7eSJed Brown self.op_core.fmt(f) 3609df49d7eSJed Brown } 3619df49d7eSJed Brown } 3629df49d7eSJed Brown 3639df49d7eSJed Brown /// View a composite Operator 3649df49d7eSJed Brown /// 3659df49d7eSJed Brown /// ``` 3669df49d7eSJed Brown /// # use libceed::prelude::*; 367*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 3689df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 3699df49d7eSJed Brown /// 3709df49d7eSJed Brown /// // Sub operator field arguments 3719df49d7eSJed Brown /// let ne = 3; 3729df49d7eSJed Brown /// let q = 4 as usize; 3739df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 3749df49d7eSJed Brown /// for i in 0..ne { 3759df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 3769df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 3779df49d7eSJed Brown /// } 378c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 3799df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 380c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 3819df49d7eSJed Brown /// 382c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 3839df49d7eSJed Brown /// 384c68be7a2SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?; 385c68be7a2SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?; 3869df49d7eSJed Brown /// 387c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 3889df49d7eSJed Brown /// let op_mass = ceed 389c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 390c68be7a2SJeremy L Thompson /// .field("u", &r, &b, VectorOpt::Active)? 391c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 392c68be7a2SJeremy L Thompson /// .field("v", &r, &b, VectorOpt::Active)?; 3939df49d7eSJed Brown /// 394c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 3959df49d7eSJed Brown /// let op_diff = ceed 396c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 397c68be7a2SJeremy L Thompson /// .field("du", &r, &b, VectorOpt::Active)? 398c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 399c68be7a2SJeremy L Thompson /// .field("dv", &r, &b, VectorOpt::Active)?; 4009df49d7eSJed Brown /// 4019df49d7eSJed Brown /// let op = ceed 402c68be7a2SJeremy L Thompson /// .composite_operator()? 403c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 404c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 4059df49d7eSJed Brown /// 4069df49d7eSJed Brown /// println!("{}", op); 407c68be7a2SJeremy L Thompson /// # Ok(()) 408c68be7a2SJeremy L Thompson /// # } 4099df49d7eSJed Brown /// ``` 4109df49d7eSJed Brown impl<'a> fmt::Display for CompositeOperator<'a> { 4119df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 4129df49d7eSJed Brown self.op_core.fmt(f) 4139df49d7eSJed Brown } 4149df49d7eSJed Brown } 4159df49d7eSJed Brown 4169df49d7eSJed Brown // ----------------------------------------------------------------------------- 4179df49d7eSJed Brown // Core functionality 4189df49d7eSJed Brown // ----------------------------------------------------------------------------- 4199df49d7eSJed Brown impl<'a> OperatorCore<'a> { 4201142270cSJeremy L Thompson // Error handling 4211142270cSJeremy L Thompson #[doc(hidden)] 4221142270cSJeremy L Thompson fn check_error(&self, ierr: i32) -> crate::Result<i32> { 4231142270cSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 4241142270cSJeremy L Thompson unsafe { 4251142270cSJeremy L Thompson bind_ceed::CeedOperatorGetCeed(self.ptr, &mut ptr); 4261142270cSJeremy L Thompson } 4271142270cSJeremy L Thompson crate::check_error(ptr, ierr) 4281142270cSJeremy L Thompson } 4291142270cSJeremy L Thompson 4309df49d7eSJed Brown // Common implementations 4319df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 4329df49d7eSJed Brown let ierr = unsafe { 4339df49d7eSJed Brown bind_ceed::CeedOperatorApply( 4349df49d7eSJed Brown self.ptr, 4359df49d7eSJed Brown input.ptr, 4369df49d7eSJed Brown output.ptr, 4379df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4389df49d7eSJed Brown ) 4399df49d7eSJed Brown }; 4401142270cSJeremy L Thompson self.check_error(ierr) 4419df49d7eSJed Brown } 4429df49d7eSJed Brown 4439df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 4449df49d7eSJed Brown let ierr = unsafe { 4459df49d7eSJed Brown bind_ceed::CeedOperatorApplyAdd( 4469df49d7eSJed Brown self.ptr, 4479df49d7eSJed Brown input.ptr, 4489df49d7eSJed Brown output.ptr, 4499df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4509df49d7eSJed Brown ) 4519df49d7eSJed Brown }; 4521142270cSJeremy L Thompson self.check_error(ierr) 4539df49d7eSJed Brown } 4549df49d7eSJed Brown 4559df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 4569df49d7eSJed Brown let ierr = unsafe { 4579df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleDiagonal( 4589df49d7eSJed Brown self.ptr, 4599df49d7eSJed Brown assembled.ptr, 4609df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4619df49d7eSJed Brown ) 4629df49d7eSJed Brown }; 4631142270cSJeremy L Thompson self.check_error(ierr) 4649df49d7eSJed Brown } 4659df49d7eSJed Brown 4669df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 4679df49d7eSJed Brown let ierr = unsafe { 4689df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddDiagonal( 4699df49d7eSJed Brown self.ptr, 4709df49d7eSJed Brown assembled.ptr, 4719df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4729df49d7eSJed Brown ) 4739df49d7eSJed Brown }; 4741142270cSJeremy L Thompson self.check_error(ierr) 4759df49d7eSJed Brown } 4769df49d7eSJed Brown 4779df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 4789df49d7eSJed Brown &self, 4799df49d7eSJed Brown assembled: &mut Vector, 4809df49d7eSJed Brown ) -> crate::Result<i32> { 4819df49d7eSJed Brown let ierr = unsafe { 4829df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssemblePointBlockDiagonal( 4839df49d7eSJed Brown self.ptr, 4849df49d7eSJed Brown assembled.ptr, 4859df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4869df49d7eSJed Brown ) 4879df49d7eSJed Brown }; 4881142270cSJeremy L Thompson self.check_error(ierr) 4899df49d7eSJed Brown } 4909df49d7eSJed Brown 4919df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 4929df49d7eSJed Brown &self, 4939df49d7eSJed Brown assembled: &mut Vector, 4949df49d7eSJed Brown ) -> crate::Result<i32> { 4959df49d7eSJed Brown let ierr = unsafe { 4969df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddPointBlockDiagonal( 4979df49d7eSJed Brown self.ptr, 4989df49d7eSJed Brown assembled.ptr, 4999df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 5009df49d7eSJed Brown ) 5019df49d7eSJed Brown }; 5021142270cSJeremy L Thompson self.check_error(ierr) 5039df49d7eSJed Brown } 5049df49d7eSJed Brown } 5059df49d7eSJed Brown 5069df49d7eSJed Brown // ----------------------------------------------------------------------------- 5079df49d7eSJed Brown // Operator 5089df49d7eSJed Brown // ----------------------------------------------------------------------------- 5099df49d7eSJed Brown impl<'a> Operator<'a> { 5109df49d7eSJed Brown // Constructor 5119df49d7eSJed Brown pub fn create<'b>( 5129df49d7eSJed Brown ceed: &'a crate::Ceed, 5139df49d7eSJed Brown qf: impl Into<QFunctionOpt<'b>>, 5149df49d7eSJed Brown dqf: impl Into<QFunctionOpt<'b>>, 5159df49d7eSJed Brown dqfT: impl Into<QFunctionOpt<'b>>, 5169df49d7eSJed Brown ) -> crate::Result<Self> { 5179df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 5189df49d7eSJed Brown let ierr = unsafe { 5199df49d7eSJed Brown bind_ceed::CeedOperatorCreate( 5209df49d7eSJed Brown ceed.ptr, 5219df49d7eSJed Brown qf.into().to_raw(), 5229df49d7eSJed Brown dqf.into().to_raw(), 5239df49d7eSJed Brown dqfT.into().to_raw(), 5249df49d7eSJed Brown &mut ptr, 5259df49d7eSJed Brown ) 5269df49d7eSJed Brown }; 5279df49d7eSJed Brown ceed.check_error(ierr)?; 5289df49d7eSJed Brown Ok(Self { 5291142270cSJeremy L Thompson op_core: OperatorCore { 5301142270cSJeremy L Thompson ptr, 5311142270cSJeremy L Thompson _lifeline: PhantomData, 5321142270cSJeremy L Thompson }, 5339df49d7eSJed Brown }) 5349df49d7eSJed Brown } 5359df49d7eSJed Brown 5361142270cSJeremy L Thompson fn from_raw(ptr: bind_ceed::CeedOperator) -> crate::Result<Self> { 5379df49d7eSJed Brown Ok(Self { 5381142270cSJeremy L Thompson op_core: OperatorCore { 5391142270cSJeremy L Thompson ptr, 5401142270cSJeremy L Thompson _lifeline: PhantomData, 5411142270cSJeremy L Thompson }, 5429df49d7eSJed Brown }) 5439df49d7eSJed Brown } 5449df49d7eSJed Brown 5459df49d7eSJed Brown /// Apply Operator to a vector 5469df49d7eSJed Brown /// 5479df49d7eSJed Brown /// * `input` - Input Vector 5489df49d7eSJed Brown /// * `output` - Output Vector 5499df49d7eSJed Brown /// 5509df49d7eSJed Brown /// ``` 5519df49d7eSJed Brown /// # use libceed::prelude::*; 552*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 5539df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 5549df49d7eSJed Brown /// let ne = 4; 5559df49d7eSJed Brown /// let p = 3; 5569df49d7eSJed Brown /// let q = 4; 5579df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 5589df49d7eSJed Brown /// 5599df49d7eSJed Brown /// // Vectors 560c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 561c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 5629df49d7eSJed Brown /// qdata.set_value(0.0); 563c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 564c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 5659df49d7eSJed Brown /// v.set_value(0.0); 5669df49d7eSJed Brown /// 5679df49d7eSJed Brown /// // Restrictions 5689df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 5699df49d7eSJed Brown /// for i in 0..ne { 5709df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 5719df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 5729df49d7eSJed Brown /// } 573c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 5749df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 5759df49d7eSJed Brown /// for i in 0..ne { 5769df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 5779df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 5789df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 5799df49d7eSJed Brown /// } 580c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 5819df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 582c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 5839df49d7eSJed Brown /// 5849df49d7eSJed Brown /// // Bases 585c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 586c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 5879df49d7eSJed Brown /// 5889df49d7eSJed Brown /// // Build quadrature data 589c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 590c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 591c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 592c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 593c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 594c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 5959df49d7eSJed Brown /// 5969df49d7eSJed Brown /// // Mass operator 597c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 5989df49d7eSJed Brown /// let op_mass = ceed 599c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 600c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 601c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 602c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 6039df49d7eSJed Brown /// 6049df49d7eSJed Brown /// v.set_value(0.0); 605c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 6069df49d7eSJed Brown /// 6079df49d7eSJed Brown /// // Check 608e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 6099df49d7eSJed Brown /// assert!( 61080a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 6119df49d7eSJed Brown /// "Incorrect interval length computed" 6129df49d7eSJed Brown /// ); 613c68be7a2SJeremy L Thompson /// # Ok(()) 614c68be7a2SJeremy L Thompson /// # } 6159df49d7eSJed Brown /// ``` 6169df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 6179df49d7eSJed Brown self.op_core.apply(input, output) 6189df49d7eSJed Brown } 6199df49d7eSJed Brown 6209df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 6219df49d7eSJed Brown /// 6229df49d7eSJed Brown /// * `input` - Input Vector 6239df49d7eSJed Brown /// * `output` - Output Vector 6249df49d7eSJed Brown /// 6259df49d7eSJed Brown /// ``` 6269df49d7eSJed Brown /// # use libceed::prelude::*; 627*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 6289df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 6299df49d7eSJed Brown /// let ne = 4; 6309df49d7eSJed Brown /// let p = 3; 6319df49d7eSJed Brown /// let q = 4; 6329df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 6339df49d7eSJed Brown /// 6349df49d7eSJed Brown /// // Vectors 635c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 636c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 6379df49d7eSJed Brown /// qdata.set_value(0.0); 638c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 639c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 6409df49d7eSJed Brown /// 6419df49d7eSJed Brown /// // Restrictions 6429df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 6439df49d7eSJed Brown /// for i in 0..ne { 6449df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 6459df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 6469df49d7eSJed Brown /// } 647c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 6489df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 6499df49d7eSJed Brown /// for i in 0..ne { 6509df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 6519df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 6529df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 6539df49d7eSJed Brown /// } 654c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 6559df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 656c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 6579df49d7eSJed Brown /// 6589df49d7eSJed Brown /// // Bases 659c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 660c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 6619df49d7eSJed Brown /// 6629df49d7eSJed Brown /// // Build quadrature data 663c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 664c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 665c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 666c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 667c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 668c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 6699df49d7eSJed Brown /// 6709df49d7eSJed Brown /// // Mass operator 671c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 6729df49d7eSJed Brown /// let op_mass = ceed 673c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 674c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 675c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 676c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 6779df49d7eSJed Brown /// 6789df49d7eSJed Brown /// v.set_value(1.0); 679c68be7a2SJeremy L Thompson /// op_mass.apply_add(&u, &mut v)?; 6809df49d7eSJed Brown /// 6819df49d7eSJed Brown /// // Check 682e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 6839df49d7eSJed Brown /// assert!( 68480a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 6859df49d7eSJed Brown /// "Incorrect interval length computed and added" 6869df49d7eSJed Brown /// ); 687c68be7a2SJeremy L Thompson /// # Ok(()) 688c68be7a2SJeremy L Thompson /// # } 6899df49d7eSJed Brown /// ``` 6909df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 6919df49d7eSJed Brown self.op_core.apply_add(input, output) 6929df49d7eSJed Brown } 6939df49d7eSJed Brown 6949df49d7eSJed Brown /// Provide a field to a Operator for use by its QFunction 6959df49d7eSJed Brown /// 6969df49d7eSJed Brown /// * `fieldname` - Name of the field (to be matched with the name used by 6979df49d7eSJed Brown /// the QFunction) 6989df49d7eSJed Brown /// * `r` - ElemRestriction 6999df49d7eSJed Brown /// * `b` - Basis in which the field resides or `BasisCollocated` if 7009df49d7eSJed Brown /// collocated with quadrature points 7019df49d7eSJed Brown /// * `v` - Vector to be used by Operator or `VectorActive` if field 7029df49d7eSJed Brown /// is active or `VectorNone` if using `Weight` with the 7039df49d7eSJed Brown /// QFunction 7049df49d7eSJed Brown /// 7059df49d7eSJed Brown /// 7069df49d7eSJed Brown /// ``` 7079df49d7eSJed Brown /// # use libceed::prelude::*; 708*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 7099df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 710c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 711c68be7a2SJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 7129df49d7eSJed Brown /// 7139df49d7eSJed Brown /// // Operator field arguments 7149df49d7eSJed Brown /// let ne = 3; 7159df49d7eSJed Brown /// let q = 4; 7169df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 7179df49d7eSJed Brown /// for i in 0..ne { 7189df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 7199df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 7209df49d7eSJed Brown /// } 721c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 7229df49d7eSJed Brown /// 723c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 7249df49d7eSJed Brown /// 7259df49d7eSJed Brown /// // Operator field 726c68be7a2SJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 727c68be7a2SJeremy L Thompson /// # Ok(()) 728c68be7a2SJeremy L Thompson /// # } 7299df49d7eSJed Brown /// ``` 7309df49d7eSJed Brown #[allow(unused_mut)] 7319df49d7eSJed Brown pub fn field<'b>( 7329df49d7eSJed Brown mut self, 7339df49d7eSJed Brown fieldname: &str, 7349df49d7eSJed Brown r: impl Into<ElemRestrictionOpt<'b>>, 7359df49d7eSJed Brown b: impl Into<BasisOpt<'b>>, 7369df49d7eSJed Brown v: impl Into<VectorOpt<'b>>, 7379df49d7eSJed Brown ) -> crate::Result<Self> { 7389df49d7eSJed Brown let fieldname = CString::new(fieldname).expect("CString::new failed"); 7399df49d7eSJed Brown let fieldname = fieldname.as_ptr() as *const i8; 7409df49d7eSJed Brown let ierr = unsafe { 7419df49d7eSJed Brown bind_ceed::CeedOperatorSetField( 7429df49d7eSJed Brown self.op_core.ptr, 7439df49d7eSJed Brown fieldname, 7449df49d7eSJed Brown r.into().to_raw(), 7459df49d7eSJed Brown b.into().to_raw(), 7469df49d7eSJed Brown v.into().to_raw(), 7479df49d7eSJed Brown ) 7489df49d7eSJed Brown }; 7491142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 7509df49d7eSJed Brown Ok(self) 7519df49d7eSJed Brown } 7529df49d7eSJed Brown 75308778c6fSJeremy L Thompson /// Get a slice of Operator inputs 75408778c6fSJeremy L Thompson /// 75508778c6fSJeremy L Thompson /// ``` 75608778c6fSJeremy L Thompson /// # use libceed::prelude::*; 757*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 75808778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 75908778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 76008778c6fSJeremy L Thompson /// 76108778c6fSJeremy L Thompson /// // Operator field arguments 76208778c6fSJeremy L Thompson /// let ne = 3; 76308778c6fSJeremy L Thompson /// let q = 4 as usize; 76408778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 76508778c6fSJeremy L Thompson /// for i in 0..ne { 76608778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 76708778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 76808778c6fSJeremy L Thompson /// } 76908778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 77008778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 77108778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 77208778c6fSJeremy L Thompson /// 77308778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 77408778c6fSJeremy L Thompson /// 77508778c6fSJeremy L Thompson /// // Operator fields 77608778c6fSJeremy L Thompson /// let op = ceed 77708778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 77808778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 77908778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 78008778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 78108778c6fSJeremy L Thompson /// 78208778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 78308778c6fSJeremy L Thompson /// 78408778c6fSJeremy L Thompson /// assert_eq!(inputs.len(), 2, "Incorrect inputs array"); 78508778c6fSJeremy L Thompson /// # Ok(()) 78608778c6fSJeremy L Thompson /// # } 78708778c6fSJeremy L Thompson /// ``` 78808778c6fSJeremy L Thompson pub fn inputs(&self) -> crate::Result<&[crate::OperatorField]> { 78908778c6fSJeremy L Thompson // Get array of raw C pointers for inputs 79008778c6fSJeremy L Thompson let mut num_inputs = 0; 79108778c6fSJeremy L Thompson let mut inputs_ptr = std::ptr::null_mut(); 79208778c6fSJeremy L Thompson let ierr = unsafe { 79308778c6fSJeremy L Thompson bind_ceed::CeedOperatorGetFields( 79408778c6fSJeremy L Thompson self.op_core.ptr, 79508778c6fSJeremy L Thompson &mut num_inputs, 79608778c6fSJeremy L Thompson &mut inputs_ptr, 79708778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt, 79808778c6fSJeremy L Thompson std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField, 79908778c6fSJeremy L Thompson ) 80008778c6fSJeremy L Thompson }; 80108778c6fSJeremy L Thompson self.op_core.check_error(ierr)?; 80208778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice 80308778c6fSJeremy L Thompson let inputs_slice = unsafe { 80408778c6fSJeremy L Thompson std::slice::from_raw_parts( 80508778c6fSJeremy L Thompson inputs_ptr as *const crate::OperatorField, 80608778c6fSJeremy L Thompson num_inputs as usize, 80708778c6fSJeremy L Thompson ) 80808778c6fSJeremy L Thompson }; 80908778c6fSJeremy L Thompson Ok(inputs_slice) 81008778c6fSJeremy L Thompson } 81108778c6fSJeremy L Thompson 81208778c6fSJeremy L Thompson /// Get a slice of Operator outputs 81308778c6fSJeremy L Thompson /// 81408778c6fSJeremy L Thompson /// ``` 81508778c6fSJeremy L Thompson /// # use libceed::prelude::*; 816*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 81708778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 81808778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 81908778c6fSJeremy L Thompson /// 82008778c6fSJeremy L Thompson /// // Operator field arguments 82108778c6fSJeremy L Thompson /// let ne = 3; 82208778c6fSJeremy L Thompson /// let q = 4 as usize; 82308778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 82408778c6fSJeremy L Thompson /// for i in 0..ne { 82508778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 82608778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 82708778c6fSJeremy L Thompson /// } 82808778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 82908778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 83008778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 83108778c6fSJeremy L Thompson /// 83208778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 83308778c6fSJeremy L Thompson /// 83408778c6fSJeremy L Thompson /// // Operator fields 83508778c6fSJeremy L Thompson /// let op = ceed 83608778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 83708778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 83808778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 83908778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 84008778c6fSJeremy L Thompson /// 84108778c6fSJeremy L Thompson /// let outputs = op.outputs()?; 84208778c6fSJeremy L Thompson /// 84308778c6fSJeremy L Thompson /// assert_eq!(outputs.len(), 1, "Incorrect outputs array"); 84408778c6fSJeremy L Thompson /// # Ok(()) 84508778c6fSJeremy L Thompson /// # } 84608778c6fSJeremy L Thompson /// ``` 84708778c6fSJeremy L Thompson pub fn outputs(&self) -> crate::Result<&[crate::OperatorField]> { 84808778c6fSJeremy L Thompson // Get array of raw C pointers for outputs 84908778c6fSJeremy L Thompson let mut num_outputs = 0; 85008778c6fSJeremy L Thompson let mut outputs_ptr = std::ptr::null_mut(); 85108778c6fSJeremy L Thompson let ierr = unsafe { 85208778c6fSJeremy L Thompson bind_ceed::CeedOperatorGetFields( 85308778c6fSJeremy L Thompson self.op_core.ptr, 85408778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt, 85508778c6fSJeremy L Thompson std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField, 85608778c6fSJeremy L Thompson &mut num_outputs, 85708778c6fSJeremy L Thompson &mut outputs_ptr, 85808778c6fSJeremy L Thompson ) 85908778c6fSJeremy L Thompson }; 86008778c6fSJeremy L Thompson self.op_core.check_error(ierr)?; 86108778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice 86208778c6fSJeremy L Thompson let outputs_slice = unsafe { 86308778c6fSJeremy L Thompson std::slice::from_raw_parts( 86408778c6fSJeremy L Thompson outputs_ptr as *const crate::OperatorField, 86508778c6fSJeremy L Thompson num_outputs as usize, 86608778c6fSJeremy L Thompson ) 86708778c6fSJeremy L Thompson }; 86808778c6fSJeremy L Thompson Ok(outputs_slice) 86908778c6fSJeremy L Thompson } 87008778c6fSJeremy L Thompson 8713f2759cfSJeremy L Thompson /// Get the number of elements associated with an Operator 8723f2759cfSJeremy L Thompson /// 8733f2759cfSJeremy L Thompson /// 8743f2759cfSJeremy L Thompson /// ``` 8753f2759cfSJeremy L Thompson /// # use libceed::prelude::*; 876*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 8773f2759cfSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 8783f2759cfSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 8793f2759cfSJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 8803f2759cfSJeremy L Thompson /// 8813f2759cfSJeremy L Thompson /// // Operator field arguments 8823f2759cfSJeremy L Thompson /// let ne = 3; 8833f2759cfSJeremy L Thompson /// let q = 4; 8843f2759cfSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 8853f2759cfSJeremy L Thompson /// for i in 0..ne { 8863f2759cfSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 8873f2759cfSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 8883f2759cfSJeremy L Thompson /// } 8893f2759cfSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 8903f2759cfSJeremy L Thompson /// 8913f2759cfSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 8923f2759cfSJeremy L Thompson /// 8933f2759cfSJeremy L Thompson /// // Operator field 8943f2759cfSJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 8953f2759cfSJeremy L Thompson /// 8963f2759cfSJeremy L Thompson /// // Check number of elements 8973f2759cfSJeremy L Thompson /// assert_eq!(op.num_elements(), ne, "Incorrect number of elements"); 8983f2759cfSJeremy L Thompson /// # Ok(()) 8993f2759cfSJeremy L Thompson /// # } 9003f2759cfSJeremy L Thompson /// ``` 9013f2759cfSJeremy L Thompson pub fn num_elements(&self) -> usize { 9023f2759cfSJeremy L Thompson let mut nelem = 0; 9033f2759cfSJeremy L Thompson unsafe { bind_ceed::CeedOperatorGetNumElements(self.op_core.ptr, &mut nelem) }; 9043f2759cfSJeremy L Thompson usize::try_from(nelem).unwrap() 9053f2759cfSJeremy L Thompson } 9063f2759cfSJeremy L Thompson 9073f2759cfSJeremy L Thompson /// Get the number of quadrature points associated with each element of 9083f2759cfSJeremy L Thompson /// an Operator 9093f2759cfSJeremy L Thompson /// 9103f2759cfSJeremy L Thompson /// 9113f2759cfSJeremy L Thompson /// ``` 9123f2759cfSJeremy L Thompson /// # use libceed::prelude::*; 913*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 9143f2759cfSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 9153f2759cfSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 9163f2759cfSJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 9173f2759cfSJeremy L Thompson /// 9183f2759cfSJeremy L Thompson /// // Operator field arguments 9193f2759cfSJeremy L Thompson /// let ne = 3; 9203f2759cfSJeremy L Thompson /// let q = 4; 9213f2759cfSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 9223f2759cfSJeremy L Thompson /// for i in 0..ne { 9233f2759cfSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 9243f2759cfSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 9253f2759cfSJeremy L Thompson /// } 9263f2759cfSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 9273f2759cfSJeremy L Thompson /// 9283f2759cfSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 9293f2759cfSJeremy L Thompson /// 9303f2759cfSJeremy L Thompson /// // Operator field 9313f2759cfSJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 9323f2759cfSJeremy L Thompson /// 9333f2759cfSJeremy L Thompson /// // Check number of quadrature points 9343f2759cfSJeremy L Thompson /// assert_eq!( 9353f2759cfSJeremy L Thompson /// op.num_quadrature_points(), 9363f2759cfSJeremy L Thompson /// q, 9373f2759cfSJeremy L Thompson /// "Incorrect number of quadrature points" 9383f2759cfSJeremy L Thompson /// ); 9393f2759cfSJeremy L Thompson /// # Ok(()) 9403f2759cfSJeremy L Thompson /// # } 9413f2759cfSJeremy L Thompson /// ``` 9423f2759cfSJeremy L Thompson pub fn num_quadrature_points(&self) -> usize { 9433f2759cfSJeremy L Thompson let mut Q = 0; 9443f2759cfSJeremy L Thompson unsafe { bind_ceed::CeedOperatorGetNumQuadraturePoints(self.op_core.ptr, &mut Q) }; 9453f2759cfSJeremy L Thompson usize::try_from(Q).unwrap() 9463f2759cfSJeremy L Thompson } 9473f2759cfSJeremy L Thompson 9489df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 9499df49d7eSJed Brown /// 9509df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 9519df49d7eSJed Brown /// 9529df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 9539df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 9549df49d7eSJed Brown /// 9559df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 9569df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 9579df49d7eSJed Brown /// 9589df49d7eSJed Brown /// ``` 9599df49d7eSJed Brown /// # use libceed::prelude::*; 960*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 9619df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 9629df49d7eSJed Brown /// let ne = 4; 9639df49d7eSJed Brown /// let p = 3; 9649df49d7eSJed Brown /// let q = 4; 9659df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 9669df49d7eSJed Brown /// 9679df49d7eSJed Brown /// // Vectors 968c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 969c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 9709df49d7eSJed Brown /// qdata.set_value(0.0); 971c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 9729df49d7eSJed Brown /// u.set_value(1.0); 973c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 9749df49d7eSJed Brown /// v.set_value(0.0); 9759df49d7eSJed Brown /// 9769df49d7eSJed Brown /// // Restrictions 9779df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 9789df49d7eSJed Brown /// for i in 0..ne { 9799df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 9809df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 9819df49d7eSJed Brown /// } 982c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 9839df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 9849df49d7eSJed Brown /// for i in 0..ne { 9859df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 9869df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 9879df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 9889df49d7eSJed Brown /// } 989c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 9909df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 991c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 9929df49d7eSJed Brown /// 9939df49d7eSJed Brown /// // Bases 994c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 995c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 9969df49d7eSJed Brown /// 9979df49d7eSJed Brown /// // Build quadrature data 998c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 999c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1000c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1001c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1002c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1003c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 10049df49d7eSJed Brown /// 10059df49d7eSJed Brown /// // Mass operator 1006c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 10079df49d7eSJed Brown /// let op_mass = ceed 1008c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1009c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1010c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1011c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 10129df49d7eSJed Brown /// 10139df49d7eSJed Brown /// // Diagonal 1014c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 10159df49d7eSJed Brown /// diag.set_value(0.0); 1016c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_diagonal(&mut diag)?; 10179df49d7eSJed Brown /// 10189df49d7eSJed Brown /// // Manual diagonal computation 1019c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 10209df49d7eSJed Brown /// for i in 0..ndofs { 10219df49d7eSJed Brown /// u.set_value(0.0); 10229df49d7eSJed Brown /// { 1023e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 10249df49d7eSJed Brown /// u_array[i] = 1.; 10259df49d7eSJed Brown /// } 10269df49d7eSJed Brown /// 1027c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 10289df49d7eSJed Brown /// 10299df49d7eSJed Brown /// { 1030e78171edSJeremy L Thompson /// let v_array = v.view_mut()?; 1031e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 10329df49d7eSJed Brown /// true_array[i] = v_array[i]; 10339df49d7eSJed Brown /// } 10349df49d7eSJed Brown /// } 10359df49d7eSJed Brown /// 10369df49d7eSJed Brown /// // Check 1037e78171edSJeremy L Thompson /// diag.view()? 10389df49d7eSJed Brown /// .iter() 1039e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 10409df49d7eSJed Brown /// .for_each(|(computed, actual)| { 10419df49d7eSJed Brown /// assert!( 104280a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 10439df49d7eSJed Brown /// "Diagonal entry incorrect" 10449df49d7eSJed Brown /// ); 10459df49d7eSJed Brown /// }); 1046c68be7a2SJeremy L Thompson /// # Ok(()) 1047c68be7a2SJeremy L Thompson /// # } 10489df49d7eSJed Brown /// ``` 10499df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 10509df49d7eSJed Brown self.op_core.linear_assemble_diagonal(assembled) 10519df49d7eSJed Brown } 10529df49d7eSJed Brown 10539df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 10549df49d7eSJed Brown /// 10559df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 10569df49d7eSJed Brown /// 10579df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 10589df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 10599df49d7eSJed Brown /// 10609df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 10619df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 10629df49d7eSJed Brown /// 10639df49d7eSJed Brown /// 10649df49d7eSJed Brown /// ``` 10659df49d7eSJed Brown /// # use libceed::prelude::*; 1066*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 10679df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 10689df49d7eSJed Brown /// let ne = 4; 10699df49d7eSJed Brown /// let p = 3; 10709df49d7eSJed Brown /// let q = 4; 10719df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 10729df49d7eSJed Brown /// 10739df49d7eSJed Brown /// // Vectors 1074c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1075c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 10769df49d7eSJed Brown /// qdata.set_value(0.0); 1077c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 10789df49d7eSJed Brown /// u.set_value(1.0); 1079c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 10809df49d7eSJed Brown /// v.set_value(0.0); 10819df49d7eSJed Brown /// 10829df49d7eSJed Brown /// // Restrictions 10839df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 10849df49d7eSJed Brown /// for i in 0..ne { 10859df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 10869df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 10879df49d7eSJed Brown /// } 1088c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 10899df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 10909df49d7eSJed Brown /// for i in 0..ne { 10919df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 10929df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 10939df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 10949df49d7eSJed Brown /// } 1095c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 10969df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1097c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 10989df49d7eSJed Brown /// 10999df49d7eSJed Brown /// // Bases 1100c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1101c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 11029df49d7eSJed Brown /// 11039df49d7eSJed Brown /// // Build quadrature data 1104c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1105c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1106c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1107c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1108c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1109c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 11109df49d7eSJed Brown /// 11119df49d7eSJed Brown /// // Mass operator 1112c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 11139df49d7eSJed Brown /// let op_mass = ceed 1114c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1115c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1116c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1117c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 11189df49d7eSJed Brown /// 11199df49d7eSJed Brown /// // Diagonal 1120c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 11219df49d7eSJed Brown /// diag.set_value(1.0); 1122c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_diagonal(&mut diag)?; 11239df49d7eSJed Brown /// 11249df49d7eSJed Brown /// // Manual diagonal computation 1125c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 11269df49d7eSJed Brown /// for i in 0..ndofs { 11279df49d7eSJed Brown /// u.set_value(0.0); 11289df49d7eSJed Brown /// { 1129e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 11309df49d7eSJed Brown /// u_array[i] = 1.; 11319df49d7eSJed Brown /// } 11329df49d7eSJed Brown /// 1133c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 11349df49d7eSJed Brown /// 11359df49d7eSJed Brown /// { 1136e78171edSJeremy L Thompson /// let v_array = v.view_mut()?; 1137e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 11389df49d7eSJed Brown /// true_array[i] = v_array[i] + 1.0; 11399df49d7eSJed Brown /// } 11409df49d7eSJed Brown /// } 11419df49d7eSJed Brown /// 11429df49d7eSJed Brown /// // Check 1143e78171edSJeremy L Thompson /// diag.view()? 11449df49d7eSJed Brown /// .iter() 1145e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 11469df49d7eSJed Brown /// .for_each(|(computed, actual)| { 11479df49d7eSJed Brown /// assert!( 114880a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 11499df49d7eSJed Brown /// "Diagonal entry incorrect" 11509df49d7eSJed Brown /// ); 11519df49d7eSJed Brown /// }); 1152c68be7a2SJeremy L Thompson /// # Ok(()) 1153c68be7a2SJeremy L Thompson /// # } 11549df49d7eSJed Brown /// ``` 11559df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 11569df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 11579df49d7eSJed Brown } 11589df49d7eSJed Brown 11599df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 11609df49d7eSJed Brown /// 11619df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 11629df49d7eSJed Brown /// Operator. 11639df49d7eSJed Brown /// 11649df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 11659df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 11669df49d7eSJed Brown /// 11679df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 11689df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 11699df49d7eSJed Brown /// diagonal, provided in row-major form with an 11709df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 11719df49d7eSJed Brown /// this vector are derived from the active vector for 11729df49d7eSJed Brown /// the CeedOperator. The array has shape 11739df49d7eSJed Brown /// `[nodes, component out, component in]`. 11749df49d7eSJed Brown /// 11759df49d7eSJed Brown /// ``` 11769df49d7eSJed Brown /// # use libceed::prelude::*; 1177*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 11789df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 11799df49d7eSJed Brown /// let ne = 4; 11809df49d7eSJed Brown /// let p = 3; 11819df49d7eSJed Brown /// let q = 4; 11829df49d7eSJed Brown /// let ncomp = 2; 11839df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 11849df49d7eSJed Brown /// 11859df49d7eSJed Brown /// // Vectors 1186c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1187c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 11889df49d7eSJed Brown /// qdata.set_value(0.0); 1189c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 11909df49d7eSJed Brown /// u.set_value(1.0); 1191c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 11929df49d7eSJed Brown /// v.set_value(0.0); 11939df49d7eSJed Brown /// 11949df49d7eSJed Brown /// // Restrictions 11959df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 11969df49d7eSJed Brown /// for i in 0..ne { 11979df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 11989df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 11999df49d7eSJed Brown /// } 1200c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 12019df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 12029df49d7eSJed Brown /// for i in 0..ne { 12039df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 12049df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 12059df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 12069df49d7eSJed Brown /// } 1207c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 12089df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1209c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 12109df49d7eSJed Brown /// 12119df49d7eSJed Brown /// // Bases 1212c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1213c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 12149df49d7eSJed Brown /// 12159df49d7eSJed Brown /// // Build quadrature data 1216c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1217c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1218c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1219c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1220c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1221c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 12229df49d7eSJed Brown /// 12239df49d7eSJed Brown /// // Mass operator 12249df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 12259df49d7eSJed Brown /// // Number of quadrature points 12269df49d7eSJed Brown /// let q = qdata.len(); 12279df49d7eSJed Brown /// 12289df49d7eSJed Brown /// // Iterate over quadrature points 12299df49d7eSJed Brown /// for i in 0..q { 12309df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 12319df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 12329df49d7eSJed Brown /// } 12339df49d7eSJed Brown /// 12349df49d7eSJed Brown /// // Return clean error code 12359df49d7eSJed Brown /// 0 12369df49d7eSJed Brown /// }; 12379df49d7eSJed Brown /// 12389df49d7eSJed Brown /// let qf_mass = ceed 1239c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 1240c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 1241c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 1242c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 12439df49d7eSJed Brown /// 12449df49d7eSJed Brown /// let op_mass = ceed 1245c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1246c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1247c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1248c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 12499df49d7eSJed Brown /// 12509df49d7eSJed Brown /// // Diagonal 1251c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 12529df49d7eSJed Brown /// diag.set_value(0.0); 1253c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_point_block_diagonal(&mut diag)?; 12549df49d7eSJed Brown /// 12559df49d7eSJed Brown /// // Manual diagonal computation 1256c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 12579df49d7eSJed Brown /// for i in 0..ndofs { 12589df49d7eSJed Brown /// for j in 0..ncomp { 12599df49d7eSJed Brown /// u.set_value(0.0); 12609df49d7eSJed Brown /// { 1261e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 12629df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 12639df49d7eSJed Brown /// } 12649df49d7eSJed Brown /// 1265c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 12669df49d7eSJed Brown /// 12679df49d7eSJed Brown /// { 1268e78171edSJeremy L Thompson /// let v_array = v.view_mut()?; 1269e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 12709df49d7eSJed Brown /// for k in 0..ncomp { 12719df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 12729df49d7eSJed Brown /// } 12739df49d7eSJed Brown /// } 12749df49d7eSJed Brown /// } 12759df49d7eSJed Brown /// } 12769df49d7eSJed Brown /// 12779df49d7eSJed Brown /// // Check 1278e78171edSJeremy L Thompson /// diag.view()? 12799df49d7eSJed Brown /// .iter() 1280e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 12819df49d7eSJed Brown /// .for_each(|(computed, actual)| { 12829df49d7eSJed Brown /// assert!( 128380a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 12849df49d7eSJed Brown /// "Diagonal entry incorrect" 12859df49d7eSJed Brown /// ); 12869df49d7eSJed Brown /// }); 1287c68be7a2SJeremy L Thompson /// # Ok(()) 1288c68be7a2SJeremy L Thompson /// # } 12899df49d7eSJed Brown /// ``` 12909df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 12919df49d7eSJed Brown &self, 12929df49d7eSJed Brown assembled: &mut Vector, 12939df49d7eSJed Brown ) -> crate::Result<i32> { 12949df49d7eSJed Brown self.op_core.linear_assemble_point_block_diagonal(assembled) 12959df49d7eSJed Brown } 12969df49d7eSJed Brown 12979df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 12989df49d7eSJed Brown /// 12999df49d7eSJed Brown /// This sums into a Vector with the point block diagonal of a linear 13009df49d7eSJed Brown /// Operator. 13019df49d7eSJed Brown /// 13029df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 13039df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 13049df49d7eSJed Brown /// 13059df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 13069df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 13079df49d7eSJed Brown /// diagonal, provided in row-major form with an 13089df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 13099df49d7eSJed Brown /// this vector are derived from the active vector for 13109df49d7eSJed Brown /// the CeedOperator. The array has shape 13119df49d7eSJed Brown /// `[nodes, component out, component in]`. 13129df49d7eSJed Brown /// 13139df49d7eSJed Brown /// ``` 13149df49d7eSJed Brown /// # use libceed::prelude::*; 1315*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 13169df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 13179df49d7eSJed Brown /// let ne = 4; 13189df49d7eSJed Brown /// let p = 3; 13199df49d7eSJed Brown /// let q = 4; 13209df49d7eSJed Brown /// let ncomp = 2; 13219df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 13229df49d7eSJed Brown /// 13239df49d7eSJed Brown /// // Vectors 1324c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1325c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 13269df49d7eSJed Brown /// qdata.set_value(0.0); 1327c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 13289df49d7eSJed Brown /// u.set_value(1.0); 1329c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 13309df49d7eSJed Brown /// v.set_value(0.0); 13319df49d7eSJed Brown /// 13329df49d7eSJed Brown /// // Restrictions 13339df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 13349df49d7eSJed Brown /// for i in 0..ne { 13359df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 13369df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 13379df49d7eSJed Brown /// } 1338c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 13399df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 13409df49d7eSJed Brown /// for i in 0..ne { 13419df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 13429df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 13439df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 13449df49d7eSJed Brown /// } 1345c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 13469df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1347c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 13489df49d7eSJed Brown /// 13499df49d7eSJed Brown /// // Bases 1350c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1351c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 13529df49d7eSJed Brown /// 13539df49d7eSJed Brown /// // Build quadrature data 1354c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1355c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1356c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1357c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1358c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1359c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 13609df49d7eSJed Brown /// 13619df49d7eSJed Brown /// // Mass operator 13629df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 13639df49d7eSJed Brown /// // Number of quadrature points 13649df49d7eSJed Brown /// let q = qdata.len(); 13659df49d7eSJed Brown /// 13669df49d7eSJed Brown /// // Iterate over quadrature points 13679df49d7eSJed Brown /// for i in 0..q { 13689df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 13699df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 13709df49d7eSJed Brown /// } 13719df49d7eSJed Brown /// 13729df49d7eSJed Brown /// // Return clean error code 13739df49d7eSJed Brown /// 0 13749df49d7eSJed Brown /// }; 13759df49d7eSJed Brown /// 13769df49d7eSJed Brown /// let qf_mass = ceed 1377c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 1378c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 1379c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 1380c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 13819df49d7eSJed Brown /// 13829df49d7eSJed Brown /// let op_mass = ceed 1383c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1384c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1385c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1386c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 13879df49d7eSJed Brown /// 13889df49d7eSJed Brown /// // Diagonal 1389c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 13909df49d7eSJed Brown /// diag.set_value(1.0); 1391c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_point_block_diagonal(&mut diag)?; 13929df49d7eSJed Brown /// 13939df49d7eSJed Brown /// // Manual diagonal computation 1394c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 13959df49d7eSJed Brown /// for i in 0..ndofs { 13969df49d7eSJed Brown /// for j in 0..ncomp { 13979df49d7eSJed Brown /// u.set_value(0.0); 13989df49d7eSJed Brown /// { 1399e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 14009df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 14019df49d7eSJed Brown /// } 14029df49d7eSJed Brown /// 1403c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 14049df49d7eSJed Brown /// 14059df49d7eSJed Brown /// { 1406e78171edSJeremy L Thompson /// let v_array = v.view_mut()?; 1407e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 14089df49d7eSJed Brown /// for k in 0..ncomp { 14099df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 14109df49d7eSJed Brown /// } 14119df49d7eSJed Brown /// } 14129df49d7eSJed Brown /// } 14139df49d7eSJed Brown /// } 14149df49d7eSJed Brown /// 14159df49d7eSJed Brown /// // Check 1416e78171edSJeremy L Thompson /// diag.view()? 14179df49d7eSJed Brown /// .iter() 1418e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 14199df49d7eSJed Brown /// .for_each(|(computed, actual)| { 14209df49d7eSJed Brown /// assert!( 142180a9ef05SNatalie Beams /// (*computed - 1.0 - *actual).abs() < 10.0 * libceed::EPSILON, 14229df49d7eSJed Brown /// "Diagonal entry incorrect" 14239df49d7eSJed Brown /// ); 14249df49d7eSJed Brown /// }); 1425c68be7a2SJeremy L Thompson /// # Ok(()) 1426c68be7a2SJeremy L Thompson /// # } 14279df49d7eSJed Brown /// ``` 14289df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 14299df49d7eSJed Brown &self, 14309df49d7eSJed Brown assembled: &mut Vector, 14319df49d7eSJed Brown ) -> crate::Result<i32> { 14329df49d7eSJed Brown self.op_core 14339df49d7eSJed Brown .linear_assemble_add_point_block_diagonal(assembled) 14349df49d7eSJed Brown } 14359df49d7eSJed Brown 14369df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 14379df49d7eSJed Brown /// given Operator, creating the prolongation basis from the fine and 14389df49d7eSJed Brown /// coarse grid interpolation 14399df49d7eSJed Brown /// 14409df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 14419df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 14429df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 14439df49d7eSJed Brown /// 14449df49d7eSJed Brown /// ``` 14459df49d7eSJed Brown /// # use libceed::prelude::*; 1446*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 14479df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 14489df49d7eSJed Brown /// let ne = 15; 14499df49d7eSJed Brown /// let p_coarse = 3; 14509df49d7eSJed Brown /// let p_fine = 5; 14519df49d7eSJed Brown /// let q = 6; 14529df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 14539df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 14549df49d7eSJed Brown /// 14559df49d7eSJed Brown /// // Vectors 14569df49d7eSJed Brown /// let x_array = (0..ne + 1) 145780a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 145880a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1459c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1460c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 14619df49d7eSJed Brown /// qdata.set_value(0.0); 1462c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 14639df49d7eSJed Brown /// u_coarse.set_value(1.0); 1464c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 14659df49d7eSJed Brown /// u_fine.set_value(1.0); 1466c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 14679df49d7eSJed Brown /// v_coarse.set_value(0.0); 1468c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 14699df49d7eSJed Brown /// v_fine.set_value(0.0); 1470c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 14719df49d7eSJed Brown /// multiplicity.set_value(1.0); 14729df49d7eSJed Brown /// 14739df49d7eSJed Brown /// // Restrictions 14749df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1475c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 14769df49d7eSJed Brown /// 14779df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 14789df49d7eSJed Brown /// for i in 0..ne { 14799df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 14809df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 14819df49d7eSJed Brown /// } 1482c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 14839df49d7eSJed Brown /// 14849df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 14859df49d7eSJed Brown /// for i in 0..ne { 14869df49d7eSJed Brown /// for j in 0..p_coarse { 14879df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 14889df49d7eSJed Brown /// } 14899df49d7eSJed Brown /// } 1490c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 14919df49d7eSJed Brown /// ne, 14929df49d7eSJed Brown /// p_coarse, 14939df49d7eSJed Brown /// 1, 14949df49d7eSJed Brown /// 1, 14959df49d7eSJed Brown /// ndofs_coarse, 14969df49d7eSJed Brown /// MemType::Host, 14979df49d7eSJed Brown /// &indu_coarse, 1498c68be7a2SJeremy L Thompson /// )?; 14999df49d7eSJed Brown /// 15009df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 15019df49d7eSJed Brown /// for i in 0..ne { 15029df49d7eSJed Brown /// for j in 0..p_fine { 15039df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 15049df49d7eSJed Brown /// } 15059df49d7eSJed Brown /// } 1506c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 15079df49d7eSJed Brown /// 15089df49d7eSJed Brown /// // Bases 1509c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1510c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1511c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 15129df49d7eSJed Brown /// 15139df49d7eSJed Brown /// // Build quadrature data 1514c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1515c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1516c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1517c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1518c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1519c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 15209df49d7eSJed Brown /// 15219df49d7eSJed Brown /// // Mass operator 1522c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 15239df49d7eSJed Brown /// let op_mass_fine = ceed 1524c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1525c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1526c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1527c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 15289df49d7eSJed Brown /// 15299df49d7eSJed Brown /// // Multigrid setup 1530c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = 1531c68be7a2SJeremy L Thompson /// op_mass_fine.create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)?; 15329df49d7eSJed Brown /// 15339df49d7eSJed Brown /// // Coarse problem 15349df49d7eSJed Brown /// u_coarse.set_value(1.0); 1535c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 15369df49d7eSJed Brown /// 15379df49d7eSJed Brown /// // Check 1538e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 15399df49d7eSJed Brown /// assert!( 154080a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 15419df49d7eSJed Brown /// "Incorrect interval length computed" 15429df49d7eSJed Brown /// ); 15439df49d7eSJed Brown /// 15449df49d7eSJed Brown /// // Prolong 1545c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 15469df49d7eSJed Brown /// 15479df49d7eSJed Brown /// // Fine problem 1548c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 15499df49d7eSJed Brown /// 15509df49d7eSJed Brown /// // Check 1551e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 15529df49d7eSJed Brown /// assert!( 155380a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 15549df49d7eSJed Brown /// "Incorrect interval length computed" 15559df49d7eSJed Brown /// ); 15569df49d7eSJed Brown /// 15579df49d7eSJed Brown /// // Restrict 1558c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 15599df49d7eSJed Brown /// 15609df49d7eSJed Brown /// // Check 1561e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 15629df49d7eSJed Brown /// assert!( 156380a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 15649df49d7eSJed Brown /// "Incorrect interval length computed" 15659df49d7eSJed Brown /// ); 1566c68be7a2SJeremy L Thompson /// # Ok(()) 1567c68be7a2SJeremy L Thompson /// # } 15689df49d7eSJed Brown /// ``` 15699df49d7eSJed Brown pub fn create_multigrid_level( 15709df49d7eSJed Brown &self, 15719df49d7eSJed Brown p_mult_fine: &Vector, 15729df49d7eSJed Brown rstr_coarse: &ElemRestriction, 15739df49d7eSJed Brown basis_coarse: &Basis, 15749df49d7eSJed Brown ) -> crate::Result<(Operator, Operator, Operator)> { 15759df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 15769df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 15779df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 15789df49d7eSJed Brown let ierr = unsafe { 15799df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreate( 15809df49d7eSJed Brown self.op_core.ptr, 15819df49d7eSJed Brown p_mult_fine.ptr, 15829df49d7eSJed Brown rstr_coarse.ptr, 15839df49d7eSJed Brown basis_coarse.ptr, 15849df49d7eSJed Brown &mut ptr_coarse, 15859df49d7eSJed Brown &mut ptr_prolong, 15869df49d7eSJed Brown &mut ptr_restrict, 15879df49d7eSJed Brown ) 15889df49d7eSJed Brown }; 15891142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 15901142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 15911142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 15921142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 15939df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 15949df49d7eSJed Brown } 15959df49d7eSJed Brown 15969df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 15979df49d7eSJed Brown /// given Operator with a tensor basis for the active basis 15989df49d7eSJed Brown /// 15999df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 16009df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 16019df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 16029df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 16039df49d7eSJed Brown /// 16049df49d7eSJed Brown /// ``` 16059df49d7eSJed Brown /// # use libceed::prelude::*; 1606*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 16079df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 16089df49d7eSJed Brown /// let ne = 15; 16099df49d7eSJed Brown /// let p_coarse = 3; 16109df49d7eSJed Brown /// let p_fine = 5; 16119df49d7eSJed Brown /// let q = 6; 16129df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 16139df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 16149df49d7eSJed Brown /// 16159df49d7eSJed Brown /// // Vectors 16169df49d7eSJed Brown /// let x_array = (0..ne + 1) 161780a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 161880a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1619c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1620c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 16219df49d7eSJed Brown /// qdata.set_value(0.0); 1622c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 16239df49d7eSJed Brown /// u_coarse.set_value(1.0); 1624c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 16259df49d7eSJed Brown /// u_fine.set_value(1.0); 1626c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 16279df49d7eSJed Brown /// v_coarse.set_value(0.0); 1628c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 16299df49d7eSJed Brown /// v_fine.set_value(0.0); 1630c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 16319df49d7eSJed Brown /// multiplicity.set_value(1.0); 16329df49d7eSJed Brown /// 16339df49d7eSJed Brown /// // Restrictions 16349df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1635c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 16369df49d7eSJed Brown /// 16379df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 16389df49d7eSJed Brown /// for i in 0..ne { 16399df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 16409df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 16419df49d7eSJed Brown /// } 1642c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 16439df49d7eSJed Brown /// 16449df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 16459df49d7eSJed Brown /// for i in 0..ne { 16469df49d7eSJed Brown /// for j in 0..p_coarse { 16479df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 16489df49d7eSJed Brown /// } 16499df49d7eSJed Brown /// } 1650c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 16519df49d7eSJed Brown /// ne, 16529df49d7eSJed Brown /// p_coarse, 16539df49d7eSJed Brown /// 1, 16549df49d7eSJed Brown /// 1, 16559df49d7eSJed Brown /// ndofs_coarse, 16569df49d7eSJed Brown /// MemType::Host, 16579df49d7eSJed Brown /// &indu_coarse, 1658c68be7a2SJeremy L Thompson /// )?; 16599df49d7eSJed Brown /// 16609df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 16619df49d7eSJed Brown /// for i in 0..ne { 16629df49d7eSJed Brown /// for j in 0..p_fine { 16639df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 16649df49d7eSJed Brown /// } 16659df49d7eSJed Brown /// } 1666c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 16679df49d7eSJed Brown /// 16689df49d7eSJed Brown /// // Bases 1669c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1670c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1671c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 16729df49d7eSJed Brown /// 16739df49d7eSJed Brown /// // Build quadrature data 1674c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1675c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1676c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1677c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1678c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1679c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 16809df49d7eSJed Brown /// 16819df49d7eSJed Brown /// // Mass operator 1682c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 16839df49d7eSJed Brown /// let op_mass_fine = ceed 1684c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1685c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1686c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1687c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 16889df49d7eSJed Brown /// 16899df49d7eSJed Brown /// // Multigrid setup 169080a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 16919df49d7eSJed Brown /// { 1692c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 1693c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 1694c68be7a2SJeremy L Thompson /// let basis_c_to_f = 1695c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 16969df49d7eSJed Brown /// for i in 0..p_coarse { 16979df49d7eSJed Brown /// coarse.set_value(0.0); 16989df49d7eSJed Brown /// { 1699e78171edSJeremy L Thompson /// let mut array = coarse.view_mut()?; 17009df49d7eSJed Brown /// array[i] = 1.; 17019df49d7eSJed Brown /// } 1702c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 17039df49d7eSJed Brown /// 1, 17049df49d7eSJed Brown /// TransposeMode::NoTranspose, 17059df49d7eSJed Brown /// EvalMode::Interp, 17069df49d7eSJed Brown /// &coarse, 17079df49d7eSJed Brown /// &mut fine, 1708c68be7a2SJeremy L Thompson /// )?; 1709e78171edSJeremy L Thompson /// let array = fine.view()?; 17109df49d7eSJed Brown /// for j in 0..p_fine { 17119df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 17129df49d7eSJed Brown /// } 17139df49d7eSJed Brown /// } 17149df49d7eSJed Brown /// } 1715c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_tensor_H1( 1716c68be7a2SJeremy L Thompson /// &multiplicity, 1717c68be7a2SJeremy L Thompson /// &ru_coarse, 1718c68be7a2SJeremy L Thompson /// &bu_coarse, 1719c68be7a2SJeremy L Thompson /// &interp_c_to_f, 1720c68be7a2SJeremy L Thompson /// )?; 17219df49d7eSJed Brown /// 17229df49d7eSJed Brown /// // Coarse problem 17239df49d7eSJed Brown /// u_coarse.set_value(1.0); 1724c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 17259df49d7eSJed Brown /// 17269df49d7eSJed Brown /// // Check 1727e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 17289df49d7eSJed Brown /// assert!( 172980a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 17309df49d7eSJed Brown /// "Incorrect interval length computed" 17319df49d7eSJed Brown /// ); 17329df49d7eSJed Brown /// 17339df49d7eSJed Brown /// // Prolong 1734c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 17359df49d7eSJed Brown /// 17369df49d7eSJed Brown /// // Fine problem 1737c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 17389df49d7eSJed Brown /// 17399df49d7eSJed Brown /// // Check 1740e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 17419df49d7eSJed Brown /// assert!( 174280a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 17439df49d7eSJed Brown /// "Incorrect interval length computed" 17449df49d7eSJed Brown /// ); 17459df49d7eSJed Brown /// 17469df49d7eSJed Brown /// // Restrict 1747c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 17489df49d7eSJed Brown /// 17499df49d7eSJed Brown /// // Check 1750e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 17519df49d7eSJed Brown /// assert!( 175280a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 17539df49d7eSJed Brown /// "Incorrect interval length computed" 17549df49d7eSJed Brown /// ); 1755c68be7a2SJeremy L Thompson /// # Ok(()) 1756c68be7a2SJeremy L Thompson /// # } 17579df49d7eSJed Brown /// ``` 17589df49d7eSJed Brown pub fn create_multigrid_level_tensor_H1( 17599df49d7eSJed Brown &self, 17609df49d7eSJed Brown p_mult_fine: &Vector, 17619df49d7eSJed Brown rstr_coarse: &ElemRestriction, 17629df49d7eSJed Brown basis_coarse: &Basis, 176380a9ef05SNatalie Beams interpCtoF: &Vec<Scalar>, 17649df49d7eSJed Brown ) -> crate::Result<(Operator, Operator, Operator)> { 17659df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 17669df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 17679df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 17689df49d7eSJed Brown let ierr = unsafe { 17699df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateTensorH1( 17709df49d7eSJed Brown self.op_core.ptr, 17719df49d7eSJed Brown p_mult_fine.ptr, 17729df49d7eSJed Brown rstr_coarse.ptr, 17739df49d7eSJed Brown basis_coarse.ptr, 17749df49d7eSJed Brown interpCtoF.as_ptr(), 17759df49d7eSJed Brown &mut ptr_coarse, 17769df49d7eSJed Brown &mut ptr_prolong, 17779df49d7eSJed Brown &mut ptr_restrict, 17789df49d7eSJed Brown ) 17799df49d7eSJed Brown }; 17801142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 17811142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 17821142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 17831142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 17849df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 17859df49d7eSJed Brown } 17869df49d7eSJed Brown 17879df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 17889df49d7eSJed Brown /// given Operator with a non-tensor basis for the active basis 17899df49d7eSJed Brown /// 17909df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 17919df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 17929df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 17939df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 17949df49d7eSJed Brown /// 17959df49d7eSJed Brown /// ``` 17969df49d7eSJed Brown /// # use libceed::prelude::*; 1797*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 17989df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 17999df49d7eSJed Brown /// let ne = 15; 18009df49d7eSJed Brown /// let p_coarse = 3; 18019df49d7eSJed Brown /// let p_fine = 5; 18029df49d7eSJed Brown /// let q = 6; 18039df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 18049df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 18059df49d7eSJed Brown /// 18069df49d7eSJed Brown /// // Vectors 18079df49d7eSJed Brown /// let x_array = (0..ne + 1) 180880a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 180980a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1810c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1811c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 18129df49d7eSJed Brown /// qdata.set_value(0.0); 1813c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 18149df49d7eSJed Brown /// u_coarse.set_value(1.0); 1815c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 18169df49d7eSJed Brown /// u_fine.set_value(1.0); 1817c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 18189df49d7eSJed Brown /// v_coarse.set_value(0.0); 1819c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 18209df49d7eSJed Brown /// v_fine.set_value(0.0); 1821c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 18229df49d7eSJed Brown /// multiplicity.set_value(1.0); 18239df49d7eSJed Brown /// 18249df49d7eSJed Brown /// // Restrictions 18259df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1826c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 18279df49d7eSJed Brown /// 18289df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 18299df49d7eSJed Brown /// for i in 0..ne { 18309df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 18319df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 18329df49d7eSJed Brown /// } 1833c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 18349df49d7eSJed Brown /// 18359df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 18369df49d7eSJed Brown /// for i in 0..ne { 18379df49d7eSJed Brown /// for j in 0..p_coarse { 18389df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 18399df49d7eSJed Brown /// } 18409df49d7eSJed Brown /// } 1841c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 18429df49d7eSJed Brown /// ne, 18439df49d7eSJed Brown /// p_coarse, 18449df49d7eSJed Brown /// 1, 18459df49d7eSJed Brown /// 1, 18469df49d7eSJed Brown /// ndofs_coarse, 18479df49d7eSJed Brown /// MemType::Host, 18489df49d7eSJed Brown /// &indu_coarse, 1849c68be7a2SJeremy L Thompson /// )?; 18509df49d7eSJed Brown /// 18519df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 18529df49d7eSJed Brown /// for i in 0..ne { 18539df49d7eSJed Brown /// for j in 0..p_fine { 18549df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 18559df49d7eSJed Brown /// } 18569df49d7eSJed Brown /// } 1857c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 18589df49d7eSJed Brown /// 18599df49d7eSJed Brown /// // Bases 1860c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1861c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1862c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 18639df49d7eSJed Brown /// 18649df49d7eSJed Brown /// // Build quadrature data 1865c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1866c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1867c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1868c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1869c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1870c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 18719df49d7eSJed Brown /// 18729df49d7eSJed Brown /// // Mass operator 1873c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 18749df49d7eSJed Brown /// let op_mass_fine = ceed 1875c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1876c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1877c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1878c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 18799df49d7eSJed Brown /// 18809df49d7eSJed Brown /// // Multigrid setup 188180a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 18829df49d7eSJed Brown /// { 1883c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 1884c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 1885c68be7a2SJeremy L Thompson /// let basis_c_to_f = 1886c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 18879df49d7eSJed Brown /// for i in 0..p_coarse { 18889df49d7eSJed Brown /// coarse.set_value(0.0); 18899df49d7eSJed Brown /// { 1890e78171edSJeremy L Thompson /// let mut array = coarse.view_mut()?; 18919df49d7eSJed Brown /// array[i] = 1.; 18929df49d7eSJed Brown /// } 1893c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 18949df49d7eSJed Brown /// 1, 18959df49d7eSJed Brown /// TransposeMode::NoTranspose, 18969df49d7eSJed Brown /// EvalMode::Interp, 18979df49d7eSJed Brown /// &coarse, 18989df49d7eSJed Brown /// &mut fine, 1899c68be7a2SJeremy L Thompson /// )?; 1900e78171edSJeremy L Thompson /// let array = fine.view()?; 19019df49d7eSJed Brown /// for j in 0..p_fine { 19029df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 19039df49d7eSJed Brown /// } 19049df49d7eSJed Brown /// } 19059df49d7eSJed Brown /// } 1906c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_H1( 1907c68be7a2SJeremy L Thompson /// &multiplicity, 1908c68be7a2SJeremy L Thompson /// &ru_coarse, 1909c68be7a2SJeremy L Thompson /// &bu_coarse, 1910c68be7a2SJeremy L Thompson /// &interp_c_to_f, 1911c68be7a2SJeremy L Thompson /// )?; 19129df49d7eSJed Brown /// 19139df49d7eSJed Brown /// // Coarse problem 19149df49d7eSJed Brown /// u_coarse.set_value(1.0); 1915c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 19169df49d7eSJed Brown /// 19179df49d7eSJed Brown /// // Check 1918e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 19199df49d7eSJed Brown /// assert!( 192080a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 19219df49d7eSJed Brown /// "Incorrect interval length computed" 19229df49d7eSJed Brown /// ); 19239df49d7eSJed Brown /// 19249df49d7eSJed Brown /// // Prolong 1925c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 19269df49d7eSJed Brown /// 19279df49d7eSJed Brown /// // Fine problem 1928c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 19299df49d7eSJed Brown /// 19309df49d7eSJed Brown /// // Check 1931e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 19329df49d7eSJed Brown /// assert!( 193380a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 19349df49d7eSJed Brown /// "Incorrect interval length computed" 19359df49d7eSJed Brown /// ); 19369df49d7eSJed Brown /// 19379df49d7eSJed Brown /// // Restrict 1938c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 19399df49d7eSJed Brown /// 19409df49d7eSJed Brown /// // Check 1941e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 19429df49d7eSJed Brown /// assert!( 194380a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 19449df49d7eSJed Brown /// "Incorrect interval length computed" 19459df49d7eSJed Brown /// ); 1946c68be7a2SJeremy L Thompson /// # Ok(()) 1947c68be7a2SJeremy L Thompson /// # } 19489df49d7eSJed Brown /// ``` 19499df49d7eSJed Brown pub fn create_multigrid_level_H1( 19509df49d7eSJed Brown &self, 19519df49d7eSJed Brown p_mult_fine: &Vector, 19529df49d7eSJed Brown rstr_coarse: &ElemRestriction, 19539df49d7eSJed Brown basis_coarse: &Basis, 195480a9ef05SNatalie Beams interpCtoF: &[Scalar], 19559df49d7eSJed Brown ) -> crate::Result<(Operator, Operator, Operator)> { 19569df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 19579df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 19589df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 19599df49d7eSJed Brown let ierr = unsafe { 19609df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateH1( 19619df49d7eSJed Brown self.op_core.ptr, 19629df49d7eSJed Brown p_mult_fine.ptr, 19639df49d7eSJed Brown rstr_coarse.ptr, 19649df49d7eSJed Brown basis_coarse.ptr, 19659df49d7eSJed Brown interpCtoF.as_ptr(), 19669df49d7eSJed Brown &mut ptr_coarse, 19679df49d7eSJed Brown &mut ptr_prolong, 19689df49d7eSJed Brown &mut ptr_restrict, 19699df49d7eSJed Brown ) 19709df49d7eSJed Brown }; 19711142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 19721142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 19731142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 19741142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 19759df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 19769df49d7eSJed Brown } 19779df49d7eSJed Brown } 19789df49d7eSJed Brown 19799df49d7eSJed Brown // ----------------------------------------------------------------------------- 19809df49d7eSJed Brown // Composite Operator 19819df49d7eSJed Brown // ----------------------------------------------------------------------------- 19829df49d7eSJed Brown impl<'a> CompositeOperator<'a> { 19839df49d7eSJed Brown // Constructor 19849df49d7eSJed Brown pub fn create(ceed: &'a crate::Ceed) -> crate::Result<Self> { 19859df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 19869df49d7eSJed Brown let ierr = unsafe { bind_ceed::CeedCompositeOperatorCreate(ceed.ptr, &mut ptr) }; 19879df49d7eSJed Brown ceed.check_error(ierr)?; 19889df49d7eSJed Brown Ok(Self { 19891142270cSJeremy L Thompson op_core: OperatorCore { 19901142270cSJeremy L Thompson ptr, 19911142270cSJeremy L Thompson _lifeline: PhantomData, 19921142270cSJeremy L Thompson }, 19939df49d7eSJed Brown }) 19949df49d7eSJed Brown } 19959df49d7eSJed Brown 19969df49d7eSJed Brown /// Apply Operator to a vector 19979df49d7eSJed Brown /// 19989df49d7eSJed Brown /// * `input` - Input Vector 19999df49d7eSJed Brown /// * `output` - Output Vector 20009df49d7eSJed Brown /// 20019df49d7eSJed Brown /// ``` 20029df49d7eSJed Brown /// # use libceed::prelude::*; 2003*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 20049df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 20059df49d7eSJed Brown /// let ne = 4; 20069df49d7eSJed Brown /// let p = 3; 20079df49d7eSJed Brown /// let q = 4; 20089df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 20099df49d7eSJed Brown /// 20109df49d7eSJed Brown /// // Vectors 2011c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 2012c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 20139df49d7eSJed Brown /// qdata_mass.set_value(0.0); 2014c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 20159df49d7eSJed Brown /// qdata_diff.set_value(0.0); 2016c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 20179df49d7eSJed Brown /// u.set_value(1.0); 2018c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 20199df49d7eSJed Brown /// v.set_value(0.0); 20209df49d7eSJed Brown /// 20219df49d7eSJed Brown /// // Restrictions 20229df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 20239df49d7eSJed Brown /// for i in 0..ne { 20249df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 20259df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 20269df49d7eSJed Brown /// } 2027c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 20289df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 20299df49d7eSJed Brown /// for i in 0..ne { 20309df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 20319df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 20329df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 20339df49d7eSJed Brown /// } 2034c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 20359df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2036c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 20379df49d7eSJed Brown /// 20389df49d7eSJed Brown /// // Bases 2039c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2040c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 20419df49d7eSJed Brown /// 20429df49d7eSJed Brown /// // Build quadrature data 2043c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 2044c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 2045c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2046c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2047c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2048c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 20499df49d7eSJed Brown /// 2050c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 2051c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 2052c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2053c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2054c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2055c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 20569df49d7eSJed Brown /// 20579df49d7eSJed Brown /// // Application operator 2058c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 20599df49d7eSJed Brown /// let op_mass = ceed 2060c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2061c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 2062c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 2063c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 20649df49d7eSJed Brown /// 2065c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 20669df49d7eSJed Brown /// let op_diff = ceed 2067c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2068c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 2069c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 2070c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 20719df49d7eSJed Brown /// 20729df49d7eSJed Brown /// let op_composite = ceed 2073c68be7a2SJeremy L Thompson /// .composite_operator()? 2074c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 2075c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 20769df49d7eSJed Brown /// 20779df49d7eSJed Brown /// v.set_value(0.0); 2078c68be7a2SJeremy L Thompson /// op_composite.apply(&u, &mut v)?; 20799df49d7eSJed Brown /// 20809df49d7eSJed Brown /// // Check 2081e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 20829df49d7eSJed Brown /// assert!( 208380a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 20849df49d7eSJed Brown /// "Incorrect interval length computed" 20859df49d7eSJed Brown /// ); 2086c68be7a2SJeremy L Thompson /// # Ok(()) 2087c68be7a2SJeremy L Thompson /// # } 20889df49d7eSJed Brown /// ``` 20899df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 20909df49d7eSJed Brown self.op_core.apply(input, output) 20919df49d7eSJed Brown } 20929df49d7eSJed Brown 20939df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 20949df49d7eSJed Brown /// 20959df49d7eSJed Brown /// * `input` - Input Vector 20969df49d7eSJed Brown /// * `output` - Output Vector 20979df49d7eSJed Brown /// 20989df49d7eSJed Brown /// ``` 20999df49d7eSJed Brown /// # use libceed::prelude::*; 2100*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 21019df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 21029df49d7eSJed Brown /// let ne = 4; 21039df49d7eSJed Brown /// let p = 3; 21049df49d7eSJed Brown /// let q = 4; 21059df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 21069df49d7eSJed Brown /// 21079df49d7eSJed Brown /// // Vectors 2108c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 2109c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 21109df49d7eSJed Brown /// qdata_mass.set_value(0.0); 2111c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 21129df49d7eSJed Brown /// qdata_diff.set_value(0.0); 2113c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 21149df49d7eSJed Brown /// u.set_value(1.0); 2115c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 21169df49d7eSJed Brown /// v.set_value(0.0); 21179df49d7eSJed Brown /// 21189df49d7eSJed Brown /// // Restrictions 21199df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 21209df49d7eSJed Brown /// for i in 0..ne { 21219df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 21229df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 21239df49d7eSJed Brown /// } 2124c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 21259df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 21269df49d7eSJed Brown /// for i in 0..ne { 21279df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 21289df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 21299df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 21309df49d7eSJed Brown /// } 2131c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 21329df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2133c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 21349df49d7eSJed Brown /// 21359df49d7eSJed Brown /// // Bases 2136c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2137c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 21389df49d7eSJed Brown /// 21399df49d7eSJed Brown /// // Build quadrature data 2140c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 2141c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 2142c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2143c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2144c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2145c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 21469df49d7eSJed Brown /// 2147c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 2148c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 2149c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2150c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2151c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2152c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 21539df49d7eSJed Brown /// 21549df49d7eSJed Brown /// // Application operator 2155c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 21569df49d7eSJed Brown /// let op_mass = ceed 2157c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2158c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 2159c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 2160c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 21619df49d7eSJed Brown /// 2162c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 21639df49d7eSJed Brown /// let op_diff = ceed 2164c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2165c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 2166c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 2167c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 21689df49d7eSJed Brown /// 21699df49d7eSJed Brown /// let op_composite = ceed 2170c68be7a2SJeremy L Thompson /// .composite_operator()? 2171c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 2172c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 21739df49d7eSJed Brown /// 21749df49d7eSJed Brown /// v.set_value(1.0); 2175c68be7a2SJeremy L Thompson /// op_composite.apply_add(&u, &mut v)?; 21769df49d7eSJed Brown /// 21779df49d7eSJed Brown /// // Check 2178e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 21799df49d7eSJed Brown /// assert!( 218080a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 21819df49d7eSJed Brown /// "Incorrect interval length computed" 21829df49d7eSJed Brown /// ); 2183c68be7a2SJeremy L Thompson /// # Ok(()) 2184c68be7a2SJeremy L Thompson /// # } 21859df49d7eSJed Brown /// ``` 21869df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 21879df49d7eSJed Brown self.op_core.apply_add(input, output) 21889df49d7eSJed Brown } 21899df49d7eSJed Brown 21909df49d7eSJed Brown /// Add a sub-Operator to a Composite Operator 21919df49d7eSJed Brown /// 21929df49d7eSJed Brown /// * `subop` - Sub-Operator 21939df49d7eSJed Brown /// 21949df49d7eSJed Brown /// ``` 21959df49d7eSJed Brown /// # use libceed::prelude::*; 2196*4d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 21979df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 2198c68be7a2SJeremy L Thompson /// let mut op = ceed.composite_operator()?; 21999df49d7eSJed Brown /// 2200c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 2201c68be7a2SJeremy L Thompson /// let op_mass = ceed.operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?; 2202c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_mass)?; 22039df49d7eSJed Brown /// 2204c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 2205c68be7a2SJeremy L Thompson /// let op_diff = ceed.operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?; 2206c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_diff)?; 2207c68be7a2SJeremy L Thompson /// # Ok(()) 2208c68be7a2SJeremy L Thompson /// # } 22099df49d7eSJed Brown /// ``` 22109df49d7eSJed Brown #[allow(unused_mut)] 22119df49d7eSJed Brown pub fn sub_operator(mut self, subop: &Operator) -> crate::Result<Self> { 22129df49d7eSJed Brown let ierr = 22139df49d7eSJed Brown unsafe { bind_ceed::CeedCompositeOperatorAddSub(self.op_core.ptr, subop.op_core.ptr) }; 22141142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 22159df49d7eSJed Brown Ok(self) 22169df49d7eSJed Brown } 22179df49d7eSJed Brown 22189df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 22199df49d7eSJed Brown /// 22209df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 22219df49d7eSJed Brown /// 22229df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 22239df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 22249df49d7eSJed Brown /// 22259df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 22269df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 22279df49d7eSJed Brown pub fn linear_asssemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 22289df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 22299df49d7eSJed Brown } 22309df49d7eSJed Brown 22319df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 22329df49d7eSJed Brown /// 22339df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 22349df49d7eSJed Brown /// Operator. 22359df49d7eSJed Brown /// 22369df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 22379df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 22389df49d7eSJed Brown /// 22399df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 22409df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 22419df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 22429df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 22439df49d7eSJed Brown } 22449df49d7eSJed Brown 22459df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 22469df49d7eSJed Brown /// 22479df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 22489df49d7eSJed Brown /// 22499df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 22509df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 22519df49d7eSJed Brown /// 22529df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 22539df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 22549df49d7eSJed Brown /// diagonal, provided in row-major form with an 22559df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 22569df49d7eSJed Brown /// this vector are derived from the active vector for 22579df49d7eSJed Brown /// the CeedOperator. The array has shape 22589df49d7eSJed Brown /// `[nodes, component out, component in]`. 22599df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 22609df49d7eSJed Brown &self, 22619df49d7eSJed Brown assembled: &mut Vector, 22629df49d7eSJed Brown ) -> crate::Result<i32> { 22639df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 22649df49d7eSJed Brown } 22659df49d7eSJed Brown 22669df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 22679df49d7eSJed Brown /// 22689df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 22699df49d7eSJed Brown /// 22709df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 22719df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 22729df49d7eSJed Brown /// 22739df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 22749df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 22759df49d7eSJed Brown /// diagonal, provided in row-major form with an 22769df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 22779df49d7eSJed Brown /// this vector are derived from the active vector for 22789df49d7eSJed Brown /// the CeedOperator. The array has shape 22799df49d7eSJed Brown /// `[nodes, component out, component in]`. 22809df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 22819df49d7eSJed Brown &self, 22829df49d7eSJed Brown assembled: &mut Vector, 22839df49d7eSJed Brown ) -> crate::Result<i32> { 22849df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 22859df49d7eSJed Brown } 22869df49d7eSJed Brown } 22879df49d7eSJed Brown 22889df49d7eSJed Brown // ----------------------------------------------------------------------------- 2289