1*3d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2*3d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 39df49d7eSJed Brown // 4*3d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 59df49d7eSJed Brown // 6*3d8e8822SJeremy 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]; 4508778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 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]; 8908778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 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]; 15708778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 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]; 22908778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 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]; 333c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 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)? 340c68be7a2SJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 341c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 342c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 3439df49d7eSJed Brown /// 3449df49d7eSJed Brown /// println!("{}", op); 345c68be7a2SJeremy L Thompson /// # Ok(()) 346c68be7a2SJeremy L Thompson /// # } 3479df49d7eSJed Brown /// ``` 3489df49d7eSJed Brown impl<'a> fmt::Display for Operator<'a> { 3499df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 3509df49d7eSJed Brown self.op_core.fmt(f) 3519df49d7eSJed Brown } 3529df49d7eSJed Brown } 3539df49d7eSJed Brown 3549df49d7eSJed Brown /// View a composite Operator 3559df49d7eSJed Brown /// 3569df49d7eSJed Brown /// ``` 3579df49d7eSJed Brown /// # use libceed::prelude::*; 3584d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 3599df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 3609df49d7eSJed Brown /// 3619df49d7eSJed Brown /// // Sub operator field arguments 3629df49d7eSJed Brown /// let ne = 3; 3639df49d7eSJed Brown /// let q = 4 as usize; 3649df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 3659df49d7eSJed Brown /// for i in 0..ne { 3669df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 3679df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 3689df49d7eSJed Brown /// } 369c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 3709df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 371c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 3729df49d7eSJed Brown /// 373c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 3749df49d7eSJed Brown /// 375c68be7a2SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?; 376c68be7a2SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?; 3779df49d7eSJed Brown /// 378c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 3799df49d7eSJed Brown /// let op_mass = ceed 380c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 381c68be7a2SJeremy L Thompson /// .field("u", &r, &b, VectorOpt::Active)? 382c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 383c68be7a2SJeremy L Thompson /// .field("v", &r, &b, VectorOpt::Active)?; 3849df49d7eSJed Brown /// 385c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 3869df49d7eSJed Brown /// let op_diff = ceed 387c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 388c68be7a2SJeremy L Thompson /// .field("du", &r, &b, VectorOpt::Active)? 389c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 390c68be7a2SJeremy L Thompson /// .field("dv", &r, &b, VectorOpt::Active)?; 3919df49d7eSJed Brown /// 3929df49d7eSJed Brown /// let op = ceed 393c68be7a2SJeremy L Thompson /// .composite_operator()? 394c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 395c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 3969df49d7eSJed Brown /// 3979df49d7eSJed Brown /// println!("{}", op); 398c68be7a2SJeremy L Thompson /// # Ok(()) 399c68be7a2SJeremy L Thompson /// # } 4009df49d7eSJed Brown /// ``` 4019df49d7eSJed Brown impl<'a> fmt::Display for CompositeOperator<'a> { 4029df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 4039df49d7eSJed Brown self.op_core.fmt(f) 4049df49d7eSJed Brown } 4059df49d7eSJed Brown } 4069df49d7eSJed Brown 4079df49d7eSJed Brown // ----------------------------------------------------------------------------- 4089df49d7eSJed Brown // Core functionality 4099df49d7eSJed Brown // ----------------------------------------------------------------------------- 4109df49d7eSJed Brown impl<'a> OperatorCore<'a> { 4111142270cSJeremy L Thompson // Error handling 4121142270cSJeremy L Thompson #[doc(hidden)] 4131142270cSJeremy L Thompson fn check_error(&self, ierr: i32) -> crate::Result<i32> { 4141142270cSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 4151142270cSJeremy L Thompson unsafe { 4161142270cSJeremy L Thompson bind_ceed::CeedOperatorGetCeed(self.ptr, &mut ptr); 4171142270cSJeremy L Thompson } 4181142270cSJeremy L Thompson crate::check_error(ptr, ierr) 4191142270cSJeremy L Thompson } 4201142270cSJeremy L Thompson 4219df49d7eSJed Brown // Common implementations 4226f97ff0aSJeremy L Thompson pub fn check(&self) -> crate::Result<i32> { 4236f97ff0aSJeremy L Thompson let ierr = unsafe { bind_ceed::CeedOperatorCheckReady(self.ptr) }; 4246f97ff0aSJeremy L Thompson self.check_error(ierr) 4256f97ff0aSJeremy L Thompson } 4266f97ff0aSJeremy L Thompson 4279df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 4289df49d7eSJed Brown let ierr = unsafe { 4299df49d7eSJed Brown bind_ceed::CeedOperatorApply( 4309df49d7eSJed Brown self.ptr, 4319df49d7eSJed Brown input.ptr, 4329df49d7eSJed Brown output.ptr, 4339df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4349df49d7eSJed Brown ) 4359df49d7eSJed Brown }; 4361142270cSJeremy L Thompson self.check_error(ierr) 4379df49d7eSJed Brown } 4389df49d7eSJed Brown 4399df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 4409df49d7eSJed Brown let ierr = unsafe { 4419df49d7eSJed Brown bind_ceed::CeedOperatorApplyAdd( 4429df49d7eSJed Brown self.ptr, 4439df49d7eSJed Brown input.ptr, 4449df49d7eSJed Brown output.ptr, 4459df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4469df49d7eSJed Brown ) 4479df49d7eSJed Brown }; 4481142270cSJeremy L Thompson self.check_error(ierr) 4499df49d7eSJed Brown } 4509df49d7eSJed Brown 4519df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 4529df49d7eSJed Brown let ierr = unsafe { 4539df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleDiagonal( 4549df49d7eSJed Brown self.ptr, 4559df49d7eSJed Brown assembled.ptr, 4569df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4579df49d7eSJed Brown ) 4589df49d7eSJed Brown }; 4591142270cSJeremy L Thompson self.check_error(ierr) 4609df49d7eSJed Brown } 4619df49d7eSJed Brown 4629df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 4639df49d7eSJed Brown let ierr = unsafe { 4649df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddDiagonal( 4659df49d7eSJed Brown self.ptr, 4669df49d7eSJed Brown assembled.ptr, 4679df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4689df49d7eSJed Brown ) 4699df49d7eSJed Brown }; 4701142270cSJeremy L Thompson self.check_error(ierr) 4719df49d7eSJed Brown } 4729df49d7eSJed Brown 4739df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 4749df49d7eSJed Brown &self, 4759df49d7eSJed Brown assembled: &mut Vector, 4769df49d7eSJed Brown ) -> crate::Result<i32> { 4779df49d7eSJed Brown let ierr = unsafe { 4789df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssemblePointBlockDiagonal( 4799df49d7eSJed Brown self.ptr, 4809df49d7eSJed Brown assembled.ptr, 4819df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4829df49d7eSJed Brown ) 4839df49d7eSJed Brown }; 4841142270cSJeremy L Thompson self.check_error(ierr) 4859df49d7eSJed Brown } 4869df49d7eSJed Brown 4879df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 4889df49d7eSJed Brown &self, 4899df49d7eSJed Brown assembled: &mut Vector, 4909df49d7eSJed Brown ) -> crate::Result<i32> { 4919df49d7eSJed Brown let ierr = unsafe { 4929df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddPointBlockDiagonal( 4939df49d7eSJed Brown self.ptr, 4949df49d7eSJed Brown assembled.ptr, 4959df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 4969df49d7eSJed Brown ) 4979df49d7eSJed Brown }; 4981142270cSJeremy L Thompson self.check_error(ierr) 4999df49d7eSJed Brown } 5009df49d7eSJed Brown } 5019df49d7eSJed Brown 5029df49d7eSJed Brown // ----------------------------------------------------------------------------- 5039df49d7eSJed Brown // Operator 5049df49d7eSJed Brown // ----------------------------------------------------------------------------- 5059df49d7eSJed Brown impl<'a> Operator<'a> { 5069df49d7eSJed Brown // Constructor 5079df49d7eSJed Brown pub fn create<'b>( 508594ef120SJeremy L Thompson ceed: &crate::Ceed, 5099df49d7eSJed Brown qf: impl Into<QFunctionOpt<'b>>, 5109df49d7eSJed Brown dqf: impl Into<QFunctionOpt<'b>>, 5119df49d7eSJed Brown dqfT: impl Into<QFunctionOpt<'b>>, 5129df49d7eSJed Brown ) -> crate::Result<Self> { 5139df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 5149df49d7eSJed Brown let ierr = unsafe { 5159df49d7eSJed Brown bind_ceed::CeedOperatorCreate( 5169df49d7eSJed Brown ceed.ptr, 5179df49d7eSJed Brown qf.into().to_raw(), 5189df49d7eSJed Brown dqf.into().to_raw(), 5199df49d7eSJed Brown dqfT.into().to_raw(), 5209df49d7eSJed Brown &mut ptr, 5219df49d7eSJed Brown ) 5229df49d7eSJed Brown }; 5239df49d7eSJed Brown ceed.check_error(ierr)?; 5249df49d7eSJed Brown Ok(Self { 5251142270cSJeremy L Thompson op_core: OperatorCore { 5261142270cSJeremy L Thompson ptr, 5271142270cSJeremy L Thompson _lifeline: PhantomData, 5281142270cSJeremy L Thompson }, 5299df49d7eSJed Brown }) 5309df49d7eSJed Brown } 5319df49d7eSJed Brown 5321142270cSJeremy L Thompson fn from_raw(ptr: bind_ceed::CeedOperator) -> crate::Result<Self> { 5339df49d7eSJed Brown Ok(Self { 5341142270cSJeremy L Thompson op_core: OperatorCore { 5351142270cSJeremy L Thompson ptr, 5361142270cSJeremy L Thompson _lifeline: PhantomData, 5371142270cSJeremy L Thompson }, 5389df49d7eSJed Brown }) 5399df49d7eSJed Brown } 5409df49d7eSJed Brown 5419df49d7eSJed Brown /// Apply Operator to a vector 5429df49d7eSJed Brown /// 5439df49d7eSJed Brown /// * `input` - Input Vector 5449df49d7eSJed Brown /// * `output` - Output Vector 5459df49d7eSJed Brown /// 5469df49d7eSJed Brown /// ``` 5479df49d7eSJed Brown /// # use libceed::prelude::*; 5484d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 5499df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 5509df49d7eSJed Brown /// let ne = 4; 5519df49d7eSJed Brown /// let p = 3; 5529df49d7eSJed Brown /// let q = 4; 5539df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 5549df49d7eSJed Brown /// 5559df49d7eSJed Brown /// // Vectors 556c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 557c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 5589df49d7eSJed Brown /// qdata.set_value(0.0); 559c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 560c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 5619df49d7eSJed Brown /// v.set_value(0.0); 5629df49d7eSJed Brown /// 5639df49d7eSJed Brown /// // Restrictions 5649df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 5659df49d7eSJed Brown /// for i in 0..ne { 5669df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 5679df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 5689df49d7eSJed Brown /// } 569c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 5709df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 5719df49d7eSJed Brown /// for i in 0..ne { 5729df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 5739df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 5749df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 5759df49d7eSJed Brown /// } 576c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 5779df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 578c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 5799df49d7eSJed Brown /// 5809df49d7eSJed Brown /// // Bases 581c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 582c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 5839df49d7eSJed Brown /// 5849df49d7eSJed Brown /// // Build quadrature data 585c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 586c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 587c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 588c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 589c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 590c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 5919df49d7eSJed Brown /// 5929df49d7eSJed Brown /// // Mass operator 593c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 5949df49d7eSJed Brown /// let op_mass = ceed 595c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 596c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 597c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 598c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 5999df49d7eSJed Brown /// 6009df49d7eSJed Brown /// v.set_value(0.0); 601c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 6029df49d7eSJed Brown /// 6039df49d7eSJed Brown /// // Check 604e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 6059df49d7eSJed Brown /// assert!( 60680a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 6079df49d7eSJed Brown /// "Incorrect interval length computed" 6089df49d7eSJed Brown /// ); 609c68be7a2SJeremy L Thompson /// # Ok(()) 610c68be7a2SJeremy L Thompson /// # } 6119df49d7eSJed Brown /// ``` 6129df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 6139df49d7eSJed Brown self.op_core.apply(input, output) 6149df49d7eSJed Brown } 6159df49d7eSJed Brown 6169df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 6179df49d7eSJed Brown /// 6189df49d7eSJed Brown /// * `input` - Input Vector 6199df49d7eSJed Brown /// * `output` - Output Vector 6209df49d7eSJed Brown /// 6219df49d7eSJed Brown /// ``` 6229df49d7eSJed Brown /// # use libceed::prelude::*; 6234d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 6249df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 6259df49d7eSJed Brown /// let ne = 4; 6269df49d7eSJed Brown /// let p = 3; 6279df49d7eSJed Brown /// let q = 4; 6289df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 6299df49d7eSJed Brown /// 6309df49d7eSJed Brown /// // Vectors 631c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 632c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 6339df49d7eSJed Brown /// qdata.set_value(0.0); 634c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 635c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 6369df49d7eSJed Brown /// 6379df49d7eSJed Brown /// // Restrictions 6389df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 6399df49d7eSJed Brown /// for i in 0..ne { 6409df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 6419df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 6429df49d7eSJed Brown /// } 643c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 6449df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 6459df49d7eSJed Brown /// for i in 0..ne { 6469df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 6479df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 6489df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 6499df49d7eSJed Brown /// } 650c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 6519df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 652c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 6539df49d7eSJed Brown /// 6549df49d7eSJed Brown /// // Bases 655c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 656c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 6579df49d7eSJed Brown /// 6589df49d7eSJed Brown /// // Build quadrature data 659c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 660c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 661c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 662c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 663c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 664c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 6659df49d7eSJed Brown /// 6669df49d7eSJed Brown /// // Mass operator 667c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 6689df49d7eSJed Brown /// let op_mass = ceed 669c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 670c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 671c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 672c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 6739df49d7eSJed Brown /// 6749df49d7eSJed Brown /// v.set_value(1.0); 675c68be7a2SJeremy L Thompson /// op_mass.apply_add(&u, &mut v)?; 6769df49d7eSJed Brown /// 6779df49d7eSJed Brown /// // Check 678e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 6799df49d7eSJed Brown /// assert!( 68080a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 6819df49d7eSJed Brown /// "Incorrect interval length computed and added" 6829df49d7eSJed Brown /// ); 683c68be7a2SJeremy L Thompson /// # Ok(()) 684c68be7a2SJeremy L Thompson /// # } 6859df49d7eSJed Brown /// ``` 6869df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 6879df49d7eSJed Brown self.op_core.apply_add(input, output) 6889df49d7eSJed Brown } 6899df49d7eSJed Brown 6909df49d7eSJed Brown /// Provide a field to a Operator for use by its QFunction 6919df49d7eSJed Brown /// 6929df49d7eSJed Brown /// * `fieldname` - Name of the field (to be matched with the name used by 6939df49d7eSJed Brown /// the QFunction) 6949df49d7eSJed Brown /// * `r` - ElemRestriction 6959df49d7eSJed Brown /// * `b` - Basis in which the field resides or `BasisCollocated` if 6969df49d7eSJed Brown /// collocated with quadrature points 6979df49d7eSJed Brown /// * `v` - Vector to be used by Operator or `VectorActive` if field 6989df49d7eSJed Brown /// is active or `VectorNone` if using `Weight` with the 6999df49d7eSJed Brown /// QFunction 7009df49d7eSJed Brown /// 7019df49d7eSJed Brown /// 7029df49d7eSJed Brown /// ``` 7039df49d7eSJed Brown /// # use libceed::prelude::*; 7044d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 7059df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 706c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 707c68be7a2SJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 7089df49d7eSJed Brown /// 7099df49d7eSJed Brown /// // Operator field arguments 7109df49d7eSJed Brown /// let ne = 3; 7119df49d7eSJed Brown /// let q = 4; 7129df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 7139df49d7eSJed Brown /// for i in 0..ne { 7149df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 7159df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 7169df49d7eSJed Brown /// } 717c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 7189df49d7eSJed Brown /// 719c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 7209df49d7eSJed Brown /// 7219df49d7eSJed Brown /// // Operator field 722c68be7a2SJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 723c68be7a2SJeremy L Thompson /// # Ok(()) 724c68be7a2SJeremy L Thompson /// # } 7259df49d7eSJed Brown /// ``` 7269df49d7eSJed Brown #[allow(unused_mut)] 7279df49d7eSJed Brown pub fn field<'b>( 7289df49d7eSJed Brown mut self, 7299df49d7eSJed Brown fieldname: &str, 7309df49d7eSJed Brown r: impl Into<ElemRestrictionOpt<'b>>, 7319df49d7eSJed Brown b: impl Into<BasisOpt<'b>>, 7329df49d7eSJed Brown v: impl Into<VectorOpt<'b>>, 7339df49d7eSJed Brown ) -> crate::Result<Self> { 7349df49d7eSJed Brown let fieldname = CString::new(fieldname).expect("CString::new failed"); 7359df49d7eSJed Brown let fieldname = fieldname.as_ptr() as *const i8; 7369df49d7eSJed Brown let ierr = unsafe { 7379df49d7eSJed Brown bind_ceed::CeedOperatorSetField( 7389df49d7eSJed Brown self.op_core.ptr, 7399df49d7eSJed Brown fieldname, 7409df49d7eSJed Brown r.into().to_raw(), 7419df49d7eSJed Brown b.into().to_raw(), 7429df49d7eSJed Brown v.into().to_raw(), 7439df49d7eSJed Brown ) 7449df49d7eSJed Brown }; 7451142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 7469df49d7eSJed Brown Ok(self) 7479df49d7eSJed Brown } 7489df49d7eSJed Brown 74908778c6fSJeremy L Thompson /// Get a slice of Operator inputs 75008778c6fSJeremy L Thompson /// 75108778c6fSJeremy L Thompson /// ``` 75208778c6fSJeremy L Thompson /// # use libceed::prelude::*; 7534d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 75408778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 75508778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 75608778c6fSJeremy L Thompson /// 75708778c6fSJeremy L Thompson /// // Operator field arguments 75808778c6fSJeremy L Thompson /// let ne = 3; 75908778c6fSJeremy L Thompson /// let q = 4 as usize; 76008778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 76108778c6fSJeremy L Thompson /// for i in 0..ne { 76208778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 76308778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 76408778c6fSJeremy L Thompson /// } 76508778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 76608778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 76708778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 76808778c6fSJeremy L Thompson /// 76908778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 77008778c6fSJeremy L Thompson /// 77108778c6fSJeremy L Thompson /// // Operator fields 77208778c6fSJeremy L Thompson /// let op = ceed 77308778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 77408778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 77508778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 77608778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 77708778c6fSJeremy L Thompson /// 77808778c6fSJeremy L Thompson /// let inputs = op.inputs()?; 77908778c6fSJeremy L Thompson /// 78008778c6fSJeremy L Thompson /// assert_eq!(inputs.len(), 2, "Incorrect inputs array"); 78108778c6fSJeremy L Thompson /// # Ok(()) 78208778c6fSJeremy L Thompson /// # } 78308778c6fSJeremy L Thompson /// ``` 78408778c6fSJeremy L Thompson pub fn inputs(&self) -> crate::Result<&[crate::OperatorField]> { 78508778c6fSJeremy L Thompson // Get array of raw C pointers for inputs 78608778c6fSJeremy L Thompson let mut num_inputs = 0; 78708778c6fSJeremy L Thompson let mut inputs_ptr = std::ptr::null_mut(); 78808778c6fSJeremy L Thompson let ierr = unsafe { 78908778c6fSJeremy L Thompson bind_ceed::CeedOperatorGetFields( 79008778c6fSJeremy L Thompson self.op_core.ptr, 79108778c6fSJeremy L Thompson &mut num_inputs, 79208778c6fSJeremy L Thompson &mut inputs_ptr, 79308778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt, 79408778c6fSJeremy L Thompson std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField, 79508778c6fSJeremy L Thompson ) 79608778c6fSJeremy L Thompson }; 79708778c6fSJeremy L Thompson self.op_core.check_error(ierr)?; 79808778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice 79908778c6fSJeremy L Thompson let inputs_slice = unsafe { 80008778c6fSJeremy L Thompson std::slice::from_raw_parts( 80108778c6fSJeremy L Thompson inputs_ptr as *const crate::OperatorField, 80208778c6fSJeremy L Thompson num_inputs as usize, 80308778c6fSJeremy L Thompson ) 80408778c6fSJeremy L Thompson }; 80508778c6fSJeremy L Thompson Ok(inputs_slice) 80608778c6fSJeremy L Thompson } 80708778c6fSJeremy L Thompson 80808778c6fSJeremy L Thompson /// Get a slice of Operator outputs 80908778c6fSJeremy L Thompson /// 81008778c6fSJeremy L Thompson /// ``` 81108778c6fSJeremy L Thompson /// # use libceed::prelude::*; 8124d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 81308778c6fSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 81408778c6fSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 81508778c6fSJeremy L Thompson /// 81608778c6fSJeremy L Thompson /// // Operator field arguments 81708778c6fSJeremy L Thompson /// let ne = 3; 81808778c6fSJeremy L Thompson /// let q = 4 as usize; 81908778c6fSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 82008778c6fSJeremy L Thompson /// for i in 0..ne { 82108778c6fSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 82208778c6fSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 82308778c6fSJeremy L Thompson /// } 82408778c6fSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 82508778c6fSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 82608778c6fSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 82708778c6fSJeremy L Thompson /// 82808778c6fSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 82908778c6fSJeremy L Thompson /// 83008778c6fSJeremy L Thompson /// // Operator fields 83108778c6fSJeremy L Thompson /// let op = ceed 83208778c6fSJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 83308778c6fSJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 83408778c6fSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 83508778c6fSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 83608778c6fSJeremy L Thompson /// 83708778c6fSJeremy L Thompson /// let outputs = op.outputs()?; 83808778c6fSJeremy L Thompson /// 83908778c6fSJeremy L Thompson /// assert_eq!(outputs.len(), 1, "Incorrect outputs array"); 84008778c6fSJeremy L Thompson /// # Ok(()) 84108778c6fSJeremy L Thompson /// # } 84208778c6fSJeremy L Thompson /// ``` 84308778c6fSJeremy L Thompson pub fn outputs(&self) -> crate::Result<&[crate::OperatorField]> { 84408778c6fSJeremy L Thompson // Get array of raw C pointers for outputs 84508778c6fSJeremy L Thompson let mut num_outputs = 0; 84608778c6fSJeremy L Thompson let mut outputs_ptr = std::ptr::null_mut(); 84708778c6fSJeremy L Thompson let ierr = unsafe { 84808778c6fSJeremy L Thompson bind_ceed::CeedOperatorGetFields( 84908778c6fSJeremy L Thompson self.op_core.ptr, 85008778c6fSJeremy L Thompson std::ptr::null_mut() as *mut bind_ceed::CeedInt, 85108778c6fSJeremy L Thompson std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField, 85208778c6fSJeremy L Thompson &mut num_outputs, 85308778c6fSJeremy L Thompson &mut outputs_ptr, 85408778c6fSJeremy L Thompson ) 85508778c6fSJeremy L Thompson }; 85608778c6fSJeremy L Thompson self.op_core.check_error(ierr)?; 85708778c6fSJeremy L Thompson // Convert raw C pointers to fixed length slice 85808778c6fSJeremy L Thompson let outputs_slice = unsafe { 85908778c6fSJeremy L Thompson std::slice::from_raw_parts( 86008778c6fSJeremy L Thompson outputs_ptr as *const crate::OperatorField, 86108778c6fSJeremy L Thompson num_outputs as usize, 86208778c6fSJeremy L Thompson ) 86308778c6fSJeremy L Thompson }; 86408778c6fSJeremy L Thompson Ok(outputs_slice) 86508778c6fSJeremy L Thompson } 86608778c6fSJeremy L Thompson 8676f97ff0aSJeremy L Thompson /// Check if Operator is setup correctly 8686f97ff0aSJeremy L Thompson /// 8696f97ff0aSJeremy L Thompson /// ``` 8706f97ff0aSJeremy L Thompson /// # use libceed::prelude::*; 8716f97ff0aSJeremy L Thompson /// # fn main() -> libceed::Result<()> { 8726f97ff0aSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 8736f97ff0aSJeremy L Thompson /// let ne = 4; 8746f97ff0aSJeremy L Thompson /// let p = 3; 8756f97ff0aSJeremy L Thompson /// let q = 4; 8766f97ff0aSJeremy L Thompson /// let ndofs = p * ne - ne + 1; 8776f97ff0aSJeremy L Thompson /// 8786f97ff0aSJeremy L Thompson /// // Restrictions 8796f97ff0aSJeremy L Thompson /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 8806f97ff0aSJeremy L Thompson /// for i in 0..ne { 8816f97ff0aSJeremy L Thompson /// indx[2 * i + 0] = i as i32; 8826f97ff0aSJeremy L Thompson /// indx[2 * i + 1] = (i + 1) as i32; 8836f97ff0aSJeremy L Thompson /// } 8846f97ff0aSJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 8856f97ff0aSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 8866f97ff0aSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 8876f97ff0aSJeremy L Thompson /// 8886f97ff0aSJeremy L Thompson /// // Bases 8896f97ff0aSJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 8906f97ff0aSJeremy L Thompson /// 8916f97ff0aSJeremy L Thompson /// // Build quadrature data 8926f97ff0aSJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 8936f97ff0aSJeremy L Thompson /// let op_build = ceed 8946f97ff0aSJeremy L Thompson /// .operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 8956f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 8966f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 8976f97ff0aSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 8986f97ff0aSJeremy L Thompson /// 8996f97ff0aSJeremy L Thompson /// // Check 9006f97ff0aSJeremy L Thompson /// assert!(op_build.check().is_ok(), "Operator setup incorrectly"); 9016f97ff0aSJeremy L Thompson /// # Ok(()) 9026f97ff0aSJeremy L Thompson /// # } 9036f97ff0aSJeremy L Thompson /// ``` 9046f97ff0aSJeremy L Thompson pub fn check(self) -> crate::Result<Self> { 9056f97ff0aSJeremy L Thompson self.op_core.check()?; 9066f97ff0aSJeremy L Thompson Ok(self) 9076f97ff0aSJeremy L Thompson } 9086f97ff0aSJeremy L Thompson 9093f2759cfSJeremy L Thompson /// Get the number of elements associated with an Operator 9103f2759cfSJeremy L Thompson /// 9113f2759cfSJeremy L Thompson /// 9123f2759cfSJeremy L Thompson /// ``` 9133f2759cfSJeremy L Thompson /// # use libceed::prelude::*; 9144d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 9153f2759cfSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 9163f2759cfSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 9173f2759cfSJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 9183f2759cfSJeremy L Thompson /// 9193f2759cfSJeremy L Thompson /// // Operator field arguments 9203f2759cfSJeremy L Thompson /// let ne = 3; 9213f2759cfSJeremy L Thompson /// let q = 4; 9223f2759cfSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 9233f2759cfSJeremy L Thompson /// for i in 0..ne { 9243f2759cfSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 9253f2759cfSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 9263f2759cfSJeremy L Thompson /// } 9273f2759cfSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 9283f2759cfSJeremy L Thompson /// 9293f2759cfSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 9303f2759cfSJeremy L Thompson /// 9313f2759cfSJeremy L Thompson /// // Operator field 9323f2759cfSJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 9333f2759cfSJeremy L Thompson /// 9343f2759cfSJeremy L Thompson /// // Check number of elements 9353f2759cfSJeremy L Thompson /// assert_eq!(op.num_elements(), ne, "Incorrect number of elements"); 9363f2759cfSJeremy L Thompson /// # Ok(()) 9373f2759cfSJeremy L Thompson /// # } 9383f2759cfSJeremy L Thompson /// ``` 9393f2759cfSJeremy L Thompson pub fn num_elements(&self) -> usize { 9403f2759cfSJeremy L Thompson let mut nelem = 0; 9413f2759cfSJeremy L Thompson unsafe { bind_ceed::CeedOperatorGetNumElements(self.op_core.ptr, &mut nelem) }; 9423f2759cfSJeremy L Thompson usize::try_from(nelem).unwrap() 9433f2759cfSJeremy L Thompson } 9443f2759cfSJeremy L Thompson 9453f2759cfSJeremy L Thompson /// Get the number of quadrature points associated with each element of 9463f2759cfSJeremy L Thompson /// an Operator 9473f2759cfSJeremy L Thompson /// 9483f2759cfSJeremy L Thompson /// 9493f2759cfSJeremy L Thompson /// ``` 9503f2759cfSJeremy L Thompson /// # use libceed::prelude::*; 9514d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 9523f2759cfSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 9533f2759cfSJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 9543f2759cfSJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 9553f2759cfSJeremy L Thompson /// 9563f2759cfSJeremy L Thompson /// // Operator field arguments 9573f2759cfSJeremy L Thompson /// let ne = 3; 9583f2759cfSJeremy L Thompson /// let q = 4; 9593f2759cfSJeremy L Thompson /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 9603f2759cfSJeremy L Thompson /// for i in 0..ne { 9613f2759cfSJeremy L Thompson /// ind[2 * i + 0] = i as i32; 9623f2759cfSJeremy L Thompson /// ind[2 * i + 1] = (i + 1) as i32; 9633f2759cfSJeremy L Thompson /// } 9643f2759cfSJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 9653f2759cfSJeremy L Thompson /// 9663f2759cfSJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 9673f2759cfSJeremy L Thompson /// 9683f2759cfSJeremy L Thompson /// // Operator field 9693f2759cfSJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 9703f2759cfSJeremy L Thompson /// 9713f2759cfSJeremy L Thompson /// // Check number of quadrature points 9723f2759cfSJeremy L Thompson /// assert_eq!( 9733f2759cfSJeremy L Thompson /// op.num_quadrature_points(), 9743f2759cfSJeremy L Thompson /// q, 9753f2759cfSJeremy L Thompson /// "Incorrect number of quadrature points" 9763f2759cfSJeremy L Thompson /// ); 9773f2759cfSJeremy L Thompson /// # Ok(()) 9783f2759cfSJeremy L Thompson /// # } 9793f2759cfSJeremy L Thompson /// ``` 9803f2759cfSJeremy L Thompson pub fn num_quadrature_points(&self) -> usize { 9813f2759cfSJeremy L Thompson let mut Q = 0; 9823f2759cfSJeremy L Thompson unsafe { bind_ceed::CeedOperatorGetNumQuadraturePoints(self.op_core.ptr, &mut Q) }; 9833f2759cfSJeremy L Thompson usize::try_from(Q).unwrap() 9843f2759cfSJeremy L Thompson } 9853f2759cfSJeremy L Thompson 9869df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 9879df49d7eSJed Brown /// 9889df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 9899df49d7eSJed Brown /// 9909df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 9919df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 9929df49d7eSJed Brown /// 9939df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 9949df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 9959df49d7eSJed Brown /// 9969df49d7eSJed Brown /// ``` 9979df49d7eSJed Brown /// # use libceed::prelude::*; 9984d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 9999df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 10009df49d7eSJed Brown /// let ne = 4; 10019df49d7eSJed Brown /// let p = 3; 10029df49d7eSJed Brown /// let q = 4; 10039df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 10049df49d7eSJed Brown /// 10059df49d7eSJed Brown /// // Vectors 1006c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1007c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 10089df49d7eSJed Brown /// qdata.set_value(0.0); 1009c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 10109df49d7eSJed Brown /// u.set_value(1.0); 1011c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 10129df49d7eSJed Brown /// v.set_value(0.0); 10139df49d7eSJed Brown /// 10149df49d7eSJed Brown /// // Restrictions 10159df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 10169df49d7eSJed Brown /// for i in 0..ne { 10179df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 10189df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 10199df49d7eSJed Brown /// } 1020c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 10219df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 10229df49d7eSJed Brown /// for i in 0..ne { 10239df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 10249df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 10259df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 10269df49d7eSJed Brown /// } 1027c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 10289df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1029c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 10309df49d7eSJed Brown /// 10319df49d7eSJed Brown /// // Bases 1032c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1033c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 10349df49d7eSJed Brown /// 10359df49d7eSJed Brown /// // Build quadrature data 1036c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1037c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1038c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1039c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1040c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1041c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 10429df49d7eSJed Brown /// 10439df49d7eSJed Brown /// // Mass operator 1044c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 10459df49d7eSJed Brown /// let op_mass = ceed 1046c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1047c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1048c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1049c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 10509df49d7eSJed Brown /// 10519df49d7eSJed Brown /// // Diagonal 1052c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 10539df49d7eSJed Brown /// diag.set_value(0.0); 1054c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_diagonal(&mut diag)?; 10559df49d7eSJed Brown /// 10569df49d7eSJed Brown /// // Manual diagonal computation 1057c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 10589c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 10599df49d7eSJed Brown /// for i in 0..ndofs { 10609df49d7eSJed Brown /// u.set_value(0.0); 10619df49d7eSJed Brown /// { 1062e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 10639df49d7eSJed Brown /// u_array[i] = 1.; 10649df49d7eSJed Brown /// } 10659df49d7eSJed Brown /// 1066c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 10679df49d7eSJed Brown /// 10689df49d7eSJed Brown /// { 10699c774eddSJeremy L Thompson /// let v_array = v.view()?; 1070e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 10719df49d7eSJed Brown /// true_array[i] = v_array[i]; 10729df49d7eSJed Brown /// } 10739df49d7eSJed Brown /// } 10749df49d7eSJed Brown /// 10759df49d7eSJed Brown /// // Check 1076e78171edSJeremy L Thompson /// diag.view()? 10779df49d7eSJed Brown /// .iter() 1078e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 10799df49d7eSJed Brown /// .for_each(|(computed, actual)| { 10809df49d7eSJed Brown /// assert!( 108180a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 10829df49d7eSJed Brown /// "Diagonal entry incorrect" 10839df49d7eSJed Brown /// ); 10849df49d7eSJed Brown /// }); 1085c68be7a2SJeremy L Thompson /// # Ok(()) 1086c68be7a2SJeremy L Thompson /// # } 10879df49d7eSJed Brown /// ``` 10889df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 10899df49d7eSJed Brown self.op_core.linear_assemble_diagonal(assembled) 10909df49d7eSJed Brown } 10919df49d7eSJed Brown 10929df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 10939df49d7eSJed Brown /// 10949df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 10959df49d7eSJed Brown /// 10969df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 10979df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 10989df49d7eSJed Brown /// 10999df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 11009df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 11019df49d7eSJed Brown /// 11029df49d7eSJed Brown /// 11039df49d7eSJed Brown /// ``` 11049df49d7eSJed Brown /// # use libceed::prelude::*; 11054d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 11069df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 11079df49d7eSJed Brown /// let ne = 4; 11089df49d7eSJed Brown /// let p = 3; 11099df49d7eSJed Brown /// let q = 4; 11109df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 11119df49d7eSJed Brown /// 11129df49d7eSJed Brown /// // Vectors 1113c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1114c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 11159df49d7eSJed Brown /// qdata.set_value(0.0); 1116c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 11179df49d7eSJed Brown /// u.set_value(1.0); 1118c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 11199df49d7eSJed Brown /// v.set_value(0.0); 11209df49d7eSJed Brown /// 11219df49d7eSJed Brown /// // Restrictions 11229df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 11239df49d7eSJed Brown /// for i in 0..ne { 11249df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 11259df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 11269df49d7eSJed Brown /// } 1127c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 11289df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 11299df49d7eSJed Brown /// for i in 0..ne { 11309df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 11319df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 11329df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 11339df49d7eSJed Brown /// } 1134c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 11359df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1136c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 11379df49d7eSJed Brown /// 11389df49d7eSJed Brown /// // Bases 1139c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1140c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 11419df49d7eSJed Brown /// 11429df49d7eSJed Brown /// // Build quadrature data 1143c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1144c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1145c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1146c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1147c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1148c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 11499df49d7eSJed Brown /// 11509df49d7eSJed Brown /// // Mass operator 1151c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 11529df49d7eSJed Brown /// let op_mass = ceed 1153c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1154c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1155c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1156c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 11579df49d7eSJed Brown /// 11589df49d7eSJed Brown /// // Diagonal 1159c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 11609df49d7eSJed Brown /// diag.set_value(1.0); 1161c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_diagonal(&mut diag)?; 11629df49d7eSJed Brown /// 11639df49d7eSJed Brown /// // Manual diagonal computation 1164c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 11659c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 11669df49d7eSJed Brown /// for i in 0..ndofs { 11679df49d7eSJed Brown /// u.set_value(0.0); 11689df49d7eSJed Brown /// { 1169e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 11709df49d7eSJed Brown /// u_array[i] = 1.; 11719df49d7eSJed Brown /// } 11729df49d7eSJed Brown /// 1173c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 11749df49d7eSJed Brown /// 11759df49d7eSJed Brown /// { 11769c774eddSJeremy L Thompson /// let v_array = v.view()?; 1177e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 11789df49d7eSJed Brown /// true_array[i] = v_array[i] + 1.0; 11799df49d7eSJed Brown /// } 11809df49d7eSJed Brown /// } 11819df49d7eSJed Brown /// 11829df49d7eSJed Brown /// // Check 1183e78171edSJeremy L Thompson /// diag.view()? 11849df49d7eSJed Brown /// .iter() 1185e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 11869df49d7eSJed Brown /// .for_each(|(computed, actual)| { 11879df49d7eSJed Brown /// assert!( 118880a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 11899df49d7eSJed Brown /// "Diagonal entry incorrect" 11909df49d7eSJed Brown /// ); 11919df49d7eSJed Brown /// }); 1192c68be7a2SJeremy L Thompson /// # Ok(()) 1193c68be7a2SJeremy L Thompson /// # } 11949df49d7eSJed Brown /// ``` 11959df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 11969df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 11979df49d7eSJed Brown } 11989df49d7eSJed Brown 11999df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 12009df49d7eSJed Brown /// 12019df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 12029df49d7eSJed Brown /// Operator. 12039df49d7eSJed Brown /// 12049df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 12059df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 12069df49d7eSJed Brown /// 12079df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 12089df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 12099df49d7eSJed Brown /// diagonal, provided in row-major form with an 12109df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 12119df49d7eSJed Brown /// this vector are derived from the active vector for 12129df49d7eSJed Brown /// the CeedOperator. The array has shape 12139df49d7eSJed Brown /// `[nodes, component out, component in]`. 12149df49d7eSJed Brown /// 12159df49d7eSJed Brown /// ``` 12169df49d7eSJed Brown /// # use libceed::prelude::*; 12174d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 12189df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 12199df49d7eSJed Brown /// let ne = 4; 12209df49d7eSJed Brown /// let p = 3; 12219df49d7eSJed Brown /// let q = 4; 12229df49d7eSJed Brown /// let ncomp = 2; 12239df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 12249df49d7eSJed Brown /// 12259df49d7eSJed Brown /// // Vectors 1226c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1227c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 12289df49d7eSJed Brown /// qdata.set_value(0.0); 1229c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 12309df49d7eSJed Brown /// u.set_value(1.0); 1231c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 12329df49d7eSJed Brown /// v.set_value(0.0); 12339df49d7eSJed Brown /// 12349df49d7eSJed Brown /// // Restrictions 12359df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 12369df49d7eSJed Brown /// for i in 0..ne { 12379df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 12389df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 12399df49d7eSJed Brown /// } 1240c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 12419df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 12429df49d7eSJed Brown /// for i in 0..ne { 12439df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 12449df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 12459df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 12469df49d7eSJed Brown /// } 1247c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 12489df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1249c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 12509df49d7eSJed Brown /// 12519df49d7eSJed Brown /// // Bases 1252c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1253c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 12549df49d7eSJed Brown /// 12559df49d7eSJed Brown /// // Build quadrature data 1256c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1257c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1258c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1259c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1260c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1261c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 12629df49d7eSJed Brown /// 12639df49d7eSJed Brown /// // Mass operator 12649df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 12659df49d7eSJed Brown /// // Number of quadrature points 12669df49d7eSJed Brown /// let q = qdata.len(); 12679df49d7eSJed Brown /// 12689df49d7eSJed Brown /// // Iterate over quadrature points 12699df49d7eSJed Brown /// for i in 0..q { 12709df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 12719df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 12729df49d7eSJed Brown /// } 12739df49d7eSJed Brown /// 12749df49d7eSJed Brown /// // Return clean error code 12759df49d7eSJed Brown /// 0 12769df49d7eSJed Brown /// }; 12779df49d7eSJed Brown /// 12789df49d7eSJed Brown /// let qf_mass = ceed 1279c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 1280c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 1281c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 1282c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 12839df49d7eSJed Brown /// 12849df49d7eSJed Brown /// let op_mass = ceed 1285c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1286c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1287c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1288c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 12899df49d7eSJed Brown /// 12909df49d7eSJed Brown /// // Diagonal 1291c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 12929df49d7eSJed Brown /// diag.set_value(0.0); 1293c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_point_block_diagonal(&mut diag)?; 12949df49d7eSJed Brown /// 12959df49d7eSJed Brown /// // Manual diagonal computation 1296c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 12979c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 12989df49d7eSJed Brown /// for i in 0..ndofs { 12999df49d7eSJed Brown /// for j in 0..ncomp { 13009df49d7eSJed Brown /// u.set_value(0.0); 13019df49d7eSJed Brown /// { 1302e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 13039df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 13049df49d7eSJed Brown /// } 13059df49d7eSJed Brown /// 1306c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 13079df49d7eSJed Brown /// 13089df49d7eSJed Brown /// { 13099c774eddSJeremy L Thompson /// let v_array = v.view()?; 1310e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 13119df49d7eSJed Brown /// for k in 0..ncomp { 13129df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 13139df49d7eSJed Brown /// } 13149df49d7eSJed Brown /// } 13159df49d7eSJed Brown /// } 13169df49d7eSJed Brown /// } 13179df49d7eSJed Brown /// 13189df49d7eSJed Brown /// // Check 1319e78171edSJeremy L Thompson /// diag.view()? 13209df49d7eSJed Brown /// .iter() 1321e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 13229df49d7eSJed Brown /// .for_each(|(computed, actual)| { 13239df49d7eSJed Brown /// assert!( 132480a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 13259df49d7eSJed Brown /// "Diagonal entry incorrect" 13269df49d7eSJed Brown /// ); 13279df49d7eSJed Brown /// }); 1328c68be7a2SJeremy L Thompson /// # Ok(()) 1329c68be7a2SJeremy L Thompson /// # } 13309df49d7eSJed Brown /// ``` 13319df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 13329df49d7eSJed Brown &self, 13339df49d7eSJed Brown assembled: &mut Vector, 13349df49d7eSJed Brown ) -> crate::Result<i32> { 13359df49d7eSJed Brown self.op_core.linear_assemble_point_block_diagonal(assembled) 13369df49d7eSJed Brown } 13379df49d7eSJed Brown 13389df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 13399df49d7eSJed Brown /// 13409df49d7eSJed Brown /// This sums into a Vector with the point block diagonal of a linear 13419df49d7eSJed Brown /// Operator. 13429df49d7eSJed Brown /// 13439df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 13449df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 13459df49d7eSJed Brown /// 13469df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 13479df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 13489df49d7eSJed Brown /// diagonal, provided in row-major form with an 13499df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 13509df49d7eSJed Brown /// this vector are derived from the active vector for 13519df49d7eSJed Brown /// the CeedOperator. The array has shape 13529df49d7eSJed Brown /// `[nodes, component out, component in]`. 13539df49d7eSJed Brown /// 13549df49d7eSJed Brown /// ``` 13559df49d7eSJed Brown /// # use libceed::prelude::*; 13564d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 13579df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 13589df49d7eSJed Brown /// let ne = 4; 13599df49d7eSJed Brown /// let p = 3; 13609df49d7eSJed Brown /// let q = 4; 13619df49d7eSJed Brown /// let ncomp = 2; 13629df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 13639df49d7eSJed Brown /// 13649df49d7eSJed Brown /// // Vectors 1365c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1366c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 13679df49d7eSJed Brown /// qdata.set_value(0.0); 1368c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 13699df49d7eSJed Brown /// u.set_value(1.0); 1370c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 13719df49d7eSJed Brown /// v.set_value(0.0); 13729df49d7eSJed Brown /// 13739df49d7eSJed Brown /// // Restrictions 13749df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 13759df49d7eSJed Brown /// for i in 0..ne { 13769df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 13779df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 13789df49d7eSJed Brown /// } 1379c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 13809df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 13819df49d7eSJed Brown /// for i in 0..ne { 13829df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 13839df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 13849df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 13859df49d7eSJed Brown /// } 1386c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 13879df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1388c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 13899df49d7eSJed Brown /// 13909df49d7eSJed Brown /// // Bases 1391c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1392c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 13939df49d7eSJed Brown /// 13949df49d7eSJed Brown /// // Build quadrature data 1395c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1396c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1397c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1398c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1399c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1400c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 14019df49d7eSJed Brown /// 14029df49d7eSJed Brown /// // Mass operator 14039df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 14049df49d7eSJed Brown /// // Number of quadrature points 14059df49d7eSJed Brown /// let q = qdata.len(); 14069df49d7eSJed Brown /// 14079df49d7eSJed Brown /// // Iterate over quadrature points 14089df49d7eSJed Brown /// for i in 0..q { 14099df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 14109df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 14119df49d7eSJed Brown /// } 14129df49d7eSJed Brown /// 14139df49d7eSJed Brown /// // Return clean error code 14149df49d7eSJed Brown /// 0 14159df49d7eSJed Brown /// }; 14169df49d7eSJed Brown /// 14179df49d7eSJed Brown /// let qf_mass = ceed 1418c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 1419c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 1420c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 1421c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 14229df49d7eSJed Brown /// 14239df49d7eSJed Brown /// let op_mass = ceed 1424c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1425c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1426c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1427c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 14289df49d7eSJed Brown /// 14299df49d7eSJed Brown /// // Diagonal 1430c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 14319df49d7eSJed Brown /// diag.set_value(1.0); 1432c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_point_block_diagonal(&mut diag)?; 14339df49d7eSJed Brown /// 14349df49d7eSJed Brown /// // Manual diagonal computation 1435c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 14369c774eddSJeremy L Thompson /// true_diag.set_value(0.0)?; 14379df49d7eSJed Brown /// for i in 0..ndofs { 14389df49d7eSJed Brown /// for j in 0..ncomp { 14399df49d7eSJed Brown /// u.set_value(0.0); 14409df49d7eSJed Brown /// { 1441e78171edSJeremy L Thompson /// let mut u_array = u.view_mut()?; 14429df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 14439df49d7eSJed Brown /// } 14449df49d7eSJed Brown /// 1445c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 14469df49d7eSJed Brown /// 14479df49d7eSJed Brown /// { 14489c774eddSJeremy L Thompson /// let v_array = v.view()?; 1449e78171edSJeremy L Thompson /// let mut true_array = true_diag.view_mut()?; 14509df49d7eSJed Brown /// for k in 0..ncomp { 14519df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 14529df49d7eSJed Brown /// } 14539df49d7eSJed Brown /// } 14549df49d7eSJed Brown /// } 14559df49d7eSJed Brown /// } 14569df49d7eSJed Brown /// 14579df49d7eSJed Brown /// // Check 1458e78171edSJeremy L Thompson /// diag.view()? 14599df49d7eSJed Brown /// .iter() 1460e78171edSJeremy L Thompson /// .zip(true_diag.view()?.iter()) 14619df49d7eSJed Brown /// .for_each(|(computed, actual)| { 14629df49d7eSJed Brown /// assert!( 146380a9ef05SNatalie Beams /// (*computed - 1.0 - *actual).abs() < 10.0 * libceed::EPSILON, 14649df49d7eSJed Brown /// "Diagonal entry incorrect" 14659df49d7eSJed Brown /// ); 14669df49d7eSJed Brown /// }); 1467c68be7a2SJeremy L Thompson /// # Ok(()) 1468c68be7a2SJeremy L Thompson /// # } 14699df49d7eSJed Brown /// ``` 14709df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 14719df49d7eSJed Brown &self, 14729df49d7eSJed Brown assembled: &mut Vector, 14739df49d7eSJed Brown ) -> crate::Result<i32> { 14749df49d7eSJed Brown self.op_core 14759df49d7eSJed Brown .linear_assemble_add_point_block_diagonal(assembled) 14769df49d7eSJed Brown } 14779df49d7eSJed Brown 14789df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 14799df49d7eSJed Brown /// given Operator, creating the prolongation basis from the fine and 14809df49d7eSJed Brown /// coarse grid interpolation 14819df49d7eSJed Brown /// 14829df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 14839df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 14849df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 14859df49d7eSJed Brown /// 14869df49d7eSJed Brown /// ``` 14879df49d7eSJed Brown /// # use libceed::prelude::*; 14884d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 14899df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 14909df49d7eSJed Brown /// let ne = 15; 14919df49d7eSJed Brown /// let p_coarse = 3; 14929df49d7eSJed Brown /// let p_fine = 5; 14939df49d7eSJed Brown /// let q = 6; 14949df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 14959df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 14969df49d7eSJed Brown /// 14979df49d7eSJed Brown /// // Vectors 14989df49d7eSJed Brown /// let x_array = (0..ne + 1) 149980a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 150080a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1501c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1502c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 15039df49d7eSJed Brown /// qdata.set_value(0.0); 1504c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 15059df49d7eSJed Brown /// u_coarse.set_value(1.0); 1506c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 15079df49d7eSJed Brown /// u_fine.set_value(1.0); 1508c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 15099df49d7eSJed Brown /// v_coarse.set_value(0.0); 1510c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 15119df49d7eSJed Brown /// v_fine.set_value(0.0); 1512c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 15139df49d7eSJed Brown /// multiplicity.set_value(1.0); 15149df49d7eSJed Brown /// 15159df49d7eSJed Brown /// // Restrictions 15169df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1517c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 15189df49d7eSJed Brown /// 15199df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 15209df49d7eSJed Brown /// for i in 0..ne { 15219df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 15229df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 15239df49d7eSJed Brown /// } 1524c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 15259df49d7eSJed Brown /// 15269df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 15279df49d7eSJed Brown /// for i in 0..ne { 15289df49d7eSJed Brown /// for j in 0..p_coarse { 15299df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 15309df49d7eSJed Brown /// } 15319df49d7eSJed Brown /// } 1532c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 15339df49d7eSJed Brown /// ne, 15349df49d7eSJed Brown /// p_coarse, 15359df49d7eSJed Brown /// 1, 15369df49d7eSJed Brown /// 1, 15379df49d7eSJed Brown /// ndofs_coarse, 15389df49d7eSJed Brown /// MemType::Host, 15399df49d7eSJed Brown /// &indu_coarse, 1540c68be7a2SJeremy L Thompson /// )?; 15419df49d7eSJed Brown /// 15429df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 15439df49d7eSJed Brown /// for i in 0..ne { 15449df49d7eSJed Brown /// for j in 0..p_fine { 15459df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 15469df49d7eSJed Brown /// } 15479df49d7eSJed Brown /// } 1548c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 15499df49d7eSJed Brown /// 15509df49d7eSJed Brown /// // Bases 1551c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1552c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1553c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 15549df49d7eSJed Brown /// 15559df49d7eSJed Brown /// // Build quadrature data 1556c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1557c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1558c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1559c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1560c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1561c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 15629df49d7eSJed Brown /// 15639df49d7eSJed Brown /// // Mass operator 1564c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 15659df49d7eSJed Brown /// let op_mass_fine = ceed 1566c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1567c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1568c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1569c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 15709df49d7eSJed Brown /// 15719df49d7eSJed Brown /// // Multigrid setup 1572c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = 1573c68be7a2SJeremy L Thompson /// op_mass_fine.create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)?; 15749df49d7eSJed Brown /// 15759df49d7eSJed Brown /// // Coarse problem 15769df49d7eSJed Brown /// u_coarse.set_value(1.0); 1577c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 15789df49d7eSJed Brown /// 15799df49d7eSJed Brown /// // Check 1580e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 15819df49d7eSJed Brown /// assert!( 158280a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 15839df49d7eSJed Brown /// "Incorrect interval length computed" 15849df49d7eSJed Brown /// ); 15859df49d7eSJed Brown /// 15869df49d7eSJed Brown /// // Prolong 1587c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 15889df49d7eSJed Brown /// 15899df49d7eSJed Brown /// // Fine problem 1590c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 15919df49d7eSJed Brown /// 15929df49d7eSJed Brown /// // Check 1593e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 15949df49d7eSJed Brown /// assert!( 159580a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 15969df49d7eSJed Brown /// "Incorrect interval length computed" 15979df49d7eSJed Brown /// ); 15989df49d7eSJed Brown /// 15999df49d7eSJed Brown /// // Restrict 1600c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 16019df49d7eSJed Brown /// 16029df49d7eSJed Brown /// // Check 1603e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 16049df49d7eSJed Brown /// assert!( 160580a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 16069df49d7eSJed Brown /// "Incorrect interval length computed" 16079df49d7eSJed Brown /// ); 1608c68be7a2SJeremy L Thompson /// # Ok(()) 1609c68be7a2SJeremy L Thompson /// # } 16109df49d7eSJed Brown /// ``` 1611594ef120SJeremy L Thompson pub fn create_multigrid_level<'b>( 16129df49d7eSJed Brown &self, 16139df49d7eSJed Brown p_mult_fine: &Vector, 16149df49d7eSJed Brown rstr_coarse: &ElemRestriction, 16159df49d7eSJed Brown basis_coarse: &Basis, 1616594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 16179df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 16189df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 16199df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 16209df49d7eSJed Brown let ierr = unsafe { 16219df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreate( 16229df49d7eSJed Brown self.op_core.ptr, 16239df49d7eSJed Brown p_mult_fine.ptr, 16249df49d7eSJed Brown rstr_coarse.ptr, 16259df49d7eSJed Brown basis_coarse.ptr, 16269df49d7eSJed Brown &mut ptr_coarse, 16279df49d7eSJed Brown &mut ptr_prolong, 16289df49d7eSJed Brown &mut ptr_restrict, 16299df49d7eSJed Brown ) 16309df49d7eSJed Brown }; 16311142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 16321142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 16331142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 16341142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 16359df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 16369df49d7eSJed Brown } 16379df49d7eSJed Brown 16389df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 16399df49d7eSJed Brown /// given Operator with a tensor basis for the active basis 16409df49d7eSJed Brown /// 16419df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 16429df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 16439df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 16449df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 16459df49d7eSJed Brown /// 16469df49d7eSJed Brown /// ``` 16479df49d7eSJed Brown /// # use libceed::prelude::*; 16484d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 16499df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 16509df49d7eSJed Brown /// let ne = 15; 16519df49d7eSJed Brown /// let p_coarse = 3; 16529df49d7eSJed Brown /// let p_fine = 5; 16539df49d7eSJed Brown /// let q = 6; 16549df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 16559df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 16569df49d7eSJed Brown /// 16579df49d7eSJed Brown /// // Vectors 16589df49d7eSJed Brown /// let x_array = (0..ne + 1) 165980a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 166080a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1661c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1662c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 16639df49d7eSJed Brown /// qdata.set_value(0.0); 1664c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 16659df49d7eSJed Brown /// u_coarse.set_value(1.0); 1666c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 16679df49d7eSJed Brown /// u_fine.set_value(1.0); 1668c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 16699df49d7eSJed Brown /// v_coarse.set_value(0.0); 1670c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 16719df49d7eSJed Brown /// v_fine.set_value(0.0); 1672c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 16739df49d7eSJed Brown /// multiplicity.set_value(1.0); 16749df49d7eSJed Brown /// 16759df49d7eSJed Brown /// // Restrictions 16769df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1677c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 16789df49d7eSJed Brown /// 16799df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 16809df49d7eSJed Brown /// for i in 0..ne { 16819df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 16829df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 16839df49d7eSJed Brown /// } 1684c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 16859df49d7eSJed Brown /// 16869df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 16879df49d7eSJed Brown /// for i in 0..ne { 16889df49d7eSJed Brown /// for j in 0..p_coarse { 16899df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 16909df49d7eSJed Brown /// } 16919df49d7eSJed Brown /// } 1692c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 16939df49d7eSJed Brown /// ne, 16949df49d7eSJed Brown /// p_coarse, 16959df49d7eSJed Brown /// 1, 16969df49d7eSJed Brown /// 1, 16979df49d7eSJed Brown /// ndofs_coarse, 16989df49d7eSJed Brown /// MemType::Host, 16999df49d7eSJed Brown /// &indu_coarse, 1700c68be7a2SJeremy L Thompson /// )?; 17019df49d7eSJed Brown /// 17029df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 17039df49d7eSJed Brown /// for i in 0..ne { 17049df49d7eSJed Brown /// for j in 0..p_fine { 17059df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 17069df49d7eSJed Brown /// } 17079df49d7eSJed Brown /// } 1708c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 17099df49d7eSJed Brown /// 17109df49d7eSJed Brown /// // Bases 1711c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1712c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1713c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 17149df49d7eSJed Brown /// 17159df49d7eSJed Brown /// // Build quadrature data 1716c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1717c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1718c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1719c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1720c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1721c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 17229df49d7eSJed Brown /// 17239df49d7eSJed Brown /// // Mass operator 1724c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 17259df49d7eSJed Brown /// let op_mass_fine = ceed 1726c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1727c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1728c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1729c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 17309df49d7eSJed Brown /// 17319df49d7eSJed Brown /// // Multigrid setup 173280a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 17339df49d7eSJed Brown /// { 1734c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 1735c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 1736c68be7a2SJeremy L Thompson /// let basis_c_to_f = 1737c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 17389df49d7eSJed Brown /// for i in 0..p_coarse { 17399df49d7eSJed Brown /// coarse.set_value(0.0); 17409df49d7eSJed Brown /// { 1741e78171edSJeremy L Thompson /// let mut array = coarse.view_mut()?; 17429df49d7eSJed Brown /// array[i] = 1.; 17439df49d7eSJed Brown /// } 1744c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 17459df49d7eSJed Brown /// 1, 17469df49d7eSJed Brown /// TransposeMode::NoTranspose, 17479df49d7eSJed Brown /// EvalMode::Interp, 17489df49d7eSJed Brown /// &coarse, 17499df49d7eSJed Brown /// &mut fine, 1750c68be7a2SJeremy L Thompson /// )?; 1751e78171edSJeremy L Thompson /// let array = fine.view()?; 17529df49d7eSJed Brown /// for j in 0..p_fine { 17539df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 17549df49d7eSJed Brown /// } 17559df49d7eSJed Brown /// } 17569df49d7eSJed Brown /// } 1757c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_tensor_H1( 1758c68be7a2SJeremy L Thompson /// &multiplicity, 1759c68be7a2SJeremy L Thompson /// &ru_coarse, 1760c68be7a2SJeremy L Thompson /// &bu_coarse, 1761c68be7a2SJeremy L Thompson /// &interp_c_to_f, 1762c68be7a2SJeremy L Thompson /// )?; 17639df49d7eSJed Brown /// 17649df49d7eSJed Brown /// // Coarse problem 17659df49d7eSJed Brown /// u_coarse.set_value(1.0); 1766c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 17679df49d7eSJed Brown /// 17689df49d7eSJed Brown /// // Check 1769e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 17709df49d7eSJed Brown /// assert!( 177180a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 17729df49d7eSJed Brown /// "Incorrect interval length computed" 17739df49d7eSJed Brown /// ); 17749df49d7eSJed Brown /// 17759df49d7eSJed Brown /// // Prolong 1776c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 17779df49d7eSJed Brown /// 17789df49d7eSJed Brown /// // Fine problem 1779c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 17809df49d7eSJed Brown /// 17819df49d7eSJed Brown /// // Check 1782e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 17839df49d7eSJed Brown /// assert!( 178480a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 17859df49d7eSJed Brown /// "Incorrect interval length computed" 17869df49d7eSJed Brown /// ); 17879df49d7eSJed Brown /// 17889df49d7eSJed Brown /// // Restrict 1789c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 17909df49d7eSJed Brown /// 17919df49d7eSJed Brown /// // Check 1792e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 17939df49d7eSJed Brown /// assert!( 179480a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 17959df49d7eSJed Brown /// "Incorrect interval length computed" 17969df49d7eSJed Brown /// ); 1797c68be7a2SJeremy L Thompson /// # Ok(()) 1798c68be7a2SJeremy L Thompson /// # } 17999df49d7eSJed Brown /// ``` 1800594ef120SJeremy L Thompson pub fn create_multigrid_level_tensor_H1<'b>( 18019df49d7eSJed Brown &self, 18029df49d7eSJed Brown p_mult_fine: &Vector, 18039df49d7eSJed Brown rstr_coarse: &ElemRestriction, 18049df49d7eSJed Brown basis_coarse: &Basis, 180580a9ef05SNatalie Beams interpCtoF: &Vec<Scalar>, 1806594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 18079df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 18089df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 18099df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 18109df49d7eSJed Brown let ierr = unsafe { 18119df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateTensorH1( 18129df49d7eSJed Brown self.op_core.ptr, 18139df49d7eSJed Brown p_mult_fine.ptr, 18149df49d7eSJed Brown rstr_coarse.ptr, 18159df49d7eSJed Brown basis_coarse.ptr, 18169df49d7eSJed Brown interpCtoF.as_ptr(), 18179df49d7eSJed Brown &mut ptr_coarse, 18189df49d7eSJed Brown &mut ptr_prolong, 18199df49d7eSJed Brown &mut ptr_restrict, 18209df49d7eSJed Brown ) 18219df49d7eSJed Brown }; 18221142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 18231142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 18241142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 18251142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 18269df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 18279df49d7eSJed Brown } 18289df49d7eSJed Brown 18299df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 18309df49d7eSJed Brown /// given Operator with a non-tensor basis for the active basis 18319df49d7eSJed Brown /// 18329df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 18339df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 18349df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 18359df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 18369df49d7eSJed Brown /// 18379df49d7eSJed Brown /// ``` 18389df49d7eSJed Brown /// # use libceed::prelude::*; 18394d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 18409df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 18419df49d7eSJed Brown /// let ne = 15; 18429df49d7eSJed Brown /// let p_coarse = 3; 18439df49d7eSJed Brown /// let p_fine = 5; 18449df49d7eSJed Brown /// let q = 6; 18459df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 18469df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 18479df49d7eSJed Brown /// 18489df49d7eSJed Brown /// // Vectors 18499df49d7eSJed Brown /// let x_array = (0..ne + 1) 185080a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 185180a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1852c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1853c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 18549df49d7eSJed Brown /// qdata.set_value(0.0); 1855c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 18569df49d7eSJed Brown /// u_coarse.set_value(1.0); 1857c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 18589df49d7eSJed Brown /// u_fine.set_value(1.0); 1859c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 18609df49d7eSJed Brown /// v_coarse.set_value(0.0); 1861c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 18629df49d7eSJed Brown /// v_fine.set_value(0.0); 1863c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 18649df49d7eSJed Brown /// multiplicity.set_value(1.0); 18659df49d7eSJed Brown /// 18669df49d7eSJed Brown /// // Restrictions 18679df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1868c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 18699df49d7eSJed Brown /// 18709df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 18719df49d7eSJed Brown /// for i in 0..ne { 18729df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 18739df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 18749df49d7eSJed Brown /// } 1875c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 18769df49d7eSJed Brown /// 18779df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 18789df49d7eSJed Brown /// for i in 0..ne { 18799df49d7eSJed Brown /// for j in 0..p_coarse { 18809df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 18819df49d7eSJed Brown /// } 18829df49d7eSJed Brown /// } 1883c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 18849df49d7eSJed Brown /// ne, 18859df49d7eSJed Brown /// p_coarse, 18869df49d7eSJed Brown /// 1, 18879df49d7eSJed Brown /// 1, 18889df49d7eSJed Brown /// ndofs_coarse, 18899df49d7eSJed Brown /// MemType::Host, 18909df49d7eSJed Brown /// &indu_coarse, 1891c68be7a2SJeremy L Thompson /// )?; 18929df49d7eSJed Brown /// 18939df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 18949df49d7eSJed Brown /// for i in 0..ne { 18959df49d7eSJed Brown /// for j in 0..p_fine { 18969df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 18979df49d7eSJed Brown /// } 18989df49d7eSJed Brown /// } 1899c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 19009df49d7eSJed Brown /// 19019df49d7eSJed Brown /// // Bases 1902c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1903c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1904c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 19059df49d7eSJed Brown /// 19069df49d7eSJed Brown /// // Build quadrature data 1907c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1908c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1909c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1910c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1911c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1912c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 19139df49d7eSJed Brown /// 19149df49d7eSJed Brown /// // Mass operator 1915c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 19169df49d7eSJed Brown /// let op_mass_fine = ceed 1917c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1918c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1919c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1920c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 19219df49d7eSJed Brown /// 19229df49d7eSJed Brown /// // Multigrid setup 192380a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 19249df49d7eSJed Brown /// { 1925c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 1926c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 1927c68be7a2SJeremy L Thompson /// let basis_c_to_f = 1928c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 19299df49d7eSJed Brown /// for i in 0..p_coarse { 19309df49d7eSJed Brown /// coarse.set_value(0.0); 19319df49d7eSJed Brown /// { 1932e78171edSJeremy L Thompson /// let mut array = coarse.view_mut()?; 19339df49d7eSJed Brown /// array[i] = 1.; 19349df49d7eSJed Brown /// } 1935c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 19369df49d7eSJed Brown /// 1, 19379df49d7eSJed Brown /// TransposeMode::NoTranspose, 19389df49d7eSJed Brown /// EvalMode::Interp, 19399df49d7eSJed Brown /// &coarse, 19409df49d7eSJed Brown /// &mut fine, 1941c68be7a2SJeremy L Thompson /// )?; 1942e78171edSJeremy L Thompson /// let array = fine.view()?; 19439df49d7eSJed Brown /// for j in 0..p_fine { 19449df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 19459df49d7eSJed Brown /// } 19469df49d7eSJed Brown /// } 19479df49d7eSJed Brown /// } 1948c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_H1( 1949c68be7a2SJeremy L Thompson /// &multiplicity, 1950c68be7a2SJeremy L Thompson /// &ru_coarse, 1951c68be7a2SJeremy L Thompson /// &bu_coarse, 1952c68be7a2SJeremy L Thompson /// &interp_c_to_f, 1953c68be7a2SJeremy L Thompson /// )?; 19549df49d7eSJed Brown /// 19559df49d7eSJed Brown /// // Coarse problem 19569df49d7eSJed Brown /// u_coarse.set_value(1.0); 1957c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 19589df49d7eSJed Brown /// 19599df49d7eSJed Brown /// // Check 1960e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 19619df49d7eSJed Brown /// assert!( 196280a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 19639df49d7eSJed Brown /// "Incorrect interval length computed" 19649df49d7eSJed Brown /// ); 19659df49d7eSJed Brown /// 19669df49d7eSJed Brown /// // Prolong 1967c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 19689df49d7eSJed Brown /// 19699df49d7eSJed Brown /// // Fine problem 1970c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 19719df49d7eSJed Brown /// 19729df49d7eSJed Brown /// // Check 1973e78171edSJeremy L Thompson /// let sum: Scalar = v_fine.view()?.iter().sum(); 19749df49d7eSJed Brown /// assert!( 197580a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 19769df49d7eSJed Brown /// "Incorrect interval length computed" 19779df49d7eSJed Brown /// ); 19789df49d7eSJed Brown /// 19799df49d7eSJed Brown /// // Restrict 1980c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 19819df49d7eSJed Brown /// 19829df49d7eSJed Brown /// // Check 1983e78171edSJeremy L Thompson /// let sum: Scalar = v_coarse.view()?.iter().sum(); 19849df49d7eSJed Brown /// assert!( 198580a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 19869df49d7eSJed Brown /// "Incorrect interval length computed" 19879df49d7eSJed Brown /// ); 1988c68be7a2SJeremy L Thompson /// # Ok(()) 1989c68be7a2SJeremy L Thompson /// # } 19909df49d7eSJed Brown /// ``` 1991594ef120SJeremy L Thompson pub fn create_multigrid_level_H1<'b>( 19929df49d7eSJed Brown &self, 19939df49d7eSJed Brown p_mult_fine: &Vector, 19949df49d7eSJed Brown rstr_coarse: &ElemRestriction, 19959df49d7eSJed Brown basis_coarse: &Basis, 199680a9ef05SNatalie Beams interpCtoF: &[Scalar], 1997594ef120SJeremy L Thompson ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> { 19989df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 19999df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 20009df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 20019df49d7eSJed Brown let ierr = unsafe { 20029df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateH1( 20039df49d7eSJed Brown self.op_core.ptr, 20049df49d7eSJed Brown p_mult_fine.ptr, 20059df49d7eSJed Brown rstr_coarse.ptr, 20069df49d7eSJed Brown basis_coarse.ptr, 20079df49d7eSJed Brown interpCtoF.as_ptr(), 20089df49d7eSJed Brown &mut ptr_coarse, 20099df49d7eSJed Brown &mut ptr_prolong, 20109df49d7eSJed Brown &mut ptr_restrict, 20119df49d7eSJed Brown ) 20129df49d7eSJed Brown }; 20131142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 20141142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 20151142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 20161142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 20179df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 20189df49d7eSJed Brown } 20199df49d7eSJed Brown } 20209df49d7eSJed Brown 20219df49d7eSJed Brown // ----------------------------------------------------------------------------- 20229df49d7eSJed Brown // Composite Operator 20239df49d7eSJed Brown // ----------------------------------------------------------------------------- 20249df49d7eSJed Brown impl<'a> CompositeOperator<'a> { 20259df49d7eSJed Brown // Constructor 2026594ef120SJeremy L Thompson pub fn create(ceed: &crate::Ceed) -> crate::Result<Self> { 20279df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 20289df49d7eSJed Brown let ierr = unsafe { bind_ceed::CeedCompositeOperatorCreate(ceed.ptr, &mut ptr) }; 20299df49d7eSJed Brown ceed.check_error(ierr)?; 20309df49d7eSJed Brown Ok(Self { 20311142270cSJeremy L Thompson op_core: OperatorCore { 20321142270cSJeremy L Thompson ptr, 20331142270cSJeremy L Thompson _lifeline: PhantomData, 20341142270cSJeremy L Thompson }, 20359df49d7eSJed Brown }) 20369df49d7eSJed Brown } 20379df49d7eSJed Brown 20389df49d7eSJed Brown /// Apply Operator to a vector 20399df49d7eSJed Brown /// 20409df49d7eSJed Brown /// * `input` - Input Vector 20419df49d7eSJed Brown /// * `output` - Output Vector 20429df49d7eSJed Brown /// 20439df49d7eSJed Brown /// ``` 20449df49d7eSJed Brown /// # use libceed::prelude::*; 20454d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 20469df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 20479df49d7eSJed Brown /// let ne = 4; 20489df49d7eSJed Brown /// let p = 3; 20499df49d7eSJed Brown /// let q = 4; 20509df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 20519df49d7eSJed Brown /// 20529df49d7eSJed Brown /// // Vectors 2053c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 2054c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 20559df49d7eSJed Brown /// qdata_mass.set_value(0.0); 2056c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 20579df49d7eSJed Brown /// qdata_diff.set_value(0.0); 2058c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 20599df49d7eSJed Brown /// u.set_value(1.0); 2060c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 20619df49d7eSJed Brown /// v.set_value(0.0); 20629df49d7eSJed Brown /// 20639df49d7eSJed Brown /// // Restrictions 20649df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 20659df49d7eSJed Brown /// for i in 0..ne { 20669df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 20679df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 20689df49d7eSJed Brown /// } 2069c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 20709df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 20719df49d7eSJed Brown /// for i in 0..ne { 20729df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 20739df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 20749df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 20759df49d7eSJed Brown /// } 2076c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 20779df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2078c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 20799df49d7eSJed Brown /// 20809df49d7eSJed Brown /// // Bases 2081c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2082c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 20839df49d7eSJed Brown /// 20849df49d7eSJed Brown /// // Build quadrature data 2085c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 2086c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 2087c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2088c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2089c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2090c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 20919df49d7eSJed Brown /// 2092c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 2093c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 2094c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2095c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2096c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2097c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 20989df49d7eSJed Brown /// 20999df49d7eSJed Brown /// // Application operator 2100c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 21019df49d7eSJed Brown /// let op_mass = ceed 2102c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2103c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 2104c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 2105c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 21069df49d7eSJed Brown /// 2107c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 21089df49d7eSJed Brown /// let op_diff = ceed 2109c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2110c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 2111c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 2112c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 21139df49d7eSJed Brown /// 21149df49d7eSJed Brown /// let op_composite = ceed 2115c68be7a2SJeremy L Thompson /// .composite_operator()? 2116c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 2117c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 21189df49d7eSJed Brown /// 21199df49d7eSJed Brown /// v.set_value(0.0); 2120c68be7a2SJeremy L Thompson /// op_composite.apply(&u, &mut v)?; 21219df49d7eSJed Brown /// 21229df49d7eSJed Brown /// // Check 2123e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 21249df49d7eSJed Brown /// assert!( 212580a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 21269df49d7eSJed Brown /// "Incorrect interval length computed" 21279df49d7eSJed Brown /// ); 2128c68be7a2SJeremy L Thompson /// # Ok(()) 2129c68be7a2SJeremy L Thompson /// # } 21309df49d7eSJed Brown /// ``` 21319df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 21329df49d7eSJed Brown self.op_core.apply(input, output) 21339df49d7eSJed Brown } 21349df49d7eSJed Brown 21359df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 21369df49d7eSJed Brown /// 21379df49d7eSJed Brown /// * `input` - Input Vector 21389df49d7eSJed Brown /// * `output` - Output Vector 21399df49d7eSJed Brown /// 21409df49d7eSJed Brown /// ``` 21419df49d7eSJed Brown /// # use libceed::prelude::*; 21424d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 21439df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 21449df49d7eSJed Brown /// let ne = 4; 21459df49d7eSJed Brown /// let p = 3; 21469df49d7eSJed Brown /// let q = 4; 21479df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 21489df49d7eSJed Brown /// 21499df49d7eSJed Brown /// // Vectors 2150c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 2151c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 21529df49d7eSJed Brown /// qdata_mass.set_value(0.0); 2153c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 21549df49d7eSJed Brown /// qdata_diff.set_value(0.0); 2155c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 21569df49d7eSJed Brown /// u.set_value(1.0); 2157c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 21589df49d7eSJed Brown /// v.set_value(0.0); 21599df49d7eSJed Brown /// 21609df49d7eSJed Brown /// // Restrictions 21619df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 21629df49d7eSJed Brown /// for i in 0..ne { 21639df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 21649df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 21659df49d7eSJed Brown /// } 2166c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 21679df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 21689df49d7eSJed Brown /// for i in 0..ne { 21699df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 21709df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 21719df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 21729df49d7eSJed Brown /// } 2173c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 21749df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 2175c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 21769df49d7eSJed Brown /// 21779df49d7eSJed Brown /// // Bases 2178c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 2179c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 21809df49d7eSJed Brown /// 21819df49d7eSJed Brown /// // Build quadrature data 2182c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 2183c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 2184c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2185c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2186c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2187c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 21889df49d7eSJed Brown /// 2189c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 2190c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 2191c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 2192c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 2193c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 2194c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 21959df49d7eSJed Brown /// 21969df49d7eSJed Brown /// // Application operator 2197c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 21989df49d7eSJed Brown /// let op_mass = ceed 2199c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 2200c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 2201c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 2202c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 22039df49d7eSJed Brown /// 2204c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 22059df49d7eSJed Brown /// let op_diff = ceed 2206c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 2207c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 2208c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 2209c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 22109df49d7eSJed Brown /// 22119df49d7eSJed Brown /// let op_composite = ceed 2212c68be7a2SJeremy L Thompson /// .composite_operator()? 2213c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 2214c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 22159df49d7eSJed Brown /// 22169df49d7eSJed Brown /// v.set_value(1.0); 2217c68be7a2SJeremy L Thompson /// op_composite.apply_add(&u, &mut v)?; 22189df49d7eSJed Brown /// 22199df49d7eSJed Brown /// // Check 2220e78171edSJeremy L Thompson /// let sum: Scalar = v.view()?.iter().sum(); 22219df49d7eSJed Brown /// assert!( 222280a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 22239df49d7eSJed Brown /// "Incorrect interval length computed" 22249df49d7eSJed Brown /// ); 2225c68be7a2SJeremy L Thompson /// # Ok(()) 2226c68be7a2SJeremy L Thompson /// # } 22279df49d7eSJed Brown /// ``` 22289df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 22299df49d7eSJed Brown self.op_core.apply_add(input, output) 22309df49d7eSJed Brown } 22319df49d7eSJed Brown 22329df49d7eSJed Brown /// Add a sub-Operator to a Composite Operator 22339df49d7eSJed Brown /// 22349df49d7eSJed Brown /// * `subop` - Sub-Operator 22359df49d7eSJed Brown /// 22369df49d7eSJed Brown /// ``` 22379df49d7eSJed Brown /// # use libceed::prelude::*; 22384d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> { 22399df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 2240c68be7a2SJeremy L Thompson /// let mut op = ceed.composite_operator()?; 22419df49d7eSJed Brown /// 2242c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 2243c68be7a2SJeremy L Thompson /// let op_mass = ceed.operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?; 2244c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_mass)?; 22459df49d7eSJed Brown /// 2246c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 2247c68be7a2SJeremy L Thompson /// let op_diff = ceed.operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?; 2248c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_diff)?; 2249c68be7a2SJeremy L Thompson /// # Ok(()) 2250c68be7a2SJeremy L Thompson /// # } 22519df49d7eSJed Brown /// ``` 22529df49d7eSJed Brown #[allow(unused_mut)] 22539df49d7eSJed Brown pub fn sub_operator(mut self, subop: &Operator) -> crate::Result<Self> { 22549df49d7eSJed Brown let ierr = 22559df49d7eSJed Brown unsafe { bind_ceed::CeedCompositeOperatorAddSub(self.op_core.ptr, subop.op_core.ptr) }; 22561142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 22579df49d7eSJed Brown Ok(self) 22589df49d7eSJed Brown } 22599df49d7eSJed Brown 22606f97ff0aSJeremy L Thompson /// Check if CompositeOperator is setup correctly 22616f97ff0aSJeremy L Thompson /// 22626f97ff0aSJeremy L Thompson /// ``` 22636f97ff0aSJeremy L Thompson /// # use libceed::prelude::*; 22646f97ff0aSJeremy L Thompson /// # fn main() -> libceed::Result<()> { 22656f97ff0aSJeremy L Thompson /// # let ceed = libceed::Ceed::default_init(); 22666f97ff0aSJeremy L Thompson /// let ne = 4; 22676f97ff0aSJeremy L Thompson /// let p = 3; 22686f97ff0aSJeremy L Thompson /// let q = 4; 22696f97ff0aSJeremy L Thompson /// let ndofs = p * ne - ne + 1; 22706f97ff0aSJeremy L Thompson /// 22716f97ff0aSJeremy L Thompson /// // Restrictions 22726f97ff0aSJeremy L Thompson /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 22736f97ff0aSJeremy L Thompson /// for i in 0..ne { 22746f97ff0aSJeremy L Thompson /// indx[2 * i + 0] = i as i32; 22756f97ff0aSJeremy L Thompson /// indx[2 * i + 1] = (i + 1) as i32; 22766f97ff0aSJeremy L Thompson /// } 22776f97ff0aSJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 22786f97ff0aSJeremy L Thompson /// let strides: [i32; 3] = [1, q as i32, q as i32]; 22796f97ff0aSJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 22806f97ff0aSJeremy L Thompson /// 22816f97ff0aSJeremy L Thompson /// // Bases 22826f97ff0aSJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 22836f97ff0aSJeremy L Thompson /// 22846f97ff0aSJeremy L Thompson /// // Build quadrature data 22856f97ff0aSJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 22866f97ff0aSJeremy L Thompson /// let op_build_mass = ceed 22876f97ff0aSJeremy L Thompson /// .operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 22886f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 22896f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 22906f97ff0aSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 22916f97ff0aSJeremy L Thompson /// 22926f97ff0aSJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 22936f97ff0aSJeremy L Thompson /// let op_build_diff = ceed 22946f97ff0aSJeremy L Thompson /// .operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 22956f97ff0aSJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 22966f97ff0aSJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 22976f97ff0aSJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 22986f97ff0aSJeremy L Thompson /// 22996f97ff0aSJeremy L Thompson /// let op_build = ceed 23006f97ff0aSJeremy L Thompson /// .composite_operator()? 23016f97ff0aSJeremy L Thompson /// .sub_operator(&op_build_mass)? 23026f97ff0aSJeremy L Thompson /// .sub_operator(&op_build_diff)?; 23036f97ff0aSJeremy L Thompson /// 23046f97ff0aSJeremy L Thompson /// // Check 23056f97ff0aSJeremy L Thompson /// assert!(op_build.check().is_ok(), "Operator setup incorrectly"); 23066f97ff0aSJeremy L Thompson /// # Ok(()) 23076f97ff0aSJeremy L Thompson /// # } 23086f97ff0aSJeremy L Thompson /// ``` 23096f97ff0aSJeremy L Thompson pub fn check(self) -> crate::Result<Self> { 23106f97ff0aSJeremy L Thompson self.op_core.check()?; 23116f97ff0aSJeremy L Thompson Ok(self) 23126f97ff0aSJeremy L Thompson } 23136f97ff0aSJeremy L Thompson 23149df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 23159df49d7eSJed Brown /// 23169df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 23179df49d7eSJed Brown /// 23189df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 23199df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 23209df49d7eSJed Brown /// 23219df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 23229df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 23239df49d7eSJed Brown pub fn linear_asssemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 23249df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 23259df49d7eSJed Brown } 23269df49d7eSJed Brown 23279df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 23289df49d7eSJed Brown /// 23299df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 23309df49d7eSJed Brown /// Operator. 23319df49d7eSJed Brown /// 23329df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 23339df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 23349df49d7eSJed Brown /// 23359df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 23369df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 23379df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 23389df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 23399df49d7eSJed Brown } 23409df49d7eSJed Brown 23419df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 23429df49d7eSJed Brown /// 23439df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 23449df49d7eSJed Brown /// 23459df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 23469df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 23479df49d7eSJed Brown /// 23489df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 23499df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 23509df49d7eSJed Brown /// diagonal, provided in row-major form with an 23519df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 23529df49d7eSJed Brown /// this vector are derived from the active vector for 23539df49d7eSJed Brown /// the CeedOperator. The array has shape 23549df49d7eSJed Brown /// `[nodes, component out, component in]`. 23559df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 23569df49d7eSJed Brown &self, 23579df49d7eSJed Brown assembled: &mut Vector, 23589df49d7eSJed Brown ) -> crate::Result<i32> { 23599df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 23609df49d7eSJed Brown } 23619df49d7eSJed Brown 23629df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 23639df49d7eSJed Brown /// 23649df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 23659df49d7eSJed Brown /// 23669df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 23679df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 23689df49d7eSJed Brown /// 23699df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 23709df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 23719df49d7eSJed Brown /// diagonal, provided in row-major form with an 23729df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 23739df49d7eSJed Brown /// this vector are derived from the active vector for 23749df49d7eSJed Brown /// the CeedOperator. The array has shape 23759df49d7eSJed Brown /// `[nodes, component out, component in]`. 23769df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 23779df49d7eSJed Brown &self, 23789df49d7eSJed Brown assembled: &mut Vector, 23799df49d7eSJed Brown ) -> crate::Result<i32> { 23809df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 23819df49d7eSJed Brown } 23829df49d7eSJed Brown } 23839df49d7eSJed Brown 23849df49d7eSJed Brown // ----------------------------------------------------------------------------- 2385