13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 39df49d7eSJed Brown // 43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 59df49d7eSJed Brown // 63d8e8822SJeremy L Thompson // This file is part of CEED: http://github.com/ceed 79df49d7eSJed Brown 89df49d7eSJed Brown //! A Ceed Operator defines the finite/spectral element operator associated to a 99df49d7eSJed Brown //! Ceed QFunction. A Ceed Operator connects Ceed ElemRestrictions, 109df49d7eSJed Brown //! Ceed Bases, and Ceed QFunctions. 119df49d7eSJed Brown 129df49d7eSJed Brown use crate::prelude::*; 139df49d7eSJed Brown 149df49d7eSJed Brown // ----------------------------------------------------------------------------- 157ed177dbSJed Brown // Operator Field context wrapper 1608778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 1708778c6fSJeremy L Thompson #[derive(Debug)] 1808778c6fSJeremy L Thompson pub struct OperatorField<'a> { 1908778c6fSJeremy L Thompson pub(crate) ptr: bind_ceed::CeedOperatorField, 2008778c6fSJeremy L Thompson _lifeline: PhantomData<&'a ()>, 2108778c6fSJeremy L Thompson } 2208778c6fSJeremy L Thompson 2308778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 2408778c6fSJeremy L Thompson // Implementations 2508778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 2608778c6fSJeremy L Thompson impl<'a> OperatorField<'a> { 2708778c6fSJeremy L Thompson /// Get the name of an OperatorField 2808778c6fSJeremy L Thompson /// 2908778c6fSJeremy L Thompson /// ``` 3008778c6fSJeremy L Thompson /// # use libceed::prelude::*; 314d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 3208778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 3308778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 3408778c6fSJeremy L Thompson /// 3508778c6fSJeremy L Thompson /// // Operator field arguments 3608778c6fSJeremy L Thompson /// let ne = 3; 3708778c6fSJeremy L Thompson /// let q = 4 as usize; 3808778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 3908778c6fSJeremy L Thompson /// for i in 0..ne { 4008778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 4108778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 4208778c6fSJeremy L Thompson /// } 4308778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 4408778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 45*d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 4608778c6fSJeremy L Thompson /// 4708778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 4808778c6fSJeremy L Thompson /// 4908778c6fSJeremy L Thompson /// // Operator fields 5008778c6fSJeremy L Thompson /// let op = ceed 5108778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 5208778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 5308778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 5408778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 5508778c6fSJeremy L Thompson /// 5608778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 5708778c6fSJeremy L Thompson /// 5808778c6fSJeremy L Thompson /// assert_eq!(inputs[0].name(), "dx", "Incorrect input name"); 5908778c6fSJeremy L Thompson /// assert_eq!(inputs[1].name(), "weights", "Incorrect input name"); 6008778c6fSJeremy L Thompson /// # Ok(()) 6108778c6fSJeremy L Thompson /// # } 6208778c6fSJeremy L Thompson /// ``` 6308778c6fSJeremy L Thompson pub fn name(&self) -> &str { 6408778c6fSJeremy L Thompson let mut name_ptr: *mut std::os::raw::c_char = std::ptr::null_mut(); 6508778c6fSJeremy L Thompson unsafe { 6608778c6fSJeremy L Thompson bind_ceed::CeedOperatorFieldGetName(self.ptr, &mut name_ptr); 6708778c6fSJeremy L Thompson } 6808778c6fSJeremy L Thompson unsafe { CStr::from_ptr(name_ptr) }.to_str().unwrap() 6908778c6fSJeremy L Thompson } 7008778c6fSJeremy L Thompson 7108778c6fSJeremy L Thompson /// Get the ElemRestriction of an OperatorField 7208778c6fSJeremy L Thompson /// 7308778c6fSJeremy L Thompson /// ``` 7408778c6fSJeremy L Thompson /// # use libceed::prelude::*; 754d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 7608778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 7708778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 7808778c6fSJeremy L Thompson /// 7908778c6fSJeremy L Thompson /// // Operator field arguments 8008778c6fSJeremy L Thompson /// let ne = 3; 8108778c6fSJeremy L Thompson /// let q = 4 as usize; 8208778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 8308778c6fSJeremy L Thompson /// for i in 0..ne { 8408778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 8508778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 8608778c6fSJeremy L Thompson /// } 8708778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 8808778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 89*d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 9008778c6fSJeremy L Thompson /// 9108778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 9208778c6fSJeremy L Thompson /// 9308778c6fSJeremy L Thompson /// // Operator fields 9408778c6fSJeremy L Thompson /// let op = ceed 9508778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 9608778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 9708778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 9808778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 9908778c6fSJeremy L Thompson /// 10008778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 10108778c6fSJeremy L Thompson /// 10208778c6fSJeremy L Thompson /// assert!( 10308778c6fSJeremy L Thompson /// inputs[0].elem_restriction().is_some(), 10408778c6fSJeremy L Thompson /// "Incorrect field ElemRestriction" 10508778c6fSJeremy L Thompson /// ); 10608778c6fSJeremy L Thompson /// if let ElemRestrictionOpt::Some(r) = inputs[0].elem_restriction() { 10708778c6fSJeremy L Thompson /// assert_eq!( 10808778c6fSJeremy L Thompson /// r.num_elements(), 10908778c6fSJeremy L Thompson /// ne, 11008778c6fSJeremy L Thompson /// "Incorrect field ElemRestriction number of elements" 11108778c6fSJeremy L Thompson /// ); 11208778c6fSJeremy L Thompson /// } 11308778c6fSJeremy L Thompson /// 11408778c6fSJeremy L Thompson /// assert!( 11508778c6fSJeremy L Thompson /// inputs[1].elem_restriction().is_none(), 11608778c6fSJeremy L Thompson /// "Incorrect field ElemRestriction" 11708778c6fSJeremy L Thompson /// ); 11808778c6fSJeremy L Thompson /// # Ok(()) 11908778c6fSJeremy L Thompson /// # } 12008778c6fSJeremy L Thompson /// ``` 12108778c6fSJeremy L Thompson pub fn elem_restriction(&self) -> ElemRestrictionOpt { 12208778c6fSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 12308778c6fSJeremy L Thompson unsafe { 12408778c6fSJeremy L Thompson bind_ceed::CeedOperatorFieldGetElemRestriction(self.ptr, &mut ptr); 12508778c6fSJeremy L Thompson } 12608778c6fSJeremy L Thompson if ptr == unsafe { bind_ceed::CEED_ELEMRESTRICTION_NONE } { 12708778c6fSJeremy L Thompson ElemRestrictionOpt::None 12808778c6fSJeremy L Thompson } else { 12908778c6fSJeremy L Thompson let slice = unsafe { 13008778c6fSJeremy L Thompson std::slice::from_raw_parts( 13108778c6fSJeremy L Thompson &ptr as *const bind_ceed::CeedElemRestriction as *const crate::ElemRestriction, 13208778c6fSJeremy L Thompson 1 as usize, 13308778c6fSJeremy L Thompson ) 13408778c6fSJeremy L Thompson }; 13508778c6fSJeremy L Thompson ElemRestrictionOpt::Some(&slice[0]) 13608778c6fSJeremy L Thompson } 13708778c6fSJeremy L Thompson } 13808778c6fSJeremy L Thompson 13908778c6fSJeremy L Thompson /// Get the Basis of an OperatorField 14008778c6fSJeremy L Thompson /// 14108778c6fSJeremy L Thompson /// ``` 14208778c6fSJeremy L Thompson /// # use libceed::prelude::*; 1434d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 14408778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 14508778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 14608778c6fSJeremy L Thompson /// 14708778c6fSJeremy L Thompson /// // Operator field arguments 14808778c6fSJeremy L Thompson /// let ne = 3; 14908778c6fSJeremy L Thompson /// let q = 4 as usize; 15008778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 15108778c6fSJeremy L Thompson /// for i in 0..ne { 15208778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 15308778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 15408778c6fSJeremy L Thompson /// } 15508778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 15608778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 157*d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 15808778c6fSJeremy L Thompson /// 15908778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 16008778c6fSJeremy L Thompson /// 16108778c6fSJeremy L Thompson /// // Operator fields 16208778c6fSJeremy L Thompson /// let op = ceed 16308778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 16408778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 16508778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 16608778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 16708778c6fSJeremy L Thompson /// 16808778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 16908778c6fSJeremy L Thompson /// 17008778c6fSJeremy L Thompson /// assert!(inputs[0].basis().is_some(), "Incorrect field Basis"); 17108778c6fSJeremy L Thompson /// if let BasisOpt::Some(b) = inputs[0].basis() { 17208778c6fSJeremy L Thompson /// assert_eq!( 17308778c6fSJeremy L Thompson /// b.num_quadrature_points(), 17408778c6fSJeremy L Thompson /// q, 17508778c6fSJeremy L Thompson /// "Incorrect field Basis number of quadrature points" 17608778c6fSJeremy L Thompson /// ); 17708778c6fSJeremy L Thompson /// } 17808778c6fSJeremy L Thompson /// assert!(inputs[1].basis().is_some(), "Incorrect field Basis"); 17908778c6fSJeremy L Thompson /// if let BasisOpt::Some(b) = inputs[0].basis() { 18008778c6fSJeremy L Thompson /// assert_eq!( 18108778c6fSJeremy L Thompson /// b.num_quadrature_points(), 18208778c6fSJeremy L Thompson /// q, 18308778c6fSJeremy L Thompson /// "Incorrect field Basis number of quadrature points" 18408778c6fSJeremy L Thompson /// ); 18508778c6fSJeremy L Thompson /// } 18608778c6fSJeremy L Thompson /// 18708778c6fSJeremy L Thompson /// let outputs = op.outputs()?; 18808778c6fSJeremy L Thompson /// 18908778c6fSJeremy L Thompson /// assert!(outputs[0].basis().is_collocated(), "Incorrect field Basis"); 19008778c6fSJeremy L Thompson /// # Ok(()) 19108778c6fSJeremy L Thompson /// # } 19208778c6fSJeremy L Thompson /// ``` 19308778c6fSJeremy L Thompson pub fn basis(&self) -> BasisOpt { 19408778c6fSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 19508778c6fSJeremy L Thompson unsafe { 19608778c6fSJeremy L Thompson bind_ceed::CeedOperatorFieldGetBasis(self.ptr, &mut ptr); 19708778c6fSJeremy L Thompson } 19808778c6fSJeremy L Thompson if ptr == unsafe { bind_ceed::CEED_BASIS_COLLOCATED } { 19908778c6fSJeremy L Thompson BasisOpt::Collocated 20008778c6fSJeremy L Thompson } else { 20108778c6fSJeremy L Thompson let slice = unsafe { 20208778c6fSJeremy L Thompson std::slice::from_raw_parts( 20308778c6fSJeremy L Thompson &ptr as *const bind_ceed::CeedBasis as *const crate::Basis, 20408778c6fSJeremy L Thompson 1 as usize, 20508778c6fSJeremy L Thompson ) 20608778c6fSJeremy L Thompson }; 20708778c6fSJeremy L Thompson BasisOpt::Some(&slice[0]) 20808778c6fSJeremy L Thompson } 20908778c6fSJeremy L Thompson } 21008778c6fSJeremy L Thompson 21108778c6fSJeremy L Thompson /// Get the Vector of an OperatorField 21208778c6fSJeremy L Thompson /// 21308778c6fSJeremy L Thompson /// ``` 21408778c6fSJeremy L Thompson /// # use libceed::prelude::*; 2154d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 21608778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 21708778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 21808778c6fSJeremy L Thompson /// 21908778c6fSJeremy L Thompson /// // Operator field arguments 22008778c6fSJeremy L Thompson /// let ne = 3; 22108778c6fSJeremy L Thompson /// let q = 4 as usize; 22208778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 22308778c6fSJeremy L Thompson /// for i in 0..ne { 22408778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 22508778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 22608778c6fSJeremy L Thompson /// } 22708778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 22808778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 229*d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 23008778c6fSJeremy L Thompson /// 23108778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 23208778c6fSJeremy L Thompson /// 23308778c6fSJeremy L Thompson /// // Operator fields 23408778c6fSJeremy L Thompson /// let op = ceed 23508778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 23608778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 23708778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 23808778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 23908778c6fSJeremy L Thompson /// 24008778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 24108778c6fSJeremy L Thompson /// 24208778c6fSJeremy L Thompson /// assert!(inputs[0].vector().is_active(), "Incorrect field Vector"); 24308778c6fSJeremy L Thompson /// assert!(inputs[1].vector().is_none(), "Incorrect field Vector"); 24408778c6fSJeremy L Thompson /// # Ok(()) 24508778c6fSJeremy L Thompson /// # } 24608778c6fSJeremy L Thompson /// ``` 24708778c6fSJeremy L Thompson pub fn vector(&self) -> VectorOpt { 24808778c6fSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 24908778c6fSJeremy L Thompson unsafe { 25008778c6fSJeremy L Thompson bind_ceed::CeedOperatorFieldGetVector(self.ptr, &mut ptr); 25108778c6fSJeremy L Thompson } 25208778c6fSJeremy L Thompson if ptr == unsafe { bind_ceed::CEED_VECTOR_ACTIVE } { 25308778c6fSJeremy L Thompson VectorOpt::Active 25408778c6fSJeremy L Thompson } else if ptr == unsafe { bind_ceed::CEED_VECTOR_NONE } { 25508778c6fSJeremy L Thompson VectorOpt::None 25608778c6fSJeremy L Thompson } else { 25708778c6fSJeremy L Thompson let slice = unsafe { 25808778c6fSJeremy L Thompson std::slice::from_raw_parts( 25908778c6fSJeremy L Thompson &ptr as *const bind_ceed::CeedVector as *const crate::Vector, 26008778c6fSJeremy L Thompson 1 as usize, 26108778c6fSJeremy L Thompson ) 26208778c6fSJeremy L Thompson }; 26308778c6fSJeremy L Thompson VectorOpt::Some(&slice[0]) 26408778c6fSJeremy L Thompson } 26508778c6fSJeremy L Thompson } 26608778c6fSJeremy L Thompson } 26708778c6fSJeremy L Thompson 26808778c6fSJeremy L Thompson // ----------------------------------------------------------------------------- 2697ed177dbSJed Brown // Operator context wrapper 2709df49d7eSJed Brown // ----------------------------------------------------------------------------- 271c68be7a2SJeremy L Thompson #[derive(Debug)] 2729df49d7eSJed Brown pub(crate) struct OperatorCore<'a> { 2739df49d7eSJed Brown ptr: bind_ceed::CeedOperator, 2741142270cSJeremy L Thompson _lifeline: PhantomData<&'a ()>, 2759df49d7eSJed Brown } 2769df49d7eSJed Brown 277c68be7a2SJeremy L Thompson #[derive(Debug)] 2789df49d7eSJed Brown pub struct Operator<'a> { 2799df49d7eSJed Brown op_core: OperatorCore<'a>, 2809df49d7eSJed Brown } 2819df49d7eSJed Brown 282c68be7a2SJeremy L Thompson #[derive(Debug)] 2839df49d7eSJed Brown pub struct CompositeOperator<'a> { 2849df49d7eSJed Brown op_core: OperatorCore<'a>, 2859df49d7eSJed Brown } 2869df49d7eSJed Brown 2879df49d7eSJed Brown // ----------------------------------------------------------------------------- 2889df49d7eSJed Brown // Destructor 2899df49d7eSJed Brown // ----------------------------------------------------------------------------- 2909df49d7eSJed Brown impl<'a> Drop for OperatorCore<'a> { 2919df49d7eSJed Brown fn drop(&mut self) { 2929df49d7eSJed Brown unsafe { 2939df49d7eSJed Brown bind_ceed::CeedOperatorDestroy(&mut self.ptr); 2949df49d7eSJed Brown } 2959df49d7eSJed Brown } 2969df49d7eSJed Brown } 2979df49d7eSJed Brown 2989df49d7eSJed Brown // ----------------------------------------------------------------------------- 2999df49d7eSJed Brown // Display 3009df49d7eSJed Brown // ----------------------------------------------------------------------------- 3019df49d7eSJed Brown impl<'a> fmt::Display for OperatorCore<'a> { 3029df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 3039df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 3049df49d7eSJed Brown let mut sizeloc = crate::MAX_BUFFER_LENGTH; 3059df49d7eSJed Brown let cstring = unsafe { 3069df49d7eSJed Brown let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc); 3079df49d7eSJed Brown bind_ceed::CeedOperatorView(self.ptr, file); 3089df49d7eSJed Brown bind_ceed::fclose(file); 3099df49d7eSJed Brown CString::from_raw(ptr) 3109df49d7eSJed Brown }; 3119df49d7eSJed Brown cstring.to_string_lossy().fmt(f) 3129df49d7eSJed Brown } 3139df49d7eSJed Brown } 3149df49d7eSJed Brown 3159df49d7eSJed Brown /// View an Operator 3169df49d7eSJed Brown /// 3179df49d7eSJed Brown /// ``` 3189df49d7eSJed Brown /// # use libceed::prelude::*; 3194d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 3209df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 321c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 3229df49d7eSJed Brown /// 3239df49d7eSJed Brown /// // Operator field arguments 3249df49d7eSJed Brown /// let ne = 3; 3259df49d7eSJed Brown /// let q = 4 as usize; 3269df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 3279df49d7eSJed Brown /// for i in 0..ne { 3289df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 3299df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 3309df49d7eSJed Brown /// } 331c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 3329df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 333*d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 3349df49d7eSJed Brown /// 335c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 3369df49d7eSJed Brown /// 3379df49d7eSJed Brown /// // Operator fields 3389df49d7eSJed Brown /// let op = ceed 339c68be7a2SJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 340ea6b5821SJeremy L Thompson /// .name("mass")? 341c68be7a2SJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 342c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 343c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 3449df49d7eSJed Brown /// 3459df49d7eSJed Brown /// println!("{}", op); 346c68be7a2SJeremy L Thompson /// # Ok(()) 347c68be7a2SJeremy L Thompson /// # } 3489df49d7eSJed Brown /// ``` 3499df49d7eSJed Brown impl<'a> fmt::Display for Operator<'a> { 3509df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 3519df49d7eSJed Brown self.op_core.fmt(f) 3529df49d7eSJed Brown } 3539df49d7eSJed Brown } 3549df49d7eSJed Brown 3559df49d7eSJed Brown /// View a composite Operator 3569df49d7eSJed Brown /// 3579df49d7eSJed Brown /// ``` 3589df49d7eSJed Brown /// # use libceed::prelude::*; 3594d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 3609df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 3619df49d7eSJed Brown /// 3629df49d7eSJed Brown /// // Sub operator field arguments 3639df49d7eSJed Brown /// let ne = 3; 3649df49d7eSJed Brown /// let q = 4 as usize; 3659df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 3669df49d7eSJed Brown /// for i in 0..ne { 3679df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 3689df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 3699df49d7eSJed Brown /// } 370c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 3719df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 372*d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 3739df49d7eSJed Brown /// 374c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 3759df49d7eSJed Brown /// 376c68be7a2SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?; 377c68be7a2SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?; 3789df49d7eSJed Brown /// 379c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 3809df49d7eSJed Brown /// let op_mass = ceed 381c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 382ea6b5821SJeremy L Thompson /// .name("Mass term")? 383c68be7a2SJeremy L Thompson /// .field("u", &r, &b, VectorOpt::Active)? 384c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 385c68be7a2SJeremy L Thompson /// .field("v", &r, &b, VectorOpt::Active)?; 3869df49d7eSJed Brown /// 387c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 3889df49d7eSJed Brown /// let op_diff = ceed 389c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 390ea6b5821SJeremy L Thompson /// .name("Poisson term")? 391c68be7a2SJeremy L Thompson /// .field("du", &r, &b, VectorOpt::Active)? 392c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 393c68be7a2SJeremy L Thompson /// .field("dv", &r, &b, VectorOpt::Active)?; 3949df49d7eSJed Brown /// 3959df49d7eSJed Brown /// let op = ceed 396c68be7a2SJeremy L Thompson /// .composite_operator()? 397ea6b5821SJeremy L Thompson /// .name("Screened Poisson")? 398c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 399c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 4009df49d7eSJed Brown /// 4019df49d7eSJed Brown /// println!("{}", op); 402c68be7a2SJeremy L Thompson /// # Ok(()) 403c68be7a2SJeremy L Thompson /// # } 4049df49d7eSJed Brown /// ``` 4059df49d7eSJed Brown impl<'a> fmt::Display for CompositeOperator<'a> { 4069df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 4079df49d7eSJed Brown self.op_core.fmt(f) 4089df49d7eSJed Brown } 4099df49d7eSJed Brown } 4109df49d7eSJed Brown 4119df49d7eSJed Brown // ----------------------------------------------------------------------------- 4129df49d7eSJed Brown // Core functionality 4139df49d7eSJed Brown // ----------------------------------------------------------------------------- 4149df49d7eSJed Brown impl<'a> OperatorCore<'a> { 4151142270cSJeremy L Thompson // Error handling 4161142270cSJeremy L Thompson #[doc(hidden)] 4171142270cSJeremy L Thompson fn check_error(&self, ierr: i32) -> crate::Result<i32> { 4181142270cSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 4191142270cSJeremy L Thompson unsafe { 4201142270cSJeremy L Thompson bind_ceed::CeedOperatorGetCeed(self.ptr, &mut ptr); 4211142270cSJeremy L Thompson } 4221142270cSJeremy L Thompson crate::check_error(ptr, ierr) 4231142270cSJeremy L Thompson } 4241142270cSJeremy L Thompson 4259df49d7eSJed Brown // Common implementations 4266f97ff0aSJeremy L Thompson pub fn check(&self) -> crate::Result<i32> { 4276f97ff0aSJeremy L Thompson let ierr = unsafe { bind_ceed::CeedOperatorCheckReady(self.ptr) }; 4286f97ff0aSJeremy L Thompson self.check_error(ierr) 4296f97ff0aSJeremy L Thompson } 4306f97ff0aSJeremy L Thompson 431ea6b5821SJeremy L Thompson pub fn name(&self, name: &str) -> crate::Result<i32> { 432ea6b5821SJeremy L Thompson let name_c = CString::new(name).expect("CString::new failed"); 433ea6b5821SJeremy L Thompson let ierr = unsafe { bind_ceed::CeedOperatorSetName(self.ptr, name_c.as_ptr()) }; 434ea6b5821SJeremy L Thompson self.check_error(ierr) 435ea6b5821SJeremy L Thompson } 436ea6b5821SJeremy L Thompson 4379df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 4389df49d7eSJed Brown let ierr = unsafe { 4399df49d7eSJed Brown bind_ceed::CeedOperatorApply( 4409df49d7eSJed Brown self.ptr, 4419df49d7eSJed Brown input.ptr, 4429df49d7eSJed Brown output.ptr, 4439df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4449df49d7eSJed Brown ) 4459df49d7eSJed Brown }; 4461142270cSJeremy L Thompson self.check_error(ierr) 4479df49d7eSJed Brown } 4489df49d7eSJed Brown 4499df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 4509df49d7eSJed Brown let ierr = unsafe { 4519df49d7eSJed Brown bind_ceed::CeedOperatorApplyAdd( 4529df49d7eSJed Brown self.ptr, 4539df49d7eSJed Brown input.ptr, 4549df49d7eSJed Brown output.ptr, 4559df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4569df49d7eSJed Brown ) 4579df49d7eSJed Brown }; 4581142270cSJeremy L Thompson self.check_error(ierr) 4599df49d7eSJed Brown } 4609df49d7eSJed Brown 4619df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 4629df49d7eSJed Brown let ierr = unsafe { 4639df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleDiagonal( 4649df49d7eSJed Brown self.ptr, 4659df49d7eSJed Brown assembled.ptr, 4669df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4679df49d7eSJed Brown ) 4689df49d7eSJed Brown }; 4691142270cSJeremy L Thompson self.check_error(ierr) 4709df49d7eSJed Brown } 4719df49d7eSJed Brown 4729df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 4739df49d7eSJed Brown let ierr = unsafe { 4749df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddDiagonal( 4759df49d7eSJed Brown self.ptr, 4769df49d7eSJed Brown assembled.ptr, 4779df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4789df49d7eSJed Brown ) 4799df49d7eSJed Brown }; 4801142270cSJeremy L Thompson self.check_error(ierr) 4819df49d7eSJed Brown } 4829df49d7eSJed Brown 4839df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 4849df49d7eSJed Brown &self, 4859df49d7eSJed Brown assembled: &mut Vector, 4869df49d7eSJed Brown ) -> crate::Result<i32> { 4879df49d7eSJed Brown let ierr = unsafe { 4889df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssemblePointBlockDiagonal( 4899df49d7eSJed Brown self.ptr, 4909df49d7eSJed Brown assembled.ptr, 4919df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4929df49d7eSJed Brown ) 4939df49d7eSJed Brown }; 4941142270cSJeremy L Thompson self.check_error(ierr) 4959df49d7eSJed Brown } 4969df49d7eSJed Brown 4979df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 4989df49d7eSJed Brown &self, 4999df49d7eSJed Brown assembled: &mut Vector, 5009df49d7eSJed Brown ) -> crate::Result<i32> { 5019df49d7eSJed Brown let ierr = unsafe { 5029df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddPointBlockDiagonal( 5039df49d7eSJed Brown self.ptr, 5049df49d7eSJed Brown assembled.ptr, 5059df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 5069df49d7eSJed Brown ) 5079df49d7eSJed Brown }; 5081142270cSJeremy L Thompson self.check_error(ierr) 5099df49d7eSJed Brown } 5109df49d7eSJed Brown } 5119df49d7eSJed Brown 5129df49d7eSJed Brown // ----------------------------------------------------------------------------- 5139df49d7eSJed Brown // Operator 5149df49d7eSJed Brown // ----------------------------------------------------------------------------- 5159df49d7eSJed Brown impl<'a> Operator<'a> { 5169df49d7eSJed Brown // Constructor 5179df49d7eSJed Brown pub fn create<'b>( 518594ef120SJeremy L Thompson ceed: &crate::Ceed, 5199df49d7eSJed Brown qf: impl Into<QFunctionOpt<'b>>, 5209df49d7eSJed Brown dqf: impl Into<QFunctionOpt<'b>>, 5219df49d7eSJed Brown dqfT: impl Into<QFunctionOpt<'b>>, 5229df49d7eSJed Brown ) -> crate::Result<Self> { 5239df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 5249df49d7eSJed Brown let ierr = unsafe { 5259df49d7eSJed Brown bind_ceed::CeedOperatorCreate( 5269df49d7eSJed Brown ceed.ptr, 5279df49d7eSJed Brown qf.into().to_raw(), 5289df49d7eSJed Brown dqf.into().to_raw(), 5299df49d7eSJed Brown dqfT.into().to_raw(), 5309df49d7eSJed Brown &mut ptr, 5319df49d7eSJed Brown ) 5329df49d7eSJed Brown }; 5339df49d7eSJed Brown ceed.check_error(ierr)?; 5349df49d7eSJed Brown Ok(Self { 5351142270cSJeremy L Thompson op_core: OperatorCore { 5361142270cSJeremy L Thompson ptr, 5371142270cSJeremy L Thompson _lifeline: PhantomData, 5381142270cSJeremy L Thompson }, 5399df49d7eSJed Brown }) 5409df49d7eSJed Brown } 5419df49d7eSJed Brown 5421142270cSJeremy L Thompson fn from_raw(ptr: bind_ceed::CeedOperator) -> crate::Result<Self> { 5439df49d7eSJed Brown Ok(Self { 5441142270cSJeremy L Thompson op_core: OperatorCore { 5451142270cSJeremy L Thompson ptr, 5461142270cSJeremy L Thompson _lifeline: PhantomData, 5471142270cSJeremy L Thompson }, 5489df49d7eSJed Brown }) 5499df49d7eSJed Brown } 5509df49d7eSJed Brown 551ea6b5821SJeremy L Thompson /// Set name for Operator printing 552ea6b5821SJeremy L Thompson /// 553ea6b5821SJeremy L Thompson /// * 'name' - Name to set 554ea6b5821SJeremy L Thompson /// 555ea6b5821SJeremy L Thompson /// ``` 556ea6b5821SJeremy L Thompson /// # use libceed::prelude::*; 557ea6b5821SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 558ea6b5821SJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 559ea6b5821SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 560ea6b5821SJeremy L Thompson /// 561ea6b5821SJeremy L Thompson /// // Operator field arguments 562ea6b5821SJeremy L Thompson /// let ne = 3; 563ea6b5821SJeremy L Thompson /// let q = 4 as usize; 564ea6b5821SJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 565ea6b5821SJeremy L Thompson /// for i in 0..ne { 566ea6b5821SJeremy L Thompson /// ind[2 * i + 0] = i as i32; 567ea6b5821SJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 568ea6b5821SJeremy L Thompson /// } 569ea6b5821SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 570ea6b5821SJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 571*d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 572ea6b5821SJeremy L Thompson /// 573ea6b5821SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 574ea6b5821SJeremy L Thompson /// 575ea6b5821SJeremy L Thompson /// // Operator fields 576ea6b5821SJeremy L Thompson /// let op = ceed 577ea6b5821SJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 578ea6b5821SJeremy L Thompson /// .name("mass")? 579ea6b5821SJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 580ea6b5821SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 581ea6b5821SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 582ea6b5821SJeremy L Thompson /// # Ok(()) 583ea6b5821SJeremy L Thompson /// # } 584ea6b5821SJeremy L Thompson /// ``` 585ea6b5821SJeremy L Thompson #[allow(unused_mut)] 586ea6b5821SJeremy L Thompson pub fn name(mut self, name: &str) -> crate::Result<Self> { 587ea6b5821SJeremy L Thompson self.op_core.name(name)?; 588ea6b5821SJeremy L Thompson Ok(self) 589ea6b5821SJeremy L Thompson } 590ea6b5821SJeremy L Thompson 5919df49d7eSJed Brown /// Apply Operator to a vector 5929df49d7eSJed Brown /// 5939df49d7eSJed Brown /// * `input` - Input Vector 5949df49d7eSJed Brown /// * `output` - Output Vector 5959df49d7eSJed Brown /// 5969df49d7eSJed Brown /// ``` 5979df49d7eSJed Brown /// # use libceed::prelude::*; 5984d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 5999df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 6009df49d7eSJed Brown /// let ne = 4; 6019df49d7eSJed Brown /// let p = 3; 6029df49d7eSJed Brown /// let q = 4; 6039df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 6049df49d7eSJed Brown /// 6059df49d7eSJed Brown /// // Vectors 606c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 607c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 6089df49d7eSJed Brown /// qdata.set_value(0.0); 609c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 610c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 6119df49d7eSJed Brown /// v.set_value(0.0); 6129df49d7eSJed Brown /// 6139df49d7eSJed Brown /// // Restrictions 6149df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 6159df49d7eSJed Brown /// for i in 0..ne { 6169df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 6179df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 6189df49d7eSJed Brown /// } 619c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 6209df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 6219df49d7eSJed Brown /// for i in 0..ne { 6229df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 6239df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 6249df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 6259df49d7eSJed Brown /// } 626c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 6279df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 628c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 6299df49d7eSJed Brown /// 6309df49d7eSJed Brown /// // Bases 631c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 632c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 6339df49d7eSJed Brown /// 6349df49d7eSJed Brown /// // Build quadrature data 635c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 636c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 637c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 638c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 639c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 640c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 6419df49d7eSJed Brown /// 6429df49d7eSJed Brown /// // Mass operator 643c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 6449df49d7eSJed Brown /// let op_mass = ceed 645c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 646c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 647c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 648c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 6499df49d7eSJed Brown /// 6509df49d7eSJed Brown /// v.set_value(0.0); 651c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 6529df49d7eSJed Brown /// 6539df49d7eSJed Brown /// // Check 654e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 6559df49d7eSJed Brown /// assert!( 65680a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 6579df49d7eSJed Brown /// "Incorrect interval length computed" 6589df49d7eSJed Brown /// ); 659c68be7a2SJeremy L Thompson /// # Ok(()) 660c68be7a2SJeremy L Thompson /// # } 6619df49d7eSJed Brown /// ``` 6629df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 6639df49d7eSJed Brown self.op_core.apply(input, output) 6649df49d7eSJed Brown } 6659df49d7eSJed Brown 6669df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 6679df49d7eSJed Brown /// 6689df49d7eSJed Brown /// * `input` - Input Vector 6699df49d7eSJed Brown /// * `output` - Output Vector 6709df49d7eSJed Brown /// 6719df49d7eSJed Brown /// ``` 6729df49d7eSJed Brown /// # use libceed::prelude::*; 6734d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 6749df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 6759df49d7eSJed Brown /// let ne = 4; 6769df49d7eSJed Brown /// let p = 3; 6779df49d7eSJed Brown /// let q = 4; 6789df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 6799df49d7eSJed Brown /// 6809df49d7eSJed Brown /// // Vectors 681c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 682c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 6839df49d7eSJed Brown /// qdata.set_value(0.0); 684c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 685c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 6869df49d7eSJed Brown /// 6879df49d7eSJed Brown /// // Restrictions 6889df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 6899df49d7eSJed Brown /// for i in 0..ne { 6909df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 6919df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 6929df49d7eSJed Brown /// } 693c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 6949df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 6959df49d7eSJed Brown /// for i in 0..ne { 6969df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 6979df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 6989df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 6999df49d7eSJed Brown /// } 700c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 7019df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 702c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 7039df49d7eSJed Brown /// 7049df49d7eSJed Brown /// // Bases 705c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 706c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 7079df49d7eSJed Brown /// 7089df49d7eSJed Brown /// // Build quadrature data 709c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 710c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 711c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 712c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 713c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 714c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 7159df49d7eSJed Brown /// 7169df49d7eSJed Brown /// // Mass operator 717c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 7189df49d7eSJed Brown /// let op_mass = ceed 719c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 720c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 721c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 722c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 7239df49d7eSJed Brown /// 7249df49d7eSJed Brown /// v.set_value(1.0); 725c68be7a2SJeremy L Thompson /// op_mass.apply_add(&u, &mut v)?; 7269df49d7eSJed Brown /// 7279df49d7eSJed Brown /// // Check 728e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 7299df49d7eSJed Brown /// assert!( 73080a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 7319df49d7eSJed Brown /// "Incorrect interval length computed and added" 7329df49d7eSJed Brown /// ); 733c68be7a2SJeremy L Thompson /// # Ok(()) 734c68be7a2SJeremy L Thompson /// # } 7359df49d7eSJed Brown /// ``` 7369df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 7379df49d7eSJed Brown self.op_core.apply_add(input, output) 7389df49d7eSJed Brown } 7399df49d7eSJed Brown 7409df49d7eSJed Brown /// Provide a field to a Operator for use by its QFunction 7419df49d7eSJed Brown /// 7429df49d7eSJed Brown /// * `fieldname` - Name of the field (to be matched with the name used by 7439df49d7eSJed Brown /// the QFunction) 7449df49d7eSJed Brown /// * `r` - ElemRestriction 7459df49d7eSJed Brown /// * `b` - Basis in which the field resides or `BasisCollocated` if 7469df49d7eSJed Brown /// collocated with quadrature points 7479df49d7eSJed Brown /// * `v` - Vector to be used by Operator or `VectorActive` if field 7489df49d7eSJed Brown /// is active or `VectorNone` if using `Weight` with the 7499df49d7eSJed Brown /// QFunction 7509df49d7eSJed Brown /// 7519df49d7eSJed Brown /// 7529df49d7eSJed Brown /// ``` 7539df49d7eSJed Brown /// # use libceed::prelude::*; 7544d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 7559df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 756c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 757c68be7a2SJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 7589df49d7eSJed Brown /// 7599df49d7eSJed Brown /// // Operator field arguments 7609df49d7eSJed Brown /// let ne = 3; 7619df49d7eSJed Brown /// let q = 4; 7629df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 7639df49d7eSJed Brown /// for i in 0..ne { 7649df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 7659df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 7669df49d7eSJed Brown /// } 767c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 7689df49d7eSJed Brown /// 769c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 7709df49d7eSJed Brown /// 7719df49d7eSJed Brown /// // Operator field 772c68be7a2SJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 773c68be7a2SJeremy L Thompson /// # Ok(()) 774c68be7a2SJeremy L Thompson /// # } 7759df49d7eSJed Brown /// ``` 7769df49d7eSJed Brown #[allow(unused_mut)] 7779df49d7eSJed Brown pub fn field<'b>( 7789df49d7eSJed Brown mut self, 7799df49d7eSJed Brown fieldname: &str, 7809df49d7eSJed Brown r: impl Into<ElemRestrictionOpt<'b>>, 7819df49d7eSJed Brown b: impl Into<BasisOpt<'b>>, 7829df49d7eSJed Brown v: impl Into<VectorOpt<'b>>, 7839df49d7eSJed Brown ) -> crate::Result<Self> { 7849df49d7eSJed Brown let fieldname = CString::new(fieldname).expect("CString::new failed"); 7859df49d7eSJed Brown let fieldname = fieldname.as_ptr() as *const i8; 7869df49d7eSJed Brown let ierr = unsafe { 7879df49d7eSJed Brown bind_ceed::CeedOperatorSetField( 7889df49d7eSJed Brown self.op_core.ptr, 7899df49d7eSJed Brown fieldname, 7909df49d7eSJed Brown r.into().to_raw(), 7919df49d7eSJed Brown b.into().to_raw(), 7929df49d7eSJed Brown v.into().to_raw(), 7939df49d7eSJed Brown ) 7949df49d7eSJed Brown }; 7951142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 7969df49d7eSJed Brown Ok(self) 7979df49d7eSJed Brown } 7989df49d7eSJed Brown 79908778c6fSJeremy L Thompson /// Get a slice of Operator inputs 80008778c6fSJeremy L Thompson /// 80108778c6fSJeremy L Thompson /// ``` 80208778c6fSJeremy L Thompson /// # use libceed::prelude::*; 8034d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 80408778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 80508778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 80608778c6fSJeremy L Thompson /// 80708778c6fSJeremy L Thompson /// // Operator field arguments 80808778c6fSJeremy L Thompson /// let ne = 3; 80908778c6fSJeremy L Thompson /// let q = 4 as usize; 81008778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 81108778c6fSJeremy L Thompson /// for i in 0..ne { 81208778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 81308778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 81408778c6fSJeremy L Thompson /// } 81508778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 81608778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 817*d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 81808778c6fSJeremy L Thompson /// 81908778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 82008778c6fSJeremy L Thompson /// 82108778c6fSJeremy L Thompson /// // Operator fields 82208778c6fSJeremy L Thompson /// let op = ceed 82308778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 82408778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 82508778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 82608778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 82708778c6fSJeremy L Thompson /// 82808778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 82908778c6fSJeremy L Thompson /// 83008778c6fSJeremy L Thompson /// assert_eq!(inputs.len(), 2, "Incorrect inputs array"); 83108778c6fSJeremy L Thompson /// # Ok(()) 83208778c6fSJeremy L Thompson /// # } 83308778c6fSJeremy L Thompson /// ``` 83408778c6fSJeremy L Thompson pub fn inputs(&self) -> crate::Result<&[crate::OperatorField]> { 83508778c6fSJeremy L Thompson // Get array of raw C pointers for inputs 83608778c6fSJeremy L Thompson let mut num_inputs = 0; 83708778c6fSJeremy L Thompson let mut inputs_ptr = std::ptr::null_mut(); 83808778c6fSJeremy L Thompson let ierr = unsafe { 83908778c6fSJeremy L Thompson bind_ceed::CeedOperatorGetFields( 84008778c6fSJeremy L Thompson self.op_core.ptr, 84108778c6fSJeremy L Thompson &mut num_inputs, 84208778c6fSJeremy L Thompson &mut inputs_ptr, 84308778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt, 84408778c6fSJeremy L Thompson std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField, 84508778c6fSJeremy L Thompson ) 84608778c6fSJeremy L Thompson }; 84708778c6fSJeremy L Thompson self.op_core.check_error(ierr)?; 84808778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice 84908778c6fSJeremy L Thompson let inputs_slice = unsafe { 85008778c6fSJeremy L Thompson std::slice::from_raw_parts( 85108778c6fSJeremy L Thompson inputs_ptr as *const crate::OperatorField, 85208778c6fSJeremy L Thompson num_inputs as usize, 85308778c6fSJeremy L Thompson ) 85408778c6fSJeremy L Thompson }; 85508778c6fSJeremy L Thompson Ok(inputs_slice) 85608778c6fSJeremy L Thompson } 85708778c6fSJeremy L Thompson 85808778c6fSJeremy L Thompson /// Get a slice of Operator outputs 85908778c6fSJeremy L Thompson /// 86008778c6fSJeremy L Thompson /// ``` 86108778c6fSJeremy L Thompson /// # use libceed::prelude::*; 8624d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 86308778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 86408778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 86508778c6fSJeremy L Thompson /// 86608778c6fSJeremy L Thompson /// // Operator field arguments 86708778c6fSJeremy L Thompson /// let ne = 3; 86808778c6fSJeremy L Thompson /// let q = 4 as usize; 86908778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 87008778c6fSJeremy L Thompson /// for i in 0..ne { 87108778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 87208778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 87308778c6fSJeremy L Thompson /// } 87408778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 87508778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 876*d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 87708778c6fSJeremy L Thompson /// 87808778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 87908778c6fSJeremy L Thompson /// 88008778c6fSJeremy L Thompson /// // Operator fields 88108778c6fSJeremy L Thompson /// let op = ceed 88208778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 88308778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 88408778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 88508778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 88608778c6fSJeremy L Thompson /// 88708778c6fSJeremy L Thompson /// let outputs = op.outputs()?; 88808778c6fSJeremy L Thompson /// 88908778c6fSJeremy L Thompson /// assert_eq!(outputs.len(), 1, "Incorrect outputs array"); 89008778c6fSJeremy L Thompson /// # Ok(()) 89108778c6fSJeremy L Thompson /// # } 89208778c6fSJeremy L Thompson /// ``` 89308778c6fSJeremy L Thompson pub fn outputs(&self) -> crate::Result<&[crate::OperatorField]> { 89408778c6fSJeremy L Thompson // Get array of raw C pointers for outputs 89508778c6fSJeremy L Thompson let mut num_outputs = 0; 89608778c6fSJeremy L Thompson let mut outputs_ptr = std::ptr::null_mut(); 89708778c6fSJeremy L Thompson let ierr = unsafe { 89808778c6fSJeremy L Thompson bind_ceed::CeedOperatorGetFields( 89908778c6fSJeremy L Thompson self.op_core.ptr, 90008778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt, 90108778c6fSJeremy L Thompson std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField, 90208778c6fSJeremy L Thompson &mut num_outputs, 90308778c6fSJeremy L Thompson &mut outputs_ptr, 90408778c6fSJeremy L Thompson ) 90508778c6fSJeremy L Thompson }; 90608778c6fSJeremy L Thompson self.op_core.check_error(ierr)?; 90708778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice 90808778c6fSJeremy L Thompson let outputs_slice = unsafe { 90908778c6fSJeremy L Thompson std::slice::from_raw_parts( 91008778c6fSJeremy L Thompson outputs_ptr as *const crate::OperatorField, 91108778c6fSJeremy L Thompson num_outputs as usize, 91208778c6fSJeremy L Thompson ) 91308778c6fSJeremy L Thompson }; 91408778c6fSJeremy L Thompson Ok(outputs_slice) 91508778c6fSJeremy L Thompson } 91608778c6fSJeremy L Thompson 9176f97ff0aSJeremy L Thompson /// Check if Operator is setup correctly 9186f97ff0aSJeremy L Thompson /// 9196f97ff0aSJeremy L Thompson /// ``` 9206f97ff0aSJeremy L Thompson /// # use libceed::prelude::*; 9216f97ff0aSJeremy L Thompson /// # fn main() -> libceed::Result<()> { 9226f97ff0aSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 9236f97ff0aSJeremy L Thompson /// let ne = 4; 9246f97ff0aSJeremy L Thompson /// let p = 3; 9256f97ff0aSJeremy L Thompson /// let q = 4; 9266f97ff0aSJeremy L Thompson /// let ndofs = p * ne - ne + 1; 9276f97ff0aSJeremy L Thompson /// 9286f97ff0aSJeremy L Thompson /// // Restrictions 9296f97ff0aSJeremy L Thompson /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 9306f97ff0aSJeremy L Thompson /// for i in 0..ne { 9316f97ff0aSJeremy L Thompson /// indx[2 * i + 0] = i as i32; 9326f97ff0aSJeremy L Thompson /// indx[2 * i + 1] = (i + 1) as i32; 9336f97ff0aSJeremy L Thompson /// } 9346f97ff0aSJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 9356f97ff0aSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 9366f97ff0aSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 9376f97ff0aSJeremy L Thompson /// 9386f97ff0aSJeremy L Thompson /// // Bases 9396f97ff0aSJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 9406f97ff0aSJeremy L Thompson /// 9416f97ff0aSJeremy L Thompson /// // Build quadrature data 9426f97ff0aSJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 9436f97ff0aSJeremy L Thompson /// let op_build = ceed 9446f97ff0aSJeremy L Thompson /// .operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 9456f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 9466f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 9476f97ff0aSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 9486f97ff0aSJeremy L Thompson /// 9496f97ff0aSJeremy L Thompson /// // Check 9506f97ff0aSJeremy L Thompson /// assert!(op_build.check().is_ok(), "Operator setup incorrectly"); 9516f97ff0aSJeremy L Thompson /// # Ok(()) 9526f97ff0aSJeremy L Thompson /// # } 9536f97ff0aSJeremy L Thompson /// ``` 9546f97ff0aSJeremy L Thompson pub fn check(self) -> crate::Result<Self> { 9556f97ff0aSJeremy L Thompson self.op_core.check()?; 9566f97ff0aSJeremy L Thompson Ok(self) 9576f97ff0aSJeremy L Thompson } 9586f97ff0aSJeremy L Thompson 9593f2759cfSJeremy L Thompson /// Get the number of elements associated with an Operator 9603f2759cfSJeremy L Thompson /// 9613f2759cfSJeremy L Thompson /// 9623f2759cfSJeremy L Thompson /// ``` 9633f2759cfSJeremy L Thompson /// # use libceed::prelude::*; 9644d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 9653f2759cfSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 9663f2759cfSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 9673f2759cfSJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 9683f2759cfSJeremy L Thompson /// 9693f2759cfSJeremy L Thompson /// // Operator field arguments 9703f2759cfSJeremy L Thompson /// let ne = 3; 9713f2759cfSJeremy L Thompson /// let q = 4; 9723f2759cfSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 9733f2759cfSJeremy L Thompson /// for i in 0..ne { 9743f2759cfSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 9753f2759cfSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 9763f2759cfSJeremy L Thompson /// } 9773f2759cfSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 9783f2759cfSJeremy L Thompson /// 9793f2759cfSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 9803f2759cfSJeremy L Thompson /// 9813f2759cfSJeremy L Thompson /// // Operator field 9823f2759cfSJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 9833f2759cfSJeremy L Thompson /// 9843f2759cfSJeremy L Thompson /// // Check number of elements 9853f2759cfSJeremy L Thompson /// assert_eq!(op.num_elements(), ne, "Incorrect number of elements"); 9863f2759cfSJeremy L Thompson /// # Ok(()) 9873f2759cfSJeremy L Thompson /// # } 9883f2759cfSJeremy L Thompson /// ``` 9893f2759cfSJeremy L Thompson pub fn num_elements(&self) -> usize { 9903f2759cfSJeremy L Thompson let mut nelem = 0; 9913f2759cfSJeremy L Thompson unsafe { bind_ceed::CeedOperatorGetNumElements(self.op_core.ptr, &mut nelem) }; 9923f2759cfSJeremy L Thompson usize::try_from(nelem).unwrap() 9933f2759cfSJeremy L Thompson } 9943f2759cfSJeremy L Thompson 9953f2759cfSJeremy L Thompson /// Get the number of quadrature points associated with each element of 9963f2759cfSJeremy L Thompson /// an Operator 9973f2759cfSJeremy L Thompson /// 9983f2759cfSJeremy L Thompson /// 9993f2759cfSJeremy L Thompson /// ``` 10003f2759cfSJeremy L Thompson /// # use libceed::prelude::*; 10014d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 10023f2759cfSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 10033f2759cfSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 10043f2759cfSJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 10053f2759cfSJeremy L Thompson /// 10063f2759cfSJeremy L Thompson /// // Operator field arguments 10073f2759cfSJeremy L Thompson /// let ne = 3; 10083f2759cfSJeremy L Thompson /// let q = 4; 10093f2759cfSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 10103f2759cfSJeremy L Thompson /// for i in 0..ne { 10113f2759cfSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 10123f2759cfSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 10133f2759cfSJeremy L Thompson /// } 10143f2759cfSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 10153f2759cfSJeremy L Thompson /// 10163f2759cfSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 10173f2759cfSJeremy L Thompson /// 10183f2759cfSJeremy L Thompson /// // Operator field 10193f2759cfSJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 10203f2759cfSJeremy L Thompson /// 10213f2759cfSJeremy L Thompson /// // Check number of quadrature points 10223f2759cfSJeremy L Thompson /// assert_eq!( 10233f2759cfSJeremy L Thompson /// op.num_quadrature_points(), 10243f2759cfSJeremy L Thompson /// q, 10253f2759cfSJeremy L Thompson /// "Incorrect number of quadrature points" 10263f2759cfSJeremy L Thompson /// ); 10273f2759cfSJeremy L Thompson /// # Ok(()) 10283f2759cfSJeremy L Thompson /// # } 10293f2759cfSJeremy L Thompson /// ``` 10303f2759cfSJeremy L Thompson pub fn num_quadrature_points(&self) -> usize { 10313f2759cfSJeremy L Thompson let mut Q = 0; 10323f2759cfSJeremy L Thompson unsafe { bind_ceed::CeedOperatorGetNumQuadraturePoints(self.op_core.ptr, &mut Q) }; 10333f2759cfSJeremy L Thompson usize::try_from(Q).unwrap() 10343f2759cfSJeremy L Thompson } 10353f2759cfSJeremy L Thompson 10369df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 10379df49d7eSJed Brown /// 10389df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 10399df49d7eSJed Brown /// 10409df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 10419df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 10429df49d7eSJed Brown /// 10439df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 10449df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 10459df49d7eSJed Brown /// 10469df49d7eSJed Brown /// ``` 10479df49d7eSJed Brown /// # use libceed::prelude::*; 10484d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 10499df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 10509df49d7eSJed Brown /// let ne = 4; 10519df49d7eSJed Brown /// let p = 3; 10529df49d7eSJed Brown /// let q = 4; 10539df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 10549df49d7eSJed Brown /// 10559df49d7eSJed Brown /// // Vectors 1056c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1057c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 10589df49d7eSJed Brown /// qdata.set_value(0.0); 1059c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 10609df49d7eSJed Brown /// u.set_value(1.0); 1061c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 10629df49d7eSJed Brown /// v.set_value(0.0); 10639df49d7eSJed Brown /// 10649df49d7eSJed Brown /// // Restrictions 10659df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 10669df49d7eSJed Brown /// for i in 0..ne { 10679df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 10689df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 10699df49d7eSJed Brown /// } 1070c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 10719df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 10729df49d7eSJed Brown /// for i in 0..ne { 10739df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 10749df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 10759df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 10769df49d7eSJed Brown /// } 1077c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 10789df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1079c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 10809df49d7eSJed Brown /// 10819df49d7eSJed Brown /// // Bases 1082c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1083c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 10849df49d7eSJed Brown /// 10859df49d7eSJed Brown /// // Build quadrature data 1086c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1087c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1088c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1089c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1090c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1091c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 10929df49d7eSJed Brown /// 10939df49d7eSJed Brown /// // Mass operator 1094c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 10959df49d7eSJed Brown /// let op_mass = ceed 1096c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1097c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1098c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1099c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 11009df49d7eSJed Brown /// 11019df49d7eSJed Brown /// // Diagonal 1102c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 11039df49d7eSJed Brown /// diag.set_value(0.0); 1104c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_diagonal(&mut diag)?; 11059df49d7eSJed Brown /// 11069df49d7eSJed Brown /// // Manual diagonal computation 1107c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 11089c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 11099df49d7eSJed Brown /// for i in 0..ndofs { 11109df49d7eSJed Brown /// u.set_value(0.0); 11119df49d7eSJed Brown /// { 1112e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 11139df49d7eSJed Brown /// u_array[i] = 1.; 11149df49d7eSJed Brown /// } 11159df49d7eSJed Brown /// 1116c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 11179df49d7eSJed Brown /// 11189df49d7eSJed Brown /// { 11199c774eddSJeremy L Thompson /// let v_array = v.view()?; 1120e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 11219df49d7eSJed Brown /// true_array[i] = v_array[i]; 11229df49d7eSJed Brown /// } 11239df49d7eSJed Brown /// } 11249df49d7eSJed Brown /// 11259df49d7eSJed Brown /// // Check 1126e78171edSJeremy L Thompson /// diag.view()? 11279df49d7eSJed Brown /// .iter() 1128e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 11299df49d7eSJed Brown /// .for_each(|(computed, actual)| { 11309df49d7eSJed Brown /// assert!( 113180a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 11329df49d7eSJed Brown /// "Diagonal entry incorrect" 11339df49d7eSJed Brown /// ); 11349df49d7eSJed Brown /// }); 1135c68be7a2SJeremy L Thompson /// # Ok(()) 1136c68be7a2SJeremy L Thompson /// # } 11379df49d7eSJed Brown /// ``` 11389df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 11399df49d7eSJed Brown self.op_core.linear_assemble_diagonal(assembled) 11409df49d7eSJed Brown } 11419df49d7eSJed Brown 11429df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 11439df49d7eSJed Brown /// 11449df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 11459df49d7eSJed Brown /// 11469df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 11479df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 11489df49d7eSJed Brown /// 11499df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 11509df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 11519df49d7eSJed Brown /// 11529df49d7eSJed Brown /// 11539df49d7eSJed Brown /// ``` 11549df49d7eSJed Brown /// # use libceed::prelude::*; 11554d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 11569df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 11579df49d7eSJed Brown /// let ne = 4; 11589df49d7eSJed Brown /// let p = 3; 11599df49d7eSJed Brown /// let q = 4; 11609df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 11619df49d7eSJed Brown /// 11629df49d7eSJed Brown /// // Vectors 1163c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1164c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 11659df49d7eSJed Brown /// qdata.set_value(0.0); 1166c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 11679df49d7eSJed Brown /// u.set_value(1.0); 1168c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 11699df49d7eSJed Brown /// v.set_value(0.0); 11709df49d7eSJed Brown /// 11719df49d7eSJed Brown /// // Restrictions 11729df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 11739df49d7eSJed Brown /// for i in 0..ne { 11749df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 11759df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 11769df49d7eSJed Brown /// } 1177c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 11789df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 11799df49d7eSJed Brown /// for i in 0..ne { 11809df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 11819df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 11829df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 11839df49d7eSJed Brown /// } 1184c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 11859df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1186c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 11879df49d7eSJed Brown /// 11889df49d7eSJed Brown /// // Bases 1189c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1190c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 11919df49d7eSJed Brown /// 11929df49d7eSJed Brown /// // Build quadrature data 1193c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1194c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1195c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1196c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1197c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1198c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 11999df49d7eSJed Brown /// 12009df49d7eSJed Brown /// // Mass operator 1201c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 12029df49d7eSJed Brown /// let op_mass = ceed 1203c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1204c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1205c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1206c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 12079df49d7eSJed Brown /// 12089df49d7eSJed Brown /// // Diagonal 1209c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 12109df49d7eSJed Brown /// diag.set_value(1.0); 1211c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_diagonal(&mut diag)?; 12129df49d7eSJed Brown /// 12139df49d7eSJed Brown /// // Manual diagonal computation 1214c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 12159c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 12169df49d7eSJed Brown /// for i in 0..ndofs { 12179df49d7eSJed Brown /// u.set_value(0.0); 12189df49d7eSJed Brown /// { 1219e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 12209df49d7eSJed Brown /// u_array[i] = 1.; 12219df49d7eSJed Brown /// } 12229df49d7eSJed Brown /// 1223c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 12249df49d7eSJed Brown /// 12259df49d7eSJed Brown /// { 12269c774eddSJeremy L Thompson /// let v_array = v.view()?; 1227e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 12289df49d7eSJed Brown /// true_array[i] = v_array[i] + 1.0; 12299df49d7eSJed Brown /// } 12309df49d7eSJed Brown /// } 12319df49d7eSJed Brown /// 12329df49d7eSJed Brown /// // Check 1233e78171edSJeremy L Thompson /// diag.view()? 12349df49d7eSJed Brown /// .iter() 1235e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 12369df49d7eSJed Brown /// .for_each(|(computed, actual)| { 12379df49d7eSJed Brown /// assert!( 123880a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 12399df49d7eSJed Brown /// "Diagonal entry incorrect" 12409df49d7eSJed Brown /// ); 12419df49d7eSJed Brown /// }); 1242c68be7a2SJeremy L Thompson /// # Ok(()) 1243c68be7a2SJeremy L Thompson /// # } 12449df49d7eSJed Brown /// ``` 12459df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 12469df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 12479df49d7eSJed Brown } 12489df49d7eSJed Brown 12499df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 12509df49d7eSJed Brown /// 12519df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 12529df49d7eSJed Brown /// Operator. 12539df49d7eSJed Brown /// 12549df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 12559df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 12569df49d7eSJed Brown /// 12579df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 12589df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 12599df49d7eSJed Brown /// diagonal, provided in row-major form with an 12609df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 12619df49d7eSJed Brown /// this vector are derived from the active vector for 12629df49d7eSJed Brown /// the CeedOperator. The array has shape 12639df49d7eSJed Brown /// `[nodes, component out, component in]`. 12649df49d7eSJed Brown /// 12659df49d7eSJed Brown /// ``` 12669df49d7eSJed Brown /// # use libceed::prelude::*; 12674d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 12689df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 12699df49d7eSJed Brown /// let ne = 4; 12709df49d7eSJed Brown /// let p = 3; 12719df49d7eSJed Brown /// let q = 4; 12729df49d7eSJed Brown /// let ncomp = 2; 12739df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 12749df49d7eSJed Brown /// 12759df49d7eSJed Brown /// // Vectors 1276c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1277c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 12789df49d7eSJed Brown /// qdata.set_value(0.0); 1279c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 12809df49d7eSJed Brown /// u.set_value(1.0); 1281c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 12829df49d7eSJed Brown /// v.set_value(0.0); 12839df49d7eSJed Brown /// 12849df49d7eSJed Brown /// // Restrictions 12859df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 12869df49d7eSJed Brown /// for i in 0..ne { 12879df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 12889df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 12899df49d7eSJed Brown /// } 1290c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 12919df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 12929df49d7eSJed Brown /// for i in 0..ne { 12939df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 12949df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 12959df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 12969df49d7eSJed Brown /// } 1297c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 12989df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1299c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 13009df49d7eSJed Brown /// 13019df49d7eSJed Brown /// // Bases 1302c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1303c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 13049df49d7eSJed Brown /// 13059df49d7eSJed Brown /// // Build quadrature data 1306c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1307c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1308c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1309c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1310c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1311c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 13129df49d7eSJed Brown /// 13139df49d7eSJed Brown /// // Mass operator 13149df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 13159df49d7eSJed Brown /// // Number of quadrature points 13169df49d7eSJed Brown /// let q = qdata.len(); 13179df49d7eSJed Brown /// 13189df49d7eSJed Brown /// // Iterate over quadrature points 13199df49d7eSJed Brown /// for i in 0..q { 13209df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 13219df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 13229df49d7eSJed Brown /// } 13239df49d7eSJed Brown /// 13249df49d7eSJed Brown /// // Return clean error code 13259df49d7eSJed Brown /// 0 13269df49d7eSJed Brown /// }; 13279df49d7eSJed Brown /// 13289df49d7eSJed Brown /// let qf_mass = ceed 1329c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 1330c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 1331c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 1332c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 13339df49d7eSJed Brown /// 13349df49d7eSJed Brown /// let op_mass = ceed 1335c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1336c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1337c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1338c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 13399df49d7eSJed Brown /// 13409df49d7eSJed Brown /// // Diagonal 1341c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 13429df49d7eSJed Brown /// diag.set_value(0.0); 1343c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_point_block_diagonal(&mut diag)?; 13449df49d7eSJed Brown /// 13459df49d7eSJed Brown /// // Manual diagonal computation 1346c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 13479c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 13489df49d7eSJed Brown /// for i in 0..ndofs { 13499df49d7eSJed Brown /// for j in 0..ncomp { 13509df49d7eSJed Brown /// u.set_value(0.0); 13519df49d7eSJed Brown /// { 1352e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 13539df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 13549df49d7eSJed Brown /// } 13559df49d7eSJed Brown /// 1356c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 13579df49d7eSJed Brown /// 13589df49d7eSJed Brown /// { 13599c774eddSJeremy L Thompson /// let v_array = v.view()?; 1360e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 13619df49d7eSJed Brown /// for k in 0..ncomp { 13629df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 13639df49d7eSJed Brown /// } 13649df49d7eSJed Brown /// } 13659df49d7eSJed Brown /// } 13669df49d7eSJed Brown /// } 13679df49d7eSJed Brown /// 13689df49d7eSJed Brown /// // Check 1369e78171edSJeremy L Thompson /// diag.view()? 13709df49d7eSJed Brown /// .iter() 1371e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 13729df49d7eSJed Brown /// .for_each(|(computed, actual)| { 13739df49d7eSJed Brown /// assert!( 137480a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 13759df49d7eSJed Brown /// "Diagonal entry incorrect" 13769df49d7eSJed Brown /// ); 13779df49d7eSJed Brown /// }); 1378c68be7a2SJeremy L Thompson /// # Ok(()) 1379c68be7a2SJeremy L Thompson /// # } 13809df49d7eSJed Brown /// ``` 13819df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 13829df49d7eSJed Brown &self, 13839df49d7eSJed Brown assembled: &mut Vector, 13849df49d7eSJed Brown ) -> crate::Result<i32> { 13859df49d7eSJed Brown self.op_core.linear_assemble_point_block_diagonal(assembled) 13869df49d7eSJed Brown } 13879df49d7eSJed Brown 13889df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 13899df49d7eSJed Brown /// 13909df49d7eSJed Brown /// This sums into a Vector with the point block diagonal of a linear 13919df49d7eSJed Brown /// Operator. 13929df49d7eSJed Brown /// 13939df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 13949df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 13959df49d7eSJed Brown /// 13969df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 13979df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 13989df49d7eSJed Brown /// diagonal, provided in row-major form with an 13999df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 14009df49d7eSJed Brown /// this vector are derived from the active vector for 14019df49d7eSJed Brown /// the CeedOperator. The array has shape 14029df49d7eSJed Brown /// `[nodes, component out, component in]`. 14039df49d7eSJed Brown /// 14049df49d7eSJed Brown /// ``` 14059df49d7eSJed Brown /// # use libceed::prelude::*; 14064d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 14079df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 14089df49d7eSJed Brown /// let ne = 4; 14099df49d7eSJed Brown /// let p = 3; 14109df49d7eSJed Brown /// let q = 4; 14119df49d7eSJed Brown /// let ncomp = 2; 14129df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 14139df49d7eSJed Brown /// 14149df49d7eSJed Brown /// // Vectors 1415c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1416c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 14179df49d7eSJed Brown /// qdata.set_value(0.0); 1418c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 14199df49d7eSJed Brown /// u.set_value(1.0); 1420c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 14219df49d7eSJed Brown /// v.set_value(0.0); 14229df49d7eSJed Brown /// 14239df49d7eSJed Brown /// // Restrictions 14249df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 14259df49d7eSJed Brown /// for i in 0..ne { 14269df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 14279df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 14289df49d7eSJed Brown /// } 1429c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 14309df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 14319df49d7eSJed Brown /// for i in 0..ne { 14329df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 14339df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 14349df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 14359df49d7eSJed Brown /// } 1436c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 14379df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1438c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 14399df49d7eSJed Brown /// 14409df49d7eSJed Brown /// // Bases 1441c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1442c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 14439df49d7eSJed Brown /// 14449df49d7eSJed Brown /// // Build quadrature data 1445c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1446c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1447c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1448c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1449c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1450c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 14519df49d7eSJed Brown /// 14529df49d7eSJed Brown /// // Mass operator 14539df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 14549df49d7eSJed Brown /// // Number of quadrature points 14559df49d7eSJed Brown /// let q = qdata.len(); 14569df49d7eSJed Brown /// 14579df49d7eSJed Brown /// // Iterate over quadrature points 14589df49d7eSJed Brown /// for i in 0..q { 14599df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 14609df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 14619df49d7eSJed Brown /// } 14629df49d7eSJed Brown /// 14639df49d7eSJed Brown /// // Return clean error code 14649df49d7eSJed Brown /// 0 14659df49d7eSJed Brown /// }; 14669df49d7eSJed Brown /// 14679df49d7eSJed Brown /// let qf_mass = ceed 1468c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 1469c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 1470c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 1471c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 14729df49d7eSJed Brown /// 14739df49d7eSJed Brown /// let op_mass = ceed 1474c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1475c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1476c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1477c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 14789df49d7eSJed Brown /// 14799df49d7eSJed Brown /// // Diagonal 1480c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 14819df49d7eSJed Brown /// diag.set_value(1.0); 1482c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_point_block_diagonal(&mut diag)?; 14839df49d7eSJed Brown /// 14849df49d7eSJed Brown /// // Manual diagonal computation 1485c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 14869c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 14879df49d7eSJed Brown /// for i in 0..ndofs { 14889df49d7eSJed Brown /// for j in 0..ncomp { 14899df49d7eSJed Brown /// u.set_value(0.0); 14909df49d7eSJed Brown /// { 1491e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 14929df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 14939df49d7eSJed Brown /// } 14949df49d7eSJed Brown /// 1495c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 14969df49d7eSJed Brown /// 14979df49d7eSJed Brown /// { 14989c774eddSJeremy L Thompson /// let v_array = v.view()?; 1499e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 15009df49d7eSJed Brown /// for k in 0..ncomp { 15019df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 15029df49d7eSJed Brown /// } 15039df49d7eSJed Brown /// } 15049df49d7eSJed Brown /// } 15059df49d7eSJed Brown /// } 15069df49d7eSJed Brown /// 15079df49d7eSJed Brown /// // Check 1508e78171edSJeremy L Thompson /// diag.view()? 15099df49d7eSJed Brown /// .iter() 1510e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 15119df49d7eSJed Brown /// .for_each(|(computed, actual)| { 15129df49d7eSJed Brown /// assert!( 151380a9ef05SNatalie Beams /// (*computed - 1.0 - *actual).abs() < 10.0 * libceed::EPSILON, 15149df49d7eSJed Brown /// "Diagonal entry incorrect" 15159df49d7eSJed Brown /// ); 15169df49d7eSJed Brown /// }); 1517c68be7a2SJeremy L Thompson /// # Ok(()) 1518c68be7a2SJeremy L Thompson /// # } 15199df49d7eSJed Brown /// ``` 15209df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 15219df49d7eSJed Brown &self, 15229df49d7eSJed Brown assembled: &mut Vector, 15239df49d7eSJed Brown ) -> crate::Result<i32> { 15249df49d7eSJed Brown self.op_core 15259df49d7eSJed Brown .linear_assemble_add_point_block_diagonal(assembled) 15269df49d7eSJed Brown } 15279df49d7eSJed Brown 15289df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 15299df49d7eSJed Brown /// given Operator, creating the prolongation basis from the fine and 15309df49d7eSJed Brown /// coarse grid interpolation 15319df49d7eSJed Brown /// 15329df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 15339df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 15349df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 15359df49d7eSJed Brown /// 15369df49d7eSJed Brown /// ``` 15379df49d7eSJed Brown /// # use libceed::prelude::*; 15384d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 15399df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 15409df49d7eSJed Brown /// let ne = 15; 15419df49d7eSJed Brown /// let p_coarse = 3; 15429df49d7eSJed Brown /// let p_fine = 5; 15439df49d7eSJed Brown /// let q = 6; 15449df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 15459df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 15469df49d7eSJed Brown /// 15479df49d7eSJed Brown /// // Vectors 15489df49d7eSJed Brown /// let x_array = (0..ne + 1) 154980a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 155080a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1551c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1552c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 15539df49d7eSJed Brown /// qdata.set_value(0.0); 1554c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 15559df49d7eSJed Brown /// u_coarse.set_value(1.0); 1556c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 15579df49d7eSJed Brown /// u_fine.set_value(1.0); 1558c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 15599df49d7eSJed Brown /// v_coarse.set_value(0.0); 1560c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 15619df49d7eSJed Brown /// v_fine.set_value(0.0); 1562c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 15639df49d7eSJed Brown /// multiplicity.set_value(1.0); 15649df49d7eSJed Brown /// 15659df49d7eSJed Brown /// // Restrictions 15669df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1567c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 15689df49d7eSJed Brown /// 15699df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 15709df49d7eSJed Brown /// for i in 0..ne { 15719df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 15729df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 15739df49d7eSJed Brown /// } 1574c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 15759df49d7eSJed Brown /// 15769df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 15779df49d7eSJed Brown /// for i in 0..ne { 15789df49d7eSJed Brown /// for j in 0..p_coarse { 15799df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 15809df49d7eSJed Brown /// } 15819df49d7eSJed Brown /// } 1582c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 15839df49d7eSJed Brown /// ne, 15849df49d7eSJed Brown /// p_coarse, 15859df49d7eSJed Brown /// 1, 15869df49d7eSJed Brown /// 1, 15879df49d7eSJed Brown /// ndofs_coarse, 15889df49d7eSJed Brown /// MemType::Host, 15899df49d7eSJed Brown /// &indu_coarse, 1590c68be7a2SJeremy L Thompson /// )?; 15919df49d7eSJed Brown /// 15929df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 15939df49d7eSJed Brown /// for i in 0..ne { 15949df49d7eSJed Brown /// for j in 0..p_fine { 15959df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 15969df49d7eSJed Brown /// } 15979df49d7eSJed Brown /// } 1598c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 15999df49d7eSJed Brown /// 16009df49d7eSJed Brown /// // Bases 1601c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1602c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1603c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 16049df49d7eSJed Brown /// 16059df49d7eSJed Brown /// // Build quadrature data 1606c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1607c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1608c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1609c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1610c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1611c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 16129df49d7eSJed Brown /// 16139df49d7eSJed Brown /// // Mass operator 1614c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 16159df49d7eSJed Brown /// let op_mass_fine = ceed 1616c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1617c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1618c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1619c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 16209df49d7eSJed Brown /// 16219df49d7eSJed Brown /// // Multigrid setup 1622c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = 1623c68be7a2SJeremy L Thompson /// op_mass_fine.create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)?; 16249df49d7eSJed Brown /// 16259df49d7eSJed Brown /// // Coarse problem 16269df49d7eSJed Brown /// u_coarse.set_value(1.0); 1627c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 16289df49d7eSJed Brown /// 16299df49d7eSJed Brown /// // Check 1630e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 16319df49d7eSJed Brown /// assert!( 163280a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 16339df49d7eSJed Brown /// "Incorrect interval length computed" 16349df49d7eSJed Brown /// ); 16359df49d7eSJed Brown /// 16369df49d7eSJed Brown /// // Prolong 1637c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 16389df49d7eSJed Brown /// 16399df49d7eSJed Brown /// // Fine problem 1640c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 16419df49d7eSJed Brown /// 16429df49d7eSJed Brown /// // Check 1643e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 16449df49d7eSJed Brown /// assert!( 164580a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 16469df49d7eSJed Brown /// "Incorrect interval length computed" 16479df49d7eSJed Brown /// ); 16489df49d7eSJed Brown /// 16499df49d7eSJed Brown /// // Restrict 1650c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 16519df49d7eSJed Brown /// 16529df49d7eSJed Brown /// // Check 1653e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 16549df49d7eSJed Brown /// assert!( 165580a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 16569df49d7eSJed Brown /// "Incorrect interval length computed" 16579df49d7eSJed Brown /// ); 1658c68be7a2SJeremy L Thompson /// # Ok(()) 1659c68be7a2SJeremy L Thompson /// # } 16609df49d7eSJed Brown /// ``` 1661594ef120SJeremy L Thompson pub fn create_multigrid_level<'b>( 16629df49d7eSJed Brown &self, 16639df49d7eSJed Brown p_mult_fine: &Vector, 16649df49d7eSJed Brown rstr_coarse: &ElemRestriction, 16659df49d7eSJed Brown basis_coarse: &Basis, 1666594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 16679df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 16689df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 16699df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 16709df49d7eSJed Brown let ierr = unsafe { 16719df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreate( 16729df49d7eSJed Brown self.op_core.ptr, 16739df49d7eSJed Brown p_mult_fine.ptr, 16749df49d7eSJed Brown rstr_coarse.ptr, 16759df49d7eSJed Brown basis_coarse.ptr, 16769df49d7eSJed Brown &mut ptr_coarse, 16779df49d7eSJed Brown &mut ptr_prolong, 16789df49d7eSJed Brown &mut ptr_restrict, 16799df49d7eSJed Brown ) 16809df49d7eSJed Brown }; 16811142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 16821142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 16831142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 16841142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 16859df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 16869df49d7eSJed Brown } 16879df49d7eSJed Brown 16889df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 16899df49d7eSJed Brown /// given Operator with a tensor basis for the active basis 16909df49d7eSJed Brown /// 16919df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 16929df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 16939df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 16949df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 16959df49d7eSJed Brown /// 16969df49d7eSJed Brown /// ``` 16979df49d7eSJed Brown /// # use libceed::prelude::*; 16984d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 16999df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 17009df49d7eSJed Brown /// let ne = 15; 17019df49d7eSJed Brown /// let p_coarse = 3; 17029df49d7eSJed Brown /// let p_fine = 5; 17039df49d7eSJed Brown /// let q = 6; 17049df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 17059df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 17069df49d7eSJed Brown /// 17079df49d7eSJed Brown /// // Vectors 17089df49d7eSJed Brown /// let x_array = (0..ne + 1) 170980a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 171080a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1711c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1712c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 17139df49d7eSJed Brown /// qdata.set_value(0.0); 1714c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 17159df49d7eSJed Brown /// u_coarse.set_value(1.0); 1716c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 17179df49d7eSJed Brown /// u_fine.set_value(1.0); 1718c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 17199df49d7eSJed Brown /// v_coarse.set_value(0.0); 1720c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 17219df49d7eSJed Brown /// v_fine.set_value(0.0); 1722c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 17239df49d7eSJed Brown /// multiplicity.set_value(1.0); 17249df49d7eSJed Brown /// 17259df49d7eSJed Brown /// // Restrictions 17269df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1727c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 17289df49d7eSJed Brown /// 17299df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 17309df49d7eSJed Brown /// for i in 0..ne { 17319df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 17329df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 17339df49d7eSJed Brown /// } 1734c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 17359df49d7eSJed Brown /// 17369df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 17379df49d7eSJed Brown /// for i in 0..ne { 17389df49d7eSJed Brown /// for j in 0..p_coarse { 17399df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 17409df49d7eSJed Brown /// } 17419df49d7eSJed Brown /// } 1742c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 17439df49d7eSJed Brown /// ne, 17449df49d7eSJed Brown /// p_coarse, 17459df49d7eSJed Brown /// 1, 17469df49d7eSJed Brown /// 1, 17479df49d7eSJed Brown /// ndofs_coarse, 17489df49d7eSJed Brown /// MemType::Host, 17499df49d7eSJed Brown /// &indu_coarse, 1750c68be7a2SJeremy L Thompson /// )?; 17519df49d7eSJed Brown /// 17529df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 17539df49d7eSJed Brown /// for i in 0..ne { 17549df49d7eSJed Brown /// for j in 0..p_fine { 17559df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 17569df49d7eSJed Brown /// } 17579df49d7eSJed Brown /// } 1758c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 17599df49d7eSJed Brown /// 17609df49d7eSJed Brown /// // Bases 1761c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1762c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1763c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 17649df49d7eSJed Brown /// 17659df49d7eSJed Brown /// // Build quadrature data 1766c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1767c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1768c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1769c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1770c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1771c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 17729df49d7eSJed Brown /// 17739df49d7eSJed Brown /// // Mass operator 1774c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 17759df49d7eSJed Brown /// let op_mass_fine = ceed 1776c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1777c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1778c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1779c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 17809df49d7eSJed Brown /// 17819df49d7eSJed Brown /// // Multigrid setup 178280a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 17839df49d7eSJed Brown /// { 1784c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 1785c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 1786c68be7a2SJeremy L Thompson /// let basis_c_to_f = 1787c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 17889df49d7eSJed Brown /// for i in 0..p_coarse { 17899df49d7eSJed Brown /// coarse.set_value(0.0); 17909df49d7eSJed Brown /// { 1791e78171edSJeremy L Thompson /// let mut array = coarse.view_mut()?; 17929df49d7eSJed Brown /// array[i] = 1.; 17939df49d7eSJed Brown /// } 1794c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 17959df49d7eSJed Brown /// 1, 17969df49d7eSJed Brown /// TransposeMode::NoTranspose, 17979df49d7eSJed Brown /// EvalMode::Interp, 17989df49d7eSJed Brown /// &coarse, 17999df49d7eSJed Brown /// &mut fine, 1800c68be7a2SJeremy L Thompson /// )?; 1801e78171edSJeremy L Thompson /// let array = fine.view()?; 18029df49d7eSJed Brown /// for j in 0..p_fine { 18039df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 18049df49d7eSJed Brown /// } 18059df49d7eSJed Brown /// } 18069df49d7eSJed Brown /// } 1807c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_tensor_H1( 1808c68be7a2SJeremy L Thompson /// &multiplicity, 1809c68be7a2SJeremy L Thompson /// &ru_coarse, 1810c68be7a2SJeremy L Thompson /// &bu_coarse, 1811c68be7a2SJeremy L Thompson /// &interp_c_to_f, 1812c68be7a2SJeremy L Thompson /// )?; 18139df49d7eSJed Brown /// 18149df49d7eSJed Brown /// // Coarse problem 18159df49d7eSJed Brown /// u_coarse.set_value(1.0); 1816c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 18179df49d7eSJed Brown /// 18189df49d7eSJed Brown /// // Check 1819e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 18209df49d7eSJed Brown /// assert!( 182180a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 18229df49d7eSJed Brown /// "Incorrect interval length computed" 18239df49d7eSJed Brown /// ); 18249df49d7eSJed Brown /// 18259df49d7eSJed Brown /// // Prolong 1826c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 18279df49d7eSJed Brown /// 18289df49d7eSJed Brown /// // Fine problem 1829c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 18309df49d7eSJed Brown /// 18319df49d7eSJed Brown /// // Check 1832e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 18339df49d7eSJed Brown /// assert!( 183480a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 18359df49d7eSJed Brown /// "Incorrect interval length computed" 18369df49d7eSJed Brown /// ); 18379df49d7eSJed Brown /// 18389df49d7eSJed Brown /// // Restrict 1839c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 18409df49d7eSJed Brown /// 18419df49d7eSJed Brown /// // Check 1842e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 18439df49d7eSJed Brown /// assert!( 184480a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 18459df49d7eSJed Brown /// "Incorrect interval length computed" 18469df49d7eSJed Brown /// ); 1847c68be7a2SJeremy L Thompson /// # Ok(()) 1848c68be7a2SJeremy L Thompson /// # } 18499df49d7eSJed Brown /// ``` 1850594ef120SJeremy L Thompson pub fn create_multigrid_level_tensor_H1<'b>( 18519df49d7eSJed Brown &self, 18529df49d7eSJed Brown p_mult_fine: &Vector, 18539df49d7eSJed Brown rstr_coarse: &ElemRestriction, 18549df49d7eSJed Brown basis_coarse: &Basis, 185580a9ef05SNatalie Beams interpCtoF: &Vec<Scalar>, 1856594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 18579df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 18589df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 18599df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 18609df49d7eSJed Brown let ierr = unsafe { 18619df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateTensorH1( 18629df49d7eSJed Brown self.op_core.ptr, 18639df49d7eSJed Brown p_mult_fine.ptr, 18649df49d7eSJed Brown rstr_coarse.ptr, 18659df49d7eSJed Brown basis_coarse.ptr, 18669df49d7eSJed Brown interpCtoF.as_ptr(), 18679df49d7eSJed Brown &mut ptr_coarse, 18689df49d7eSJed Brown &mut ptr_prolong, 18699df49d7eSJed Brown &mut ptr_restrict, 18709df49d7eSJed Brown ) 18719df49d7eSJed Brown }; 18721142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 18731142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 18741142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 18751142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 18769df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 18779df49d7eSJed Brown } 18789df49d7eSJed Brown 18799df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 18809df49d7eSJed Brown /// given Operator with a non-tensor basis for the active basis 18819df49d7eSJed Brown /// 18829df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 18839df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 18849df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 18859df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 18869df49d7eSJed Brown /// 18879df49d7eSJed Brown /// ``` 18889df49d7eSJed Brown /// # use libceed::prelude::*; 18894d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 18909df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 18919df49d7eSJed Brown /// let ne = 15; 18929df49d7eSJed Brown /// let p_coarse = 3; 18939df49d7eSJed Brown /// let p_fine = 5; 18949df49d7eSJed Brown /// let q = 6; 18959df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 18969df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 18979df49d7eSJed Brown /// 18989df49d7eSJed Brown /// // Vectors 18999df49d7eSJed Brown /// let x_array = (0..ne + 1) 190080a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 190180a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1902c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1903c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 19049df49d7eSJed Brown /// qdata.set_value(0.0); 1905c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 19069df49d7eSJed Brown /// u_coarse.set_value(1.0); 1907c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 19089df49d7eSJed Brown /// u_fine.set_value(1.0); 1909c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 19109df49d7eSJed Brown /// v_coarse.set_value(0.0); 1911c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 19129df49d7eSJed Brown /// v_fine.set_value(0.0); 1913c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 19149df49d7eSJed Brown /// multiplicity.set_value(1.0); 19159df49d7eSJed Brown /// 19169df49d7eSJed Brown /// // Restrictions 19179df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1918c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 19199df49d7eSJed Brown /// 19209df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 19219df49d7eSJed Brown /// for i in 0..ne { 19229df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 19239df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 19249df49d7eSJed Brown /// } 1925c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 19269df49d7eSJed Brown /// 19279df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 19289df49d7eSJed Brown /// for i in 0..ne { 19299df49d7eSJed Brown /// for j in 0..p_coarse { 19309df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 19319df49d7eSJed Brown /// } 19329df49d7eSJed Brown /// } 1933c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 19349df49d7eSJed Brown /// ne, 19359df49d7eSJed Brown /// p_coarse, 19369df49d7eSJed Brown /// 1, 19379df49d7eSJed Brown /// 1, 19389df49d7eSJed Brown /// ndofs_coarse, 19399df49d7eSJed Brown /// MemType::Host, 19409df49d7eSJed Brown /// &indu_coarse, 1941c68be7a2SJeremy L Thompson /// )?; 19429df49d7eSJed Brown /// 19439df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 19449df49d7eSJed Brown /// for i in 0..ne { 19459df49d7eSJed Brown /// for j in 0..p_fine { 19469df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 19479df49d7eSJed Brown /// } 19489df49d7eSJed Brown /// } 1949c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 19509df49d7eSJed Brown /// 19519df49d7eSJed Brown /// // Bases 1952c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1953c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1954c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 19559df49d7eSJed Brown /// 19569df49d7eSJed Brown /// // Build quadrature data 1957c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1958c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1959c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1960c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1961c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1962c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 19639df49d7eSJed Brown /// 19649df49d7eSJed Brown /// // Mass operator 1965c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 19669df49d7eSJed Brown /// let op_mass_fine = ceed 1967c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1968c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1969c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1970c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 19719df49d7eSJed Brown /// 19729df49d7eSJed Brown /// // Multigrid setup 197380a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 19749df49d7eSJed Brown /// { 1975c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 1976c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 1977c68be7a2SJeremy L Thompson /// let basis_c_to_f = 1978c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 19799df49d7eSJed Brown /// for i in 0..p_coarse { 19809df49d7eSJed Brown /// coarse.set_value(0.0); 19819df49d7eSJed Brown /// { 1982e78171edSJeremy L Thompson /// let mut array = coarse.view_mut()?; 19839df49d7eSJed Brown /// array[i] = 1.; 19849df49d7eSJed Brown /// } 1985c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 19869df49d7eSJed Brown /// 1, 19879df49d7eSJed Brown /// TransposeMode::NoTranspose, 19889df49d7eSJed Brown /// EvalMode::Interp, 19899df49d7eSJed Brown /// &coarse, 19909df49d7eSJed Brown /// &mut fine, 1991c68be7a2SJeremy L Thompson /// )?; 1992e78171edSJeremy L Thompson /// let array = fine.view()?; 19939df49d7eSJed Brown /// for j in 0..p_fine { 19949df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 19959df49d7eSJed Brown /// } 19969df49d7eSJed Brown /// } 19979df49d7eSJed Brown /// } 1998c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_H1( 1999c68be7a2SJeremy L Thompson /// &multiplicity, 2000c68be7a2SJeremy L Thompson /// &ru_coarse, 2001c68be7a2SJeremy L Thompson /// &bu_coarse, 2002c68be7a2SJeremy L Thompson /// &interp_c_to_f, 2003c68be7a2SJeremy L Thompson /// )?; 20049df49d7eSJed Brown /// 20059df49d7eSJed Brown /// // Coarse problem 20069df49d7eSJed Brown /// u_coarse.set_value(1.0); 2007c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 20089df49d7eSJed Brown /// 20099df49d7eSJed Brown /// // Check 2010e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 20119df49d7eSJed Brown /// assert!( 201280a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 20139df49d7eSJed Brown /// "Incorrect interval length computed" 20149df49d7eSJed Brown /// ); 20159df49d7eSJed Brown /// 20169df49d7eSJed Brown /// // Prolong 2017c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 20189df49d7eSJed Brown /// 20199df49d7eSJed Brown /// // Fine problem 2020c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 20219df49d7eSJed Brown /// 20229df49d7eSJed Brown /// // Check 2023e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 20249df49d7eSJed Brown /// assert!( 202580a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 20269df49d7eSJed Brown /// "Incorrect interval length computed" 20279df49d7eSJed Brown /// ); 20289df49d7eSJed Brown /// 20299df49d7eSJed Brown /// // Restrict 2030c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 20319df49d7eSJed Brown /// 20329df49d7eSJed Brown /// // Check 2033e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 20349df49d7eSJed Brown /// assert!( 203580a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 20369df49d7eSJed Brown /// "Incorrect interval length computed" 20379df49d7eSJed Brown /// ); 2038c68be7a2SJeremy L Thompson /// # Ok(()) 2039c68be7a2SJeremy L Thompson /// # } 20409df49d7eSJed Brown /// ``` 2041594ef120SJeremy L Thompson pub fn create_multigrid_level_H1<'b>( 20429df49d7eSJed Brown &self, 20439df49d7eSJed Brown p_mult_fine: &Vector, 20449df49d7eSJed Brown rstr_coarse: &ElemRestriction, 20459df49d7eSJed Brown basis_coarse: &Basis, 204680a9ef05SNatalie Beams interpCtoF: &[Scalar], 2047594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 20489df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 20499df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 20509df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 20519df49d7eSJed Brown let ierr = unsafe { 20529df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateH1( 20539df49d7eSJed Brown self.op_core.ptr, 20549df49d7eSJed Brown p_mult_fine.ptr, 20559df49d7eSJed Brown rstr_coarse.ptr, 20569df49d7eSJed Brown basis_coarse.ptr, 20579df49d7eSJed Brown interpCtoF.as_ptr(), 20589df49d7eSJed Brown &mut ptr_coarse, 20599df49d7eSJed Brown &mut ptr_prolong, 20609df49d7eSJed Brown &mut ptr_restrict, 20619df49d7eSJed Brown ) 20629df49d7eSJed Brown }; 20631142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 20641142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 20651142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 20661142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 20679df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 20689df49d7eSJed Brown } 20699df49d7eSJed Brown } 20709df49d7eSJed Brown 20719df49d7eSJed Brown // ----------------------------------------------------------------------------- 20729df49d7eSJed Brown // Composite Operator 20739df49d7eSJed Brown // ----------------------------------------------------------------------------- 20749df49d7eSJed Brown impl<'a> CompositeOperator<'a> { 20759df49d7eSJed Brown // Constructor 2076594ef120SJeremy L Thompson pub fn create(ceed: &crate::Ceed) -> crate::Result<Self> { 20779df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 20789df49d7eSJed Brown let ierr = unsafe { bind_ceed::CeedCompositeOperatorCreate(ceed.ptr, &mut ptr) }; 20799df49d7eSJed Brown ceed.check_error(ierr)?; 20809df49d7eSJed Brown Ok(Self { 20811142270cSJeremy L Thompson op_core: OperatorCore { 20821142270cSJeremy L Thompson ptr, 20831142270cSJeremy L Thompson _lifeline: PhantomData, 20841142270cSJeremy L Thompson }, 20859df49d7eSJed Brown }) 20869df49d7eSJed Brown } 20879df49d7eSJed Brown 2088ea6b5821SJeremy L Thompson /// Set name for CompositeOperator printing 2089ea6b5821SJeremy L Thompson /// 2090ea6b5821SJeremy L Thompson /// * 'name' - Name to set 2091ea6b5821SJeremy L Thompson /// 2092ea6b5821SJeremy L Thompson /// ``` 2093ea6b5821SJeremy L Thompson /// # use libceed::prelude::*; 2094ea6b5821SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 2095ea6b5821SJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 2096ea6b5821SJeremy L Thompson /// 2097ea6b5821SJeremy L Thompson /// // Sub operator field arguments 2098ea6b5821SJeremy L Thompson /// let ne = 3; 2099ea6b5821SJeremy L Thompson /// let q = 4 as usize; 2100ea6b5821SJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 2101ea6b5821SJeremy L Thompson /// for i in 0..ne { 2102ea6b5821SJeremy L Thompson /// ind[2 * i + 0] = i as i32; 2103ea6b5821SJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 2104ea6b5821SJeremy L Thompson /// } 2105ea6b5821SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 2106ea6b5821SJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2107*d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 2108ea6b5821SJeremy L Thompson /// 2109ea6b5821SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2110ea6b5821SJeremy L Thompson /// 2111ea6b5821SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?; 2112ea6b5821SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?; 2113ea6b5821SJeremy L Thompson /// 2114ea6b5821SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 2115ea6b5821SJeremy L Thompson /// let op_mass = ceed 2116ea6b5821SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2117ea6b5821SJeremy L Thompson /// .name("Mass term")? 2118ea6b5821SJeremy L Thompson /// .field("u", &r, &b, VectorOpt::Active)? 2119ea6b5821SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 2120ea6b5821SJeremy L Thompson /// .field("v", &r, &b, VectorOpt::Active)?; 2121ea6b5821SJeremy L Thompson /// 2122ea6b5821SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 2123ea6b5821SJeremy L Thompson /// let op_diff = ceed 2124ea6b5821SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2125ea6b5821SJeremy L Thompson /// .name("Poisson term")? 2126ea6b5821SJeremy L Thompson /// .field("du", &r, &b, VectorOpt::Active)? 2127ea6b5821SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 2128ea6b5821SJeremy L Thompson /// .field("dv", &r, &b, VectorOpt::Active)?; 2129ea6b5821SJeremy L Thompson /// 2130ea6b5821SJeremy L Thompson /// let op = ceed 2131ea6b5821SJeremy L Thompson /// .composite_operator()? 2132ea6b5821SJeremy L Thompson /// .name("Screened Poisson")? 2133ea6b5821SJeremy L Thompson /// .sub_operator(&op_mass)? 2134ea6b5821SJeremy L Thompson /// .sub_operator(&op_diff)?; 2135ea6b5821SJeremy L Thompson /// # Ok(()) 2136ea6b5821SJeremy L Thompson /// # } 2137ea6b5821SJeremy L Thompson /// ``` 2138ea6b5821SJeremy L Thompson #[allow(unused_mut)] 2139ea6b5821SJeremy L Thompson pub fn name(mut self, name: &str) -> crate::Result<Self> { 2140ea6b5821SJeremy L Thompson self.op_core.name(name)?; 2141ea6b5821SJeremy L Thompson Ok(self) 2142ea6b5821SJeremy L Thompson } 2143ea6b5821SJeremy L Thompson 21449df49d7eSJed Brown /// Apply Operator to a vector 21459df49d7eSJed Brown /// 2146ea6b5821SJeremy L Thompson /// * `input` - Inpuht Vector 21479df49d7eSJed Brown /// * `output` - Output Vector 21489df49d7eSJed Brown /// 21499df49d7eSJed Brown /// ``` 21509df49d7eSJed Brown /// # use libceed::prelude::*; 21514d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 21529df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 21539df49d7eSJed Brown /// let ne = 4; 21549df49d7eSJed Brown /// let p = 3; 21559df49d7eSJed Brown /// let q = 4; 21569df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 21579df49d7eSJed Brown /// 21589df49d7eSJed Brown /// // Vectors 2159c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 2160c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 21619df49d7eSJed Brown /// qdata_mass.set_value(0.0); 2162c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 21639df49d7eSJed Brown /// qdata_diff.set_value(0.0); 2164c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 21659df49d7eSJed Brown /// u.set_value(1.0); 2166c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 21679df49d7eSJed Brown /// v.set_value(0.0); 21689df49d7eSJed Brown /// 21699df49d7eSJed Brown /// // Restrictions 21709df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 21719df49d7eSJed Brown /// for i in 0..ne { 21729df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 21739df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 21749df49d7eSJed Brown /// } 2175c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 21769df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 21779df49d7eSJed Brown /// for i in 0..ne { 21789df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 21799df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 21809df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 21819df49d7eSJed Brown /// } 2182c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 21839df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2184c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 21859df49d7eSJed Brown /// 21869df49d7eSJed Brown /// // Bases 2187c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2188c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 21899df49d7eSJed Brown /// 21909df49d7eSJed Brown /// // Build quadrature data 2191c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 2192c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 2193c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2194c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2195c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2196c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 21979df49d7eSJed Brown /// 2198c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 2199c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 2200c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2201c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2202c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2203c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 22049df49d7eSJed Brown /// 22059df49d7eSJed Brown /// // Application operator 2206c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 22079df49d7eSJed Brown /// let op_mass = ceed 2208c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2209c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 2210c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 2211c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 22129df49d7eSJed Brown /// 2213c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 22149df49d7eSJed Brown /// let op_diff = ceed 2215c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2216c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 2217c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 2218c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 22199df49d7eSJed Brown /// 22209df49d7eSJed Brown /// let op_composite = ceed 2221c68be7a2SJeremy L Thompson /// .composite_operator()? 2222c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 2223c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 22249df49d7eSJed Brown /// 22259df49d7eSJed Brown /// v.set_value(0.0); 2226c68be7a2SJeremy L Thompson /// op_composite.apply(&u, &mut v)?; 22279df49d7eSJed Brown /// 22289df49d7eSJed Brown /// // Check 2229e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 22309df49d7eSJed Brown /// assert!( 223180a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 22329df49d7eSJed Brown /// "Incorrect interval length computed" 22339df49d7eSJed Brown /// ); 2234c68be7a2SJeremy L Thompson /// # Ok(()) 2235c68be7a2SJeremy L Thompson /// # } 22369df49d7eSJed Brown /// ``` 22379df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 22389df49d7eSJed Brown self.op_core.apply(input, output) 22399df49d7eSJed Brown } 22409df49d7eSJed Brown 22419df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 22429df49d7eSJed Brown /// 22439df49d7eSJed Brown /// * `input` - Input Vector 22449df49d7eSJed Brown /// * `output` - Output Vector 22459df49d7eSJed Brown /// 22469df49d7eSJed Brown /// ``` 22479df49d7eSJed Brown /// # use libceed::prelude::*; 22484d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 22499df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 22509df49d7eSJed Brown /// let ne = 4; 22519df49d7eSJed Brown /// let p = 3; 22529df49d7eSJed Brown /// let q = 4; 22539df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 22549df49d7eSJed Brown /// 22559df49d7eSJed Brown /// // Vectors 2256c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 2257c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 22589df49d7eSJed Brown /// qdata_mass.set_value(0.0); 2259c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 22609df49d7eSJed Brown /// qdata_diff.set_value(0.0); 2261c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 22629df49d7eSJed Brown /// u.set_value(1.0); 2263c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 22649df49d7eSJed Brown /// v.set_value(0.0); 22659df49d7eSJed Brown /// 22669df49d7eSJed Brown /// // Restrictions 22679df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 22689df49d7eSJed Brown /// for i in 0..ne { 22699df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 22709df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 22719df49d7eSJed Brown /// } 2272c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 22739df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 22749df49d7eSJed Brown /// for i in 0..ne { 22759df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 22769df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 22779df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 22789df49d7eSJed Brown /// } 2279c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 22809df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2281c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 22829df49d7eSJed Brown /// 22839df49d7eSJed Brown /// // Bases 2284c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2285c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 22869df49d7eSJed Brown /// 22879df49d7eSJed Brown /// // Build quadrature data 2288c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 2289c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 2290c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2291c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2292c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2293c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 22949df49d7eSJed Brown /// 2295c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 2296c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 2297c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2298c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2299c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2300c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 23019df49d7eSJed Brown /// 23029df49d7eSJed Brown /// // Application operator 2303c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 23049df49d7eSJed Brown /// let op_mass = ceed 2305c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2306c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 2307c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 2308c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 23099df49d7eSJed Brown /// 2310c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 23119df49d7eSJed Brown /// let op_diff = ceed 2312c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2313c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 2314c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 2315c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 23169df49d7eSJed Brown /// 23179df49d7eSJed Brown /// let op_composite = ceed 2318c68be7a2SJeremy L Thompson /// .composite_operator()? 2319c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 2320c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 23219df49d7eSJed Brown /// 23229df49d7eSJed Brown /// v.set_value(1.0); 2323c68be7a2SJeremy L Thompson /// op_composite.apply_add(&u, &mut v)?; 23249df49d7eSJed Brown /// 23259df49d7eSJed Brown /// // Check 2326e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 23279df49d7eSJed Brown /// assert!( 232880a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 23299df49d7eSJed Brown /// "Incorrect interval length computed" 23309df49d7eSJed Brown /// ); 2331c68be7a2SJeremy L Thompson /// # Ok(()) 2332c68be7a2SJeremy L Thompson /// # } 23339df49d7eSJed Brown /// ``` 23349df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 23359df49d7eSJed Brown self.op_core.apply_add(input, output) 23369df49d7eSJed Brown } 23379df49d7eSJed Brown 23389df49d7eSJed Brown /// Add a sub-Operator to a Composite Operator 23399df49d7eSJed Brown /// 23409df49d7eSJed Brown /// * `subop` - Sub-Operator 23419df49d7eSJed Brown /// 23429df49d7eSJed Brown /// ``` 23439df49d7eSJed Brown /// # use libceed::prelude::*; 23444d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 23459df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 2346c68be7a2SJeremy L Thompson /// let mut op = ceed.composite_operator()?; 23479df49d7eSJed Brown /// 2348c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 2349c68be7a2SJeremy L Thompson /// let op_mass = ceed.operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?; 2350c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_mass)?; 23519df49d7eSJed Brown /// 2352c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 2353c68be7a2SJeremy L Thompson /// let op_diff = ceed.operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?; 2354c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_diff)?; 2355c68be7a2SJeremy L Thompson /// # Ok(()) 2356c68be7a2SJeremy L Thompson /// # } 23579df49d7eSJed Brown /// ``` 23589df49d7eSJed Brown #[allow(unused_mut)] 23599df49d7eSJed Brown pub fn sub_operator(mut self, subop: &Operator) -> crate::Result<Self> { 23609df49d7eSJed Brown let ierr = 23619df49d7eSJed Brown unsafe { bind_ceed::CeedCompositeOperatorAddSub(self.op_core.ptr, subop.op_core.ptr) }; 23621142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 23639df49d7eSJed Brown Ok(self) 23649df49d7eSJed Brown } 23659df49d7eSJed Brown 23666f97ff0aSJeremy L Thompson /// Check if CompositeOperator is setup correctly 23676f97ff0aSJeremy L Thompson /// 23686f97ff0aSJeremy L Thompson /// ``` 23696f97ff0aSJeremy L Thompson /// # use libceed::prelude::*; 23706f97ff0aSJeremy L Thompson /// # fn main() -> libceed::Result<()> { 23716f97ff0aSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 23726f97ff0aSJeremy L Thompson /// let ne = 4; 23736f97ff0aSJeremy L Thompson /// let p = 3; 23746f97ff0aSJeremy L Thompson /// let q = 4; 23756f97ff0aSJeremy L Thompson /// let ndofs = p * ne - ne + 1; 23766f97ff0aSJeremy L Thompson /// 23776f97ff0aSJeremy L Thompson /// // Restrictions 23786f97ff0aSJeremy L Thompson /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 23796f97ff0aSJeremy L Thompson /// for i in 0..ne { 23806f97ff0aSJeremy L Thompson /// indx[2 * i + 0] = i as i32; 23816f97ff0aSJeremy L Thompson /// indx[2 * i + 1] = (i + 1) as i32; 23826f97ff0aSJeremy L Thompson /// } 23836f97ff0aSJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 23846f97ff0aSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 23856f97ff0aSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 23866f97ff0aSJeremy L Thompson /// 23876f97ff0aSJeremy L Thompson /// // Bases 23886f97ff0aSJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 23896f97ff0aSJeremy L Thompson /// 23906f97ff0aSJeremy L Thompson /// // Build quadrature data 23916f97ff0aSJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 23926f97ff0aSJeremy L Thompson /// let op_build_mass = ceed 23936f97ff0aSJeremy L Thompson /// .operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 23946f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 23956f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 23966f97ff0aSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 23976f97ff0aSJeremy L Thompson /// 23986f97ff0aSJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 23996f97ff0aSJeremy L Thompson /// let op_build_diff = ceed 24006f97ff0aSJeremy L Thompson /// .operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 24016f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 24026f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 24036f97ff0aSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 24046f97ff0aSJeremy L Thompson /// 24056f97ff0aSJeremy L Thompson /// let op_build = ceed 24066f97ff0aSJeremy L Thompson /// .composite_operator()? 24076f97ff0aSJeremy L Thompson /// .sub_operator(&op_build_mass)? 24086f97ff0aSJeremy L Thompson /// .sub_operator(&op_build_diff)?; 24096f97ff0aSJeremy L Thompson /// 24106f97ff0aSJeremy L Thompson /// // Check 24116f97ff0aSJeremy L Thompson /// assert!(op_build.check().is_ok(), "Operator setup incorrectly"); 24126f97ff0aSJeremy L Thompson /// # Ok(()) 24136f97ff0aSJeremy L Thompson /// # } 24146f97ff0aSJeremy L Thompson /// ``` 24156f97ff0aSJeremy L Thompson pub fn check(self) -> crate::Result<Self> { 24166f97ff0aSJeremy L Thompson self.op_core.check()?; 24176f97ff0aSJeremy L Thompson Ok(self) 24186f97ff0aSJeremy L Thompson } 24196f97ff0aSJeremy L Thompson 24209df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 24219df49d7eSJed Brown /// 24229df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 24239df49d7eSJed Brown /// 24249df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 24259df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 24269df49d7eSJed Brown /// 24279df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 24289df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 2429b748b478SJeremy L Thompson pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 24309df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 24319df49d7eSJed Brown } 24329df49d7eSJed Brown 24339df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 24349df49d7eSJed Brown /// 24359df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 24369df49d7eSJed Brown /// Operator. 24379df49d7eSJed Brown /// 24389df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 24399df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 24409df49d7eSJed Brown /// 24419df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 24429df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 24439df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 24449df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 24459df49d7eSJed Brown } 24469df49d7eSJed Brown 24479df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 24489df49d7eSJed Brown /// 24499df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 24509df49d7eSJed Brown /// 24519df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 24529df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 24539df49d7eSJed Brown /// 24549df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 24559df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 24569df49d7eSJed Brown /// diagonal, provided in row-major form with an 24579df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 24589df49d7eSJed Brown /// this vector are derived from the active vector for 24599df49d7eSJed Brown /// the CeedOperator. The array has shape 24609df49d7eSJed Brown /// `[nodes, component out, component in]`. 24619df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 24629df49d7eSJed Brown &self, 24639df49d7eSJed Brown assembled: &mut Vector, 24649df49d7eSJed Brown ) -> crate::Result<i32> { 24659df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 24669df49d7eSJed Brown } 24679df49d7eSJed Brown 24689df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 24699df49d7eSJed Brown /// 24709df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 24719df49d7eSJed Brown /// 24729df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 24739df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 24749df49d7eSJed Brown /// 24759df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 24769df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 24779df49d7eSJed Brown /// diagonal, provided in row-major form with an 24789df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 24799df49d7eSJed Brown /// this vector are derived from the active vector for 24809df49d7eSJed Brown /// the CeedOperator. The array has shape 24819df49d7eSJed Brown /// `[nodes, component out, component in]`. 24829df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 24839df49d7eSJed Brown &self, 24849df49d7eSJed Brown assembled: &mut Vector, 24859df49d7eSJed Brown ) -> crate::Result<i32> { 24869df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 24879df49d7eSJed Brown } 24889df49d7eSJed Brown } 24899df49d7eSJed Brown 24909df49d7eSJed Brown // ----------------------------------------------------------------------------- 2491