xref: /libCEED/rust/libceed/src/operator.rs (revision 4b61a5a04425d85ec42b770771dd05c355ddbfd8)
13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
39df49d7eSJed Brown //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
59df49d7eSJed Brown //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
79df49d7eSJed Brown 
89df49d7eSJed Brown //! A Ceed Operator defines the finite/spectral element operator associated to a
99df49d7eSJed Brown //! Ceed QFunction. A Ceed Operator connects Ceed ElemRestrictions,
109df49d7eSJed Brown //! Ceed Bases, and Ceed QFunctions.
119df49d7eSJed Brown 
129df49d7eSJed Brown use crate::prelude::*;
139df49d7eSJed Brown 
149df49d7eSJed Brown // -----------------------------------------------------------------------------
157ed177dbSJed Brown // Operator Field context wrapper
1608778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
1708778c6fSJeremy L Thompson #[derive(Debug)]
1808778c6fSJeremy L Thompson pub struct OperatorField<'a> {
1908778c6fSJeremy L Thompson     pub(crate) ptr: bind_ceed::CeedOperatorField,
2008778c6fSJeremy L Thompson     _lifeline: PhantomData<&'a ()>,
2108778c6fSJeremy L Thompson }
2208778c6fSJeremy L Thompson 
2308778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
2408778c6fSJeremy L Thompson // Implementations
2508778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
2608778c6fSJeremy L Thompson impl<'a> OperatorField<'a> {
2708778c6fSJeremy L Thompson     /// Get the name of an OperatorField
2808778c6fSJeremy L Thompson     ///
2908778c6fSJeremy L Thompson     /// ```
3008778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
314d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
3208778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
3308778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
3408778c6fSJeremy L Thompson     ///
3508778c6fSJeremy L Thompson     /// // Operator field arguments
3608778c6fSJeremy L Thompson     /// let ne = 3;
3708778c6fSJeremy L Thompson     /// let q = 4 as usize;
3808778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
3908778c6fSJeremy L Thompson     /// for i in 0..ne {
4008778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
4108778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
4208778c6fSJeremy L Thompson     /// }
4308778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
4408778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
45d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
4608778c6fSJeremy L Thompson     ///
4708778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
4808778c6fSJeremy L Thompson     ///
4908778c6fSJeremy L Thompson     /// // Operator fields
5008778c6fSJeremy L Thompson     /// let op = ceed
5108778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
5208778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
5308778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
54356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, 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];
89d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
9008778c6fSJeremy L Thompson     ///
9108778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
9208778c6fSJeremy L Thompson     ///
9308778c6fSJeremy L Thompson     /// // Operator fields
9408778c6fSJeremy L Thompson     /// let op = ceed
9508778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
9608778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
9708778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
98356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, 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];
157d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
15808778c6fSJeremy L Thompson     ///
15908778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
16008778c6fSJeremy L Thompson     ///
16108778c6fSJeremy L Thompson     /// // Operator fields
16208778c6fSJeremy L Thompson     /// let op = ceed
16308778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
16408778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
16508778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
166356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, 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     ///
189356036faSJeremy L Thompson     /// assert!(outputs[0].basis().is_none(), "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         }
198356036faSJeremy L Thompson         if ptr == unsafe { bind_ceed::CEED_BASIS_NONE } {
199356036faSJeremy L Thompson             BasisOpt::None
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];
229d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
23008778c6fSJeremy L Thompson     ///
23108778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
23208778c6fSJeremy L Thompson     ///
23308778c6fSJeremy L Thompson     /// // Operator fields
23408778c6fSJeremy L Thompson     /// let op = ceed
23508778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
23608778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
23708778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
238356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, 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];
333d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
3349df49d7eSJed Brown ///
335c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
3369df49d7eSJed Brown ///
3379df49d7eSJed Brown /// // Operator fields
3389df49d7eSJed Brown /// let op = ceed
339c68be7a2SJeremy L Thompson ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
340ea6b5821SJeremy L Thompson ///     .name("mass")?
341c68be7a2SJeremy L Thompson ///     .field("dx", &r, &b, VectorOpt::Active)?
342c68be7a2SJeremy L Thompson ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
343356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
3449df49d7eSJed Brown ///
3459df49d7eSJed Brown /// println!("{}", op);
346c68be7a2SJeremy L Thompson /// # Ok(())
347c68be7a2SJeremy L Thompson /// # }
3489df49d7eSJed Brown /// ```
3499df49d7eSJed Brown impl<'a> fmt::Display for Operator<'a> {
3509df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3519df49d7eSJed Brown         self.op_core.fmt(f)
3529df49d7eSJed Brown     }
3539df49d7eSJed Brown }
3549df49d7eSJed Brown 
3559df49d7eSJed Brown /// View a composite Operator
3569df49d7eSJed Brown ///
3579df49d7eSJed Brown /// ```
3589df49d7eSJed Brown /// # use libceed::prelude::*;
3594d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
3609df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
3619df49d7eSJed Brown ///
3629df49d7eSJed Brown /// // Sub operator field arguments
3639df49d7eSJed Brown /// let ne = 3;
3649df49d7eSJed Brown /// let q = 4 as usize;
3659df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne];
3669df49d7eSJed Brown /// for i in 0..ne {
3679df49d7eSJed Brown ///     ind[2 * i + 0] = i as i32;
3689df49d7eSJed Brown ///     ind[2 * i + 1] = (i + 1) as i32;
3699df49d7eSJed Brown /// }
370c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
3719df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32];
372d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
3739df49d7eSJed Brown ///
374c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
3759df49d7eSJed Brown ///
376c68be7a2SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?;
377c68be7a2SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?;
3789df49d7eSJed Brown ///
379c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
3809df49d7eSJed Brown /// let op_mass = ceed
381c68be7a2SJeremy L Thompson ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
382ea6b5821SJeremy L Thompson ///     .name("Mass term")?
383c68be7a2SJeremy L Thompson ///     .field("u", &r, &b, VectorOpt::Active)?
384356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
385c68be7a2SJeremy L Thompson ///     .field("v", &r, &b, VectorOpt::Active)?;
3869df49d7eSJed Brown ///
387c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
3889df49d7eSJed Brown /// let op_diff = ceed
389c68be7a2SJeremy L Thompson ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
390ea6b5821SJeremy L Thompson ///     .name("Poisson term")?
391c68be7a2SJeremy L Thompson ///     .field("du", &r, &b, VectorOpt::Active)?
392356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
393c68be7a2SJeremy L Thompson ///     .field("dv", &r, &b, VectorOpt::Active)?;
3949df49d7eSJed Brown ///
3959df49d7eSJed Brown /// let op = ceed
396c68be7a2SJeremy L Thompson ///     .composite_operator()?
397ea6b5821SJeremy L Thompson ///     .name("Screened Poisson")?
398c68be7a2SJeremy L Thompson ///     .sub_operator(&op_mass)?
399c68be7a2SJeremy L Thompson ///     .sub_operator(&op_diff)?;
4009df49d7eSJed Brown ///
4019df49d7eSJed Brown /// println!("{}", op);
402c68be7a2SJeremy L Thompson /// # Ok(())
403c68be7a2SJeremy L Thompson /// # }
4049df49d7eSJed Brown /// ```
4059df49d7eSJed Brown impl<'a> fmt::Display for CompositeOperator<'a> {
4069df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4079df49d7eSJed Brown         self.op_core.fmt(f)
4089df49d7eSJed Brown     }
4099df49d7eSJed Brown }
4109df49d7eSJed Brown 
4119df49d7eSJed Brown // -----------------------------------------------------------------------------
4129df49d7eSJed Brown // Core functionality
4139df49d7eSJed Brown // -----------------------------------------------------------------------------
4149df49d7eSJed Brown impl<'a> OperatorCore<'a> {
4151142270cSJeremy L Thompson     // Error handling
4161142270cSJeremy L Thompson     #[doc(hidden)]
4171142270cSJeremy L Thompson     fn check_error(&self, ierr: i32) -> crate::Result<i32> {
4181142270cSJeremy L Thompson         let mut ptr = std::ptr::null_mut();
4191142270cSJeremy L Thompson         unsafe {
4201142270cSJeremy L Thompson             bind_ceed::CeedOperatorGetCeed(self.ptr, &mut ptr);
4211142270cSJeremy L Thompson         }
4221142270cSJeremy L Thompson         crate::check_error(ptr, ierr)
4231142270cSJeremy L Thompson     }
4241142270cSJeremy L Thompson 
4259df49d7eSJed Brown     // Common implementations
4266f97ff0aSJeremy L Thompson     pub fn check(&self) -> crate::Result<i32> {
4276f97ff0aSJeremy L Thompson         let ierr = unsafe { bind_ceed::CeedOperatorCheckReady(self.ptr) };
4286f97ff0aSJeremy L Thompson         self.check_error(ierr)
4296f97ff0aSJeremy L Thompson     }
4306f97ff0aSJeremy L Thompson 
431ea6b5821SJeremy L Thompson     pub fn name(&self, name: &str) -> crate::Result<i32> {
432ea6b5821SJeremy L Thompson         let name_c = CString::new(name).expect("CString::new failed");
433ea6b5821SJeremy L Thompson         let ierr = unsafe { bind_ceed::CeedOperatorSetName(self.ptr, name_c.as_ptr()) };
434ea6b5821SJeremy L Thompson         self.check_error(ierr)
435ea6b5821SJeremy L Thompson     }
436ea6b5821SJeremy L Thompson 
4379df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
4389df49d7eSJed Brown         let ierr = unsafe {
4399df49d7eSJed Brown             bind_ceed::CeedOperatorApply(
4409df49d7eSJed Brown                 self.ptr,
4419df49d7eSJed Brown                 input.ptr,
4429df49d7eSJed Brown                 output.ptr,
4439df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4449df49d7eSJed Brown             )
4459df49d7eSJed Brown         };
4461142270cSJeremy L Thompson         self.check_error(ierr)
4479df49d7eSJed Brown     }
4489df49d7eSJed Brown 
4499df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
4509df49d7eSJed Brown         let ierr = unsafe {
4519df49d7eSJed Brown             bind_ceed::CeedOperatorApplyAdd(
4529df49d7eSJed Brown                 self.ptr,
4539df49d7eSJed Brown                 input.ptr,
4549df49d7eSJed Brown                 output.ptr,
4559df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4569df49d7eSJed Brown             )
4579df49d7eSJed Brown         };
4581142270cSJeremy L Thompson         self.check_error(ierr)
4599df49d7eSJed Brown     }
4609df49d7eSJed Brown 
4619df49d7eSJed Brown     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
4629df49d7eSJed Brown         let ierr = unsafe {
4639df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleDiagonal(
4649df49d7eSJed Brown                 self.ptr,
4659df49d7eSJed Brown                 assembled.ptr,
4669df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4679df49d7eSJed Brown             )
4689df49d7eSJed Brown         };
4691142270cSJeremy L Thompson         self.check_error(ierr)
4709df49d7eSJed Brown     }
4719df49d7eSJed Brown 
4729df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
4739df49d7eSJed Brown         let ierr = unsafe {
4749df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleAddDiagonal(
4759df49d7eSJed Brown                 self.ptr,
4769df49d7eSJed Brown                 assembled.ptr,
4779df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4789df49d7eSJed Brown             )
4799df49d7eSJed Brown         };
4801142270cSJeremy L Thompson         self.check_error(ierr)
4819df49d7eSJed Brown     }
4829df49d7eSJed Brown 
4839df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
4849df49d7eSJed Brown         &self,
4859df49d7eSJed Brown         assembled: &mut Vector,
4869df49d7eSJed Brown     ) -> crate::Result<i32> {
4879df49d7eSJed Brown         let ierr = unsafe {
4889df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssemblePointBlockDiagonal(
4899df49d7eSJed Brown                 self.ptr,
4909df49d7eSJed Brown                 assembled.ptr,
4919df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4929df49d7eSJed Brown             )
4939df49d7eSJed Brown         };
4941142270cSJeremy L Thompson         self.check_error(ierr)
4959df49d7eSJed Brown     }
4969df49d7eSJed Brown 
4979df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
4989df49d7eSJed Brown         &self,
4999df49d7eSJed Brown         assembled: &mut Vector,
5009df49d7eSJed Brown     ) -> crate::Result<i32> {
5019df49d7eSJed Brown         let ierr = unsafe {
5029df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleAddPointBlockDiagonal(
5039df49d7eSJed Brown                 self.ptr,
5049df49d7eSJed Brown                 assembled.ptr,
5059df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
5069df49d7eSJed Brown             )
5079df49d7eSJed Brown         };
5081142270cSJeremy L Thompson         self.check_error(ierr)
5099df49d7eSJed Brown     }
5109df49d7eSJed Brown }
5119df49d7eSJed Brown 
5129df49d7eSJed Brown // -----------------------------------------------------------------------------
5139df49d7eSJed Brown // Operator
5149df49d7eSJed Brown // -----------------------------------------------------------------------------
5159df49d7eSJed Brown impl<'a> Operator<'a> {
5169df49d7eSJed Brown     // Constructor
5179df49d7eSJed Brown     pub fn create<'b>(
518594ef120SJeremy L Thompson         ceed: &crate::Ceed,
5199df49d7eSJed Brown         qf: impl Into<QFunctionOpt<'b>>,
5209df49d7eSJed Brown         dqf: impl Into<QFunctionOpt<'b>>,
5219df49d7eSJed Brown         dqfT: impl Into<QFunctionOpt<'b>>,
5229df49d7eSJed Brown     ) -> crate::Result<Self> {
5239df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
5249df49d7eSJed Brown         let ierr = unsafe {
5259df49d7eSJed Brown             bind_ceed::CeedOperatorCreate(
5269df49d7eSJed Brown                 ceed.ptr,
5279df49d7eSJed Brown                 qf.into().to_raw(),
5289df49d7eSJed Brown                 dqf.into().to_raw(),
5299df49d7eSJed Brown                 dqfT.into().to_raw(),
5309df49d7eSJed Brown                 &mut ptr,
5319df49d7eSJed Brown             )
5329df49d7eSJed Brown         };
5339df49d7eSJed Brown         ceed.check_error(ierr)?;
5349df49d7eSJed Brown         Ok(Self {
5351142270cSJeremy L Thompson             op_core: OperatorCore {
5361142270cSJeremy L Thompson                 ptr,
5371142270cSJeremy L Thompson                 _lifeline: PhantomData,
5381142270cSJeremy L Thompson             },
5399df49d7eSJed Brown         })
5409df49d7eSJed Brown     }
5419df49d7eSJed Brown 
5421142270cSJeremy L Thompson     fn from_raw(ptr: bind_ceed::CeedOperator) -> crate::Result<Self> {
5439df49d7eSJed Brown         Ok(Self {
5441142270cSJeremy L Thompson             op_core: OperatorCore {
5451142270cSJeremy L Thompson                 ptr,
5461142270cSJeremy L Thompson                 _lifeline: PhantomData,
5471142270cSJeremy L Thompson             },
5489df49d7eSJed Brown         })
5499df49d7eSJed Brown     }
5509df49d7eSJed Brown 
551ea6b5821SJeremy L Thompson     /// Set name for Operator printing
552ea6b5821SJeremy L Thompson     ///
553ea6b5821SJeremy L Thompson     /// * 'name' - Name to set
554ea6b5821SJeremy L Thompson     ///
555ea6b5821SJeremy L Thompson     /// ```
556ea6b5821SJeremy L Thompson     /// # use libceed::prelude::*;
557ea6b5821SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
558ea6b5821SJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
559ea6b5821SJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
560ea6b5821SJeremy L Thompson     ///
561ea6b5821SJeremy L Thompson     /// // Operator field arguments
562ea6b5821SJeremy L Thompson     /// let ne = 3;
563ea6b5821SJeremy L Thompson     /// let q = 4 as usize;
564ea6b5821SJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
565ea6b5821SJeremy L Thompson     /// for i in 0..ne {
566ea6b5821SJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
567ea6b5821SJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
568ea6b5821SJeremy L Thompson     /// }
569ea6b5821SJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
570ea6b5821SJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
571d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
572ea6b5821SJeremy L Thompson     ///
573ea6b5821SJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
574ea6b5821SJeremy L Thompson     ///
575ea6b5821SJeremy L Thompson     /// // Operator fields
576ea6b5821SJeremy L Thompson     /// let op = ceed
577ea6b5821SJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
578ea6b5821SJeremy L Thompson     ///     .name("mass")?
579ea6b5821SJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
580ea6b5821SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
581356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
582ea6b5821SJeremy L Thompson     /// # Ok(())
583ea6b5821SJeremy L Thompson     /// # }
584ea6b5821SJeremy L Thompson     /// ```
585ea6b5821SJeremy L Thompson     #[allow(unused_mut)]
586ea6b5821SJeremy L Thompson     pub fn name(mut self, name: &str) -> crate::Result<Self> {
587ea6b5821SJeremy L Thompson         self.op_core.name(name)?;
588ea6b5821SJeremy L Thompson         Ok(self)
589ea6b5821SJeremy L Thompson     }
590ea6b5821SJeremy L Thompson 
5919df49d7eSJed Brown     /// Apply Operator to a vector
5929df49d7eSJed Brown     ///
5939df49d7eSJed Brown     /// * `input`  - Input Vector
5949df49d7eSJed Brown     /// * `output` - Output Vector
5959df49d7eSJed Brown     ///
5969df49d7eSJed Brown     /// ```
5979df49d7eSJed Brown     /// # use libceed::prelude::*;
5984d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
5999df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
6009df49d7eSJed Brown     /// let ne = 4;
6019df49d7eSJed Brown     /// let p = 3;
6029df49d7eSJed Brown     /// let q = 4;
6039df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
6049df49d7eSJed Brown     ///
6059df49d7eSJed Brown     /// // Vectors
606c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
607c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
6089df49d7eSJed Brown     /// qdata.set_value(0.0);
609c68be7a2SJeremy L Thompson     /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?;
610c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
6119df49d7eSJed Brown     /// v.set_value(0.0);
6129df49d7eSJed Brown     ///
6139df49d7eSJed Brown     /// // Restrictions
6149df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
6159df49d7eSJed Brown     /// for i in 0..ne {
6169df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
6179df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
6189df49d7eSJed Brown     /// }
619c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
6209df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
6219df49d7eSJed Brown     /// for i in 0..ne {
6229df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
6239df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
6249df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
6259df49d7eSJed Brown     /// }
626c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
6279df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
628c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
6299df49d7eSJed Brown     ///
6309df49d7eSJed Brown     /// // Bases
631c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
632c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
6339df49d7eSJed Brown     ///
6349df49d7eSJed Brown     /// // Build quadrature data
635c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
636c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
637c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
638c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
639356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
640c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
6419df49d7eSJed Brown     ///
6429df49d7eSJed Brown     /// // Mass operator
643c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
6449df49d7eSJed Brown     /// let op_mass = ceed
645c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
646c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
647356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
648c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
6499df49d7eSJed Brown     ///
6509df49d7eSJed Brown     /// v.set_value(0.0);
651c68be7a2SJeremy L Thompson     /// op_mass.apply(&u, &mut v)?;
6529df49d7eSJed Brown     ///
6539df49d7eSJed Brown     /// // Check
654e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
655*4b61a5a0SRezgar Shakeri     /// let error: Scalar = (sum - 2.0).abs();
6569df49d7eSJed Brown     /// assert!(
657*4b61a5a0SRezgar Shakeri     ///     error < 50.0 * libceed::EPSILON,
658*4b61a5a0SRezgar Shakeri     ///     "Incorrect interval length computed. Expected: 2.0, Found: {}, Error: {:.12e}",
659*4b61a5a0SRezgar Shakeri     ///     sum,
660*4b61a5a0SRezgar Shakeri     ///     error
6619df49d7eSJed Brown     /// );
662c68be7a2SJeremy L Thompson     /// # Ok(())
663c68be7a2SJeremy L Thompson     /// # }
6649df49d7eSJed Brown     /// ```
6659df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
6669df49d7eSJed Brown         self.op_core.apply(input, output)
6679df49d7eSJed Brown     }
6689df49d7eSJed Brown 
6699df49d7eSJed Brown     /// Apply Operator to a vector and add result to output vector
6709df49d7eSJed Brown     ///
6719df49d7eSJed Brown     /// * `input`  - Input Vector
6729df49d7eSJed Brown     /// * `output` - Output Vector
6739df49d7eSJed Brown     ///
6749df49d7eSJed Brown     /// ```
6759df49d7eSJed Brown     /// # use libceed::prelude::*;
6764d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
6779df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
6789df49d7eSJed Brown     /// let ne = 4;
6799df49d7eSJed Brown     /// let p = 3;
6809df49d7eSJed Brown     /// let q = 4;
6819df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
6829df49d7eSJed Brown     ///
6839df49d7eSJed Brown     /// // Vectors
684c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
685c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
6869df49d7eSJed Brown     /// qdata.set_value(0.0);
687c68be7a2SJeremy L Thompson     /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?;
688c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
6899df49d7eSJed Brown     ///
6909df49d7eSJed Brown     /// // Restrictions
6919df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
6929df49d7eSJed Brown     /// for i in 0..ne {
6939df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
6949df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
6959df49d7eSJed Brown     /// }
696c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
6979df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
6989df49d7eSJed Brown     /// for i in 0..ne {
6999df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
7009df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
7019df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
7029df49d7eSJed Brown     /// }
703c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
7049df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
705c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
7069df49d7eSJed Brown     ///
7079df49d7eSJed Brown     /// // Bases
708c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
709c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
7109df49d7eSJed Brown     ///
7119df49d7eSJed Brown     /// // Build quadrature data
712c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
713c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
714c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
715c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
716356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
717c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
7189df49d7eSJed Brown     ///
7199df49d7eSJed Brown     /// // Mass operator
720c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
7219df49d7eSJed Brown     /// let op_mass = ceed
722c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
723c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
724356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
725c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
7269df49d7eSJed Brown     ///
7279df49d7eSJed Brown     /// v.set_value(1.0);
728c68be7a2SJeremy L Thompson     /// op_mass.apply_add(&u, &mut v)?;
7299df49d7eSJed Brown     ///
7309df49d7eSJed Brown     /// // Check
731e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
7329df49d7eSJed Brown     /// assert!(
73380a9ef05SNatalie Beams     ///     (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON,
7349df49d7eSJed Brown     ///     "Incorrect interval length computed and added"
7359df49d7eSJed Brown     /// );
736c68be7a2SJeremy L Thompson     /// # Ok(())
737c68be7a2SJeremy L Thompson     /// # }
7389df49d7eSJed Brown     /// ```
7399df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
7409df49d7eSJed Brown         self.op_core.apply_add(input, output)
7419df49d7eSJed Brown     }
7429df49d7eSJed Brown 
7439df49d7eSJed Brown     /// Provide a field to a Operator for use by its QFunction
7449df49d7eSJed Brown     ///
7459df49d7eSJed Brown     /// * `fieldname` - Name of the field (to be matched with the name used by
7469df49d7eSJed Brown     ///                   the QFunction)
7479df49d7eSJed Brown     /// * `r`         - ElemRestriction
748356036faSJeremy L Thompson     /// * `b`         - Basis in which the field resides or `BasisOpt::None`
749356036faSJeremy L Thompson     /// * `v`         - Vector to be used by Operator or `VectorOpt::Active` if field
750356036faSJeremy L Thompson     ///                   is active or `VectorOpt::None` if using `Weight` with the
7519df49d7eSJed Brown     ///                   QFunction
7529df49d7eSJed Brown     ///
7539df49d7eSJed Brown     ///
7549df49d7eSJed Brown     /// ```
7559df49d7eSJed Brown     /// # use libceed::prelude::*;
7564d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
7579df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
758c68be7a2SJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
759c68be7a2SJeremy L Thompson     /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;
7609df49d7eSJed Brown     ///
7619df49d7eSJed Brown     /// // Operator field arguments
7629df49d7eSJed Brown     /// let ne = 3;
7639df49d7eSJed Brown     /// let q = 4;
7649df49d7eSJed Brown     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
7659df49d7eSJed Brown     /// for i in 0..ne {
7669df49d7eSJed Brown     ///     ind[2 * i + 0] = i as i32;
7679df49d7eSJed Brown     ///     ind[2 * i + 1] = (i + 1) as i32;
7689df49d7eSJed Brown     /// }
769c68be7a2SJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
7709df49d7eSJed Brown     ///
771c68be7a2SJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
7729df49d7eSJed Brown     ///
7739df49d7eSJed Brown     /// // Operator field
774c68be7a2SJeremy L Thompson     /// op = op.field("dx", &r, &b, VectorOpt::Active)?;
775c68be7a2SJeremy L Thompson     /// # Ok(())
776c68be7a2SJeremy L Thompson     /// # }
7779df49d7eSJed Brown     /// ```
7789df49d7eSJed Brown     #[allow(unused_mut)]
7799df49d7eSJed Brown     pub fn field<'b>(
7809df49d7eSJed Brown         mut self,
7819df49d7eSJed Brown         fieldname: &str,
7829df49d7eSJed Brown         r: impl Into<ElemRestrictionOpt<'b>>,
7839df49d7eSJed Brown         b: impl Into<BasisOpt<'b>>,
7849df49d7eSJed Brown         v: impl Into<VectorOpt<'b>>,
7859df49d7eSJed Brown     ) -> crate::Result<Self> {
7869df49d7eSJed Brown         let fieldname = CString::new(fieldname).expect("CString::new failed");
7879df49d7eSJed Brown         let fieldname = fieldname.as_ptr() as *const i8;
7889df49d7eSJed Brown         let ierr = unsafe {
7899df49d7eSJed Brown             bind_ceed::CeedOperatorSetField(
7909df49d7eSJed Brown                 self.op_core.ptr,
7919df49d7eSJed Brown                 fieldname,
7929df49d7eSJed Brown                 r.into().to_raw(),
7939df49d7eSJed Brown                 b.into().to_raw(),
7949df49d7eSJed Brown                 v.into().to_raw(),
7959df49d7eSJed Brown             )
7969df49d7eSJed Brown         };
7971142270cSJeremy L Thompson         self.op_core.check_error(ierr)?;
7989df49d7eSJed Brown         Ok(self)
7999df49d7eSJed Brown     }
8009df49d7eSJed Brown 
80108778c6fSJeremy L Thompson     /// Get a slice of Operator inputs
80208778c6fSJeremy L Thompson     ///
80308778c6fSJeremy L Thompson     /// ```
80408778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
8054d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
80608778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
80708778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
80808778c6fSJeremy L Thompson     ///
80908778c6fSJeremy L Thompson     /// // Operator field arguments
81008778c6fSJeremy L Thompson     /// let ne = 3;
81108778c6fSJeremy L Thompson     /// let q = 4 as usize;
81208778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
81308778c6fSJeremy L Thompson     /// for i in 0..ne {
81408778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
81508778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
81608778c6fSJeremy L Thompson     /// }
81708778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
81808778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
819d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
82008778c6fSJeremy L Thompson     ///
82108778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
82208778c6fSJeremy L Thompson     ///
82308778c6fSJeremy L Thompson     /// // Operator fields
82408778c6fSJeremy L Thompson     /// let op = ceed
82508778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
82608778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
82708778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
828356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
82908778c6fSJeremy L Thompson     ///
83008778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
83108778c6fSJeremy L Thompson     ///
83208778c6fSJeremy L Thompson     /// assert_eq!(inputs.len(), 2, "Incorrect inputs array");
83308778c6fSJeremy L Thompson     /// # Ok(())
83408778c6fSJeremy L Thompson     /// # }
83508778c6fSJeremy L Thompson     /// ```
83608778c6fSJeremy L Thompson     pub fn inputs(&self) -> crate::Result<&[crate::OperatorField]> {
83708778c6fSJeremy L Thompson         // Get array of raw C pointers for inputs
83808778c6fSJeremy L Thompson         let mut num_inputs = 0;
83908778c6fSJeremy L Thompson         let mut inputs_ptr = std::ptr::null_mut();
84008778c6fSJeremy L Thompson         let ierr = unsafe {
84108778c6fSJeremy L Thompson             bind_ceed::CeedOperatorGetFields(
84208778c6fSJeremy L Thompson                 self.op_core.ptr,
84308778c6fSJeremy L Thompson                 &mut num_inputs,
84408778c6fSJeremy L Thompson                 &mut inputs_ptr,
84508778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut bind_ceed::CeedInt,
84608778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField,
84708778c6fSJeremy L Thompson             )
84808778c6fSJeremy L Thompson         };
84908778c6fSJeremy L Thompson         self.op_core.check_error(ierr)?;
85008778c6fSJeremy L Thompson         // Convert raw C pointers to fixed length slice
85108778c6fSJeremy L Thompson         let inputs_slice = unsafe {
85208778c6fSJeremy L Thompson             std::slice::from_raw_parts(
85308778c6fSJeremy L Thompson                 inputs_ptr as *const crate::OperatorField,
85408778c6fSJeremy L Thompson                 num_inputs as usize,
85508778c6fSJeremy L Thompson             )
85608778c6fSJeremy L Thompson         };
85708778c6fSJeremy L Thompson         Ok(inputs_slice)
85808778c6fSJeremy L Thompson     }
85908778c6fSJeremy L Thompson 
86008778c6fSJeremy L Thompson     /// Get a slice of Operator outputs
86108778c6fSJeremy L Thompson     ///
86208778c6fSJeremy L Thompson     /// ```
86308778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
8644d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
86508778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
86608778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
86708778c6fSJeremy L Thompson     ///
86808778c6fSJeremy L Thompson     /// // Operator field arguments
86908778c6fSJeremy L Thompson     /// let ne = 3;
87008778c6fSJeremy L Thompson     /// let q = 4 as usize;
87108778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
87208778c6fSJeremy L Thompson     /// for i in 0..ne {
87308778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
87408778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
87508778c6fSJeremy L Thompson     /// }
87608778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
87708778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
878d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
87908778c6fSJeremy L Thompson     ///
88008778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
88108778c6fSJeremy L Thompson     ///
88208778c6fSJeremy L Thompson     /// // Operator fields
88308778c6fSJeremy L Thompson     /// let op = ceed
88408778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
88508778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
88608778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
887356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
88808778c6fSJeremy L Thompson     ///
88908778c6fSJeremy L Thompson     /// let outputs = op.outputs()?;
89008778c6fSJeremy L Thompson     ///
89108778c6fSJeremy L Thompson     /// assert_eq!(outputs.len(), 1, "Incorrect outputs array");
89208778c6fSJeremy L Thompson     /// # Ok(())
89308778c6fSJeremy L Thompson     /// # }
89408778c6fSJeremy L Thompson     /// ```
89508778c6fSJeremy L Thompson     pub fn outputs(&self) -> crate::Result<&[crate::OperatorField]> {
89608778c6fSJeremy L Thompson         // Get array of raw C pointers for outputs
89708778c6fSJeremy L Thompson         let mut num_outputs = 0;
89808778c6fSJeremy L Thompson         let mut outputs_ptr = std::ptr::null_mut();
89908778c6fSJeremy L Thompson         let ierr = unsafe {
90008778c6fSJeremy L Thompson             bind_ceed::CeedOperatorGetFields(
90108778c6fSJeremy L Thompson                 self.op_core.ptr,
90208778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut bind_ceed::CeedInt,
90308778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField,
90408778c6fSJeremy L Thompson                 &mut num_outputs,
90508778c6fSJeremy L Thompson                 &mut outputs_ptr,
90608778c6fSJeremy L Thompson             )
90708778c6fSJeremy L Thompson         };
90808778c6fSJeremy L Thompson         self.op_core.check_error(ierr)?;
90908778c6fSJeremy L Thompson         // Convert raw C pointers to fixed length slice
91008778c6fSJeremy L Thompson         let outputs_slice = unsafe {
91108778c6fSJeremy L Thompson             std::slice::from_raw_parts(
91208778c6fSJeremy L Thompson                 outputs_ptr as *const crate::OperatorField,
91308778c6fSJeremy L Thompson                 num_outputs as usize,
91408778c6fSJeremy L Thompson             )
91508778c6fSJeremy L Thompson         };
91608778c6fSJeremy L Thompson         Ok(outputs_slice)
91708778c6fSJeremy L Thompson     }
91808778c6fSJeremy L Thompson 
9196f97ff0aSJeremy L Thompson     /// Check if Operator is setup correctly
9206f97ff0aSJeremy L Thompson     ///
9216f97ff0aSJeremy L Thompson     /// ```
9226f97ff0aSJeremy L Thompson     /// # use libceed::prelude::*;
9236f97ff0aSJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
9246f97ff0aSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
9256f97ff0aSJeremy L Thompson     /// let ne = 4;
9266f97ff0aSJeremy L Thompson     /// let p = 3;
9276f97ff0aSJeremy L Thompson     /// let q = 4;
9286f97ff0aSJeremy L Thompson     /// let ndofs = p * ne - ne + 1;
9296f97ff0aSJeremy L Thompson     ///
9306f97ff0aSJeremy L Thompson     /// // Restrictions
9316f97ff0aSJeremy L Thompson     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
9326f97ff0aSJeremy L Thompson     /// for i in 0..ne {
9336f97ff0aSJeremy L Thompson     ///     indx[2 * i + 0] = i as i32;
9346f97ff0aSJeremy L Thompson     ///     indx[2 * i + 1] = (i + 1) as i32;
9356f97ff0aSJeremy L Thompson     /// }
9366f97ff0aSJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
9376f97ff0aSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
9386f97ff0aSJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
9396f97ff0aSJeremy L Thompson     ///
9406f97ff0aSJeremy L Thompson     /// // Bases
9416f97ff0aSJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
9426f97ff0aSJeremy L Thompson     ///
9436f97ff0aSJeremy L Thompson     /// // Build quadrature data
9446f97ff0aSJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
9456f97ff0aSJeremy L Thompson     /// let op_build = ceed
9466f97ff0aSJeremy L Thompson     ///     .operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
9476f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
9486f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
949356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
9506f97ff0aSJeremy L Thompson     ///
9516f97ff0aSJeremy L Thompson     /// // Check
9526f97ff0aSJeremy L Thompson     /// assert!(op_build.check().is_ok(), "Operator setup incorrectly");
9536f97ff0aSJeremy L Thompson     /// # Ok(())
9546f97ff0aSJeremy L Thompson     /// # }
9556f97ff0aSJeremy L Thompson     /// ```
9566f97ff0aSJeremy L Thompson     pub fn check(self) -> crate::Result<Self> {
9576f97ff0aSJeremy L Thompson         self.op_core.check()?;
9586f97ff0aSJeremy L Thompson         Ok(self)
9596f97ff0aSJeremy L Thompson     }
9606f97ff0aSJeremy L Thompson 
9613f2759cfSJeremy L Thompson     /// Get the number of elements associated with an Operator
9623f2759cfSJeremy L Thompson     ///
9633f2759cfSJeremy L Thompson     ///
9643f2759cfSJeremy L Thompson     /// ```
9653f2759cfSJeremy L Thompson     /// # use libceed::prelude::*;
9664d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
9673f2759cfSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
9683f2759cfSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
9693f2759cfSJeremy L Thompson     /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;
9703f2759cfSJeremy L Thompson     ///
9713f2759cfSJeremy L Thompson     /// // Operator field arguments
9723f2759cfSJeremy L Thompson     /// let ne = 3;
9733f2759cfSJeremy L Thompson     /// let q = 4;
9743f2759cfSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
9753f2759cfSJeremy L Thompson     /// for i in 0..ne {
9763f2759cfSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
9773f2759cfSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
9783f2759cfSJeremy L Thompson     /// }
9793f2759cfSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
9803f2759cfSJeremy L Thompson     ///
9813f2759cfSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
9823f2759cfSJeremy L Thompson     ///
9833f2759cfSJeremy L Thompson     /// // Operator field
9843f2759cfSJeremy L Thompson     /// op = op.field("dx", &r, &b, VectorOpt::Active)?;
9853f2759cfSJeremy L Thompson     ///
9863f2759cfSJeremy L Thompson     /// // Check number of elements
9873f2759cfSJeremy L Thompson     /// assert_eq!(op.num_elements(), ne, "Incorrect number of elements");
9883f2759cfSJeremy L Thompson     /// # Ok(())
9893f2759cfSJeremy L Thompson     /// # }
9903f2759cfSJeremy L Thompson     /// ```
9913f2759cfSJeremy L Thompson     pub fn num_elements(&self) -> usize {
9923f2759cfSJeremy L Thompson         let mut nelem = 0;
9933f2759cfSJeremy L Thompson         unsafe { bind_ceed::CeedOperatorGetNumElements(self.op_core.ptr, &mut nelem) };
9943f2759cfSJeremy L Thompson         usize::try_from(nelem).unwrap()
9953f2759cfSJeremy L Thompson     }
9963f2759cfSJeremy L Thompson 
9973f2759cfSJeremy L Thompson     /// Get the number of quadrature points associated with each element of
9983f2759cfSJeremy L Thompson     ///   an Operator
9993f2759cfSJeremy L Thompson     ///
10003f2759cfSJeremy L Thompson     ///
10013f2759cfSJeremy L Thompson     /// ```
10023f2759cfSJeremy L Thompson     /// # use libceed::prelude::*;
10034d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
10043f2759cfSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
10053f2759cfSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
10063f2759cfSJeremy L Thompson     /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;
10073f2759cfSJeremy L Thompson     ///
10083f2759cfSJeremy L Thompson     /// // Operator field arguments
10093f2759cfSJeremy L Thompson     /// let ne = 3;
10103f2759cfSJeremy L Thompson     /// let q = 4;
10113f2759cfSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
10123f2759cfSJeremy L Thompson     /// for i in 0..ne {
10133f2759cfSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
10143f2759cfSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
10153f2759cfSJeremy L Thompson     /// }
10163f2759cfSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
10173f2759cfSJeremy L Thompson     ///
10183f2759cfSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
10193f2759cfSJeremy L Thompson     ///
10203f2759cfSJeremy L Thompson     /// // Operator field
10213f2759cfSJeremy L Thompson     /// op = op.field("dx", &r, &b, VectorOpt::Active)?;
10223f2759cfSJeremy L Thompson     ///
10233f2759cfSJeremy L Thompson     /// // Check number of quadrature points
10243f2759cfSJeremy L Thompson     /// assert_eq!(
10253f2759cfSJeremy L Thompson     ///     op.num_quadrature_points(),
10263f2759cfSJeremy L Thompson     ///     q,
10273f2759cfSJeremy L Thompson     ///     "Incorrect number of quadrature points"
10283f2759cfSJeremy L Thompson     /// );
10293f2759cfSJeremy L Thompson     /// # Ok(())
10303f2759cfSJeremy L Thompson     /// # }
10313f2759cfSJeremy L Thompson     /// ```
10323f2759cfSJeremy L Thompson     pub fn num_quadrature_points(&self) -> usize {
10333f2759cfSJeremy L Thompson         let mut Q = 0;
10343f2759cfSJeremy L Thompson         unsafe { bind_ceed::CeedOperatorGetNumQuadraturePoints(self.op_core.ptr, &mut Q) };
10353f2759cfSJeremy L Thompson         usize::try_from(Q).unwrap()
10363f2759cfSJeremy L Thompson     }
10373f2759cfSJeremy L Thompson 
10389df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
10399df49d7eSJed Brown     ///
10409df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
10419df49d7eSJed Brown     ///
10429df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
10439df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
10449df49d7eSJed Brown     ///
10459df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
10469df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
10479df49d7eSJed Brown     ///
10489df49d7eSJed Brown     /// ```
10499df49d7eSJed Brown     /// # use libceed::prelude::*;
10504d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
10519df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
10529df49d7eSJed Brown     /// let ne = 4;
10539df49d7eSJed Brown     /// let p = 3;
10549df49d7eSJed Brown     /// let q = 4;
10559df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
10569df49d7eSJed Brown     ///
10579df49d7eSJed Brown     /// // Vectors
1058c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1059c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
10609df49d7eSJed Brown     /// qdata.set_value(0.0);
1061c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
10629df49d7eSJed Brown     /// u.set_value(1.0);
1063c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
10649df49d7eSJed Brown     /// v.set_value(0.0);
10659df49d7eSJed Brown     ///
10669df49d7eSJed Brown     /// // Restrictions
10679df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
10689df49d7eSJed Brown     /// for i in 0..ne {
10699df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
10709df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
10719df49d7eSJed Brown     /// }
1072c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
10739df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
10749df49d7eSJed Brown     /// for i in 0..ne {
10759df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
10769df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
10779df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
10789df49d7eSJed Brown     /// }
1079c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?;
10809df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1081c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
10829df49d7eSJed Brown     ///
10839df49d7eSJed Brown     /// // Bases
1084c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1085c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
10869df49d7eSJed Brown     ///
10879df49d7eSJed Brown     /// // Build quadrature data
1088c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1089c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1090c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1091c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1092356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1093c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
10949df49d7eSJed Brown     ///
10959df49d7eSJed Brown     /// // Mass operator
1096c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
10979df49d7eSJed Brown     /// let op_mass = ceed
1098c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1099c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1100356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1101c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
11029df49d7eSJed Brown     ///
11039df49d7eSJed Brown     /// // Diagonal
1104c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ndofs)?;
11059df49d7eSJed Brown     /// diag.set_value(0.0);
1106c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_diagonal(&mut diag)?;
11079df49d7eSJed Brown     ///
11089df49d7eSJed Brown     /// // Manual diagonal computation
1109c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ndofs)?;
11109c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
11119df49d7eSJed Brown     /// for i in 0..ndofs {
11129df49d7eSJed Brown     ///     u.set_value(0.0);
11139df49d7eSJed Brown     ///     {
1114e78171edSJeremy L Thompson     ///         let mut u_array = u.view_mut()?;
11159df49d7eSJed Brown     ///         u_array[i] = 1.;
11169df49d7eSJed Brown     ///     }
11179df49d7eSJed Brown     ///
1118c68be7a2SJeremy L Thompson     ///     op_mass.apply(&u, &mut v)?;
11199df49d7eSJed Brown     ///
11209df49d7eSJed Brown     ///     {
11219c774eddSJeremy L Thompson     ///         let v_array = v.view()?;
1122e78171edSJeremy L Thompson     ///         let mut true_array = true_diag.view_mut()?;
11239df49d7eSJed Brown     ///         true_array[i] = v_array[i];
11249df49d7eSJed Brown     ///     }
11259df49d7eSJed Brown     /// }
11269df49d7eSJed Brown     ///
11279df49d7eSJed Brown     /// // Check
1128e78171edSJeremy L Thompson     /// diag.view()?
11299df49d7eSJed Brown     ///     .iter()
1130e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
11319df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
11329df49d7eSJed Brown     ///         assert!(
113380a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
11349df49d7eSJed Brown     ///             "Diagonal entry incorrect"
11359df49d7eSJed Brown     ///         );
11369df49d7eSJed Brown     ///     });
1137c68be7a2SJeremy L Thompson     /// # Ok(())
1138c68be7a2SJeremy L Thompson     /// # }
11399df49d7eSJed Brown     /// ```
11409df49d7eSJed Brown     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
11419df49d7eSJed Brown         self.op_core.linear_assemble_diagonal(assembled)
11429df49d7eSJed Brown     }
11439df49d7eSJed Brown 
11449df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
11459df49d7eSJed Brown     ///
11469df49d7eSJed Brown     /// This sums into a Vector with the diagonal of a linear Operator.
11479df49d7eSJed Brown     ///
11489df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
11499df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
11509df49d7eSJed Brown     ///
11519df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
11529df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
11539df49d7eSJed Brown     ///
11549df49d7eSJed Brown     ///
11559df49d7eSJed Brown     /// ```
11569df49d7eSJed Brown     /// # use libceed::prelude::*;
11574d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
11589df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
11599df49d7eSJed Brown     /// let ne = 4;
11609df49d7eSJed Brown     /// let p = 3;
11619df49d7eSJed Brown     /// let q = 4;
11629df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
11639df49d7eSJed Brown     ///
11649df49d7eSJed Brown     /// // Vectors
1165c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1166c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
11679df49d7eSJed Brown     /// qdata.set_value(0.0);
1168c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
11699df49d7eSJed Brown     /// u.set_value(1.0);
1170c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
11719df49d7eSJed Brown     /// v.set_value(0.0);
11729df49d7eSJed Brown     ///
11739df49d7eSJed Brown     /// // Restrictions
11749df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
11759df49d7eSJed Brown     /// for i in 0..ne {
11769df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
11779df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
11789df49d7eSJed Brown     /// }
1179c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
11809df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
11819df49d7eSJed Brown     /// for i in 0..ne {
11829df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
11839df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
11849df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
11859df49d7eSJed Brown     /// }
1186c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?;
11879df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1188c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
11899df49d7eSJed Brown     ///
11909df49d7eSJed Brown     /// // Bases
1191c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1192c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
11939df49d7eSJed Brown     ///
11949df49d7eSJed Brown     /// // Build quadrature data
1195c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1196c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1197c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1198c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1199356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1200c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
12019df49d7eSJed Brown     ///
12029df49d7eSJed Brown     /// // Mass operator
1203c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
12049df49d7eSJed Brown     /// let op_mass = ceed
1205c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1206c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1207356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1208c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
12099df49d7eSJed Brown     ///
12109df49d7eSJed Brown     /// // Diagonal
1211c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ndofs)?;
12129df49d7eSJed Brown     /// diag.set_value(1.0);
1213c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_add_diagonal(&mut diag)?;
12149df49d7eSJed Brown     ///
12159df49d7eSJed Brown     /// // Manual diagonal computation
1216c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ndofs)?;
12179c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
12189df49d7eSJed Brown     /// for i in 0..ndofs {
12199df49d7eSJed Brown     ///     u.set_value(0.0);
12209df49d7eSJed Brown     ///     {
1221e78171edSJeremy L Thompson     ///         let mut u_array = u.view_mut()?;
12229df49d7eSJed Brown     ///         u_array[i] = 1.;
12239df49d7eSJed Brown     ///     }
12249df49d7eSJed Brown     ///
1225c68be7a2SJeremy L Thompson     ///     op_mass.apply(&u, &mut v)?;
12269df49d7eSJed Brown     ///
12279df49d7eSJed Brown     ///     {
12289c774eddSJeremy L Thompson     ///         let v_array = v.view()?;
1229e78171edSJeremy L Thompson     ///         let mut true_array = true_diag.view_mut()?;
12309df49d7eSJed Brown     ///         true_array[i] = v_array[i] + 1.0;
12319df49d7eSJed Brown     ///     }
12329df49d7eSJed Brown     /// }
12339df49d7eSJed Brown     ///
12349df49d7eSJed Brown     /// // Check
1235e78171edSJeremy L Thompson     /// diag.view()?
12369df49d7eSJed Brown     ///     .iter()
1237e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
12389df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
12399df49d7eSJed Brown     ///         assert!(
124080a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
12419df49d7eSJed Brown     ///             "Diagonal entry incorrect"
12429df49d7eSJed Brown     ///         );
12439df49d7eSJed Brown     ///     });
1244c68be7a2SJeremy L Thompson     /// # Ok(())
1245c68be7a2SJeremy L Thompson     /// # }
12469df49d7eSJed Brown     /// ```
12479df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
12489df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
12499df49d7eSJed Brown     }
12509df49d7eSJed Brown 
12519df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
12529df49d7eSJed Brown     ///
12539df49d7eSJed Brown     /// This overwrites a Vector with the point block diagonal of a linear
12549df49d7eSJed Brown     /// Operator.
12559df49d7eSJed Brown     ///
12569df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
12579df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
12589df49d7eSJed Brown     ///
12599df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
12609df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
12619df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
12629df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
12639df49d7eSJed Brown     ///                   this vector are derived from the active vector for
12649df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
12659df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
12669df49d7eSJed Brown     ///
12679df49d7eSJed Brown     /// ```
12689df49d7eSJed Brown     /// # use libceed::prelude::*;
12694d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
12709df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
12719df49d7eSJed Brown     /// let ne = 4;
12729df49d7eSJed Brown     /// let p = 3;
12739df49d7eSJed Brown     /// let q = 4;
12749df49d7eSJed Brown     /// let ncomp = 2;
12759df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
12769df49d7eSJed Brown     ///
12779df49d7eSJed Brown     /// // Vectors
1278c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1279c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
12809df49d7eSJed Brown     /// qdata.set_value(0.0);
1281c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ncomp * ndofs)?;
12829df49d7eSJed Brown     /// u.set_value(1.0);
1283c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ncomp * ndofs)?;
12849df49d7eSJed Brown     /// v.set_value(0.0);
12859df49d7eSJed Brown     ///
12869df49d7eSJed Brown     /// // Restrictions
12879df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
12889df49d7eSJed Brown     /// for i in 0..ne {
12899df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
12909df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
12919df49d7eSJed Brown     /// }
1292c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
12939df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
12949df49d7eSJed Brown     /// for i in 0..ne {
12959df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
12969df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
12979df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
12989df49d7eSJed Brown     /// }
1299c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?;
13009df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1301c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
13029df49d7eSJed Brown     ///
13039df49d7eSJed Brown     /// // Bases
1304c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1305c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?;
13069df49d7eSJed Brown     ///
13079df49d7eSJed Brown     /// // Build quadrature data
1308c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1309c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1310c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1311c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1312356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1313c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
13149df49d7eSJed Brown     ///
13159df49d7eSJed Brown     /// // Mass operator
13169df49d7eSJed Brown     /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
13179df49d7eSJed Brown     ///     // Number of quadrature points
13189df49d7eSJed Brown     ///     let q = qdata.len();
13199df49d7eSJed Brown     ///
13209df49d7eSJed Brown     ///     // Iterate over quadrature points
13219df49d7eSJed Brown     ///     for i in 0..q {
13229df49d7eSJed Brown     ///         v[i + 0 * q] = u[i + 1 * q] * qdata[i];
13239df49d7eSJed Brown     ///         v[i + 1 * q] = u[i + 0 * q] * qdata[i];
13249df49d7eSJed Brown     ///     }
13259df49d7eSJed Brown     ///
13269df49d7eSJed Brown     ///     // Return clean error code
13279df49d7eSJed Brown     ///     0
13289df49d7eSJed Brown     /// };
13299df49d7eSJed Brown     ///
13309df49d7eSJed Brown     /// let qf_mass = ceed
1331c68be7a2SJeremy L Thompson     ///     .q_function_interior(1, Box::new(mass_2_comp))?
1332c68be7a2SJeremy L Thompson     ///     .input("u", 2, EvalMode::Interp)?
1333c68be7a2SJeremy L Thompson     ///     .input("qdata", 1, EvalMode::None)?
1334c68be7a2SJeremy L Thompson     ///     .output("v", 2, EvalMode::Interp)?;
13359df49d7eSJed Brown     ///
13369df49d7eSJed Brown     /// let op_mass = ceed
1337c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1338c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1339356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1340c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
13419df49d7eSJed Brown     ///
13429df49d7eSJed Brown     /// // Diagonal
1343c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?;
13449df49d7eSJed Brown     /// diag.set_value(0.0);
1345c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_point_block_diagonal(&mut diag)?;
13469df49d7eSJed Brown     ///
13479df49d7eSJed Brown     /// // Manual diagonal computation
1348c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?;
13499c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
13509df49d7eSJed Brown     /// for i in 0..ndofs {
13519df49d7eSJed Brown     ///     for j in 0..ncomp {
13529df49d7eSJed Brown     ///         u.set_value(0.0);
13539df49d7eSJed Brown     ///         {
1354e78171edSJeremy L Thompson     ///             let mut u_array = u.view_mut()?;
13559df49d7eSJed Brown     ///             u_array[i + j * ndofs] = 1.;
13569df49d7eSJed Brown     ///         }
13579df49d7eSJed Brown     ///
1358c68be7a2SJeremy L Thompson     ///         op_mass.apply(&u, &mut v)?;
13599df49d7eSJed Brown     ///
13609df49d7eSJed Brown     ///         {
13619c774eddSJeremy L Thompson     ///             let v_array = v.view()?;
1362e78171edSJeremy L Thompson     ///             let mut true_array = true_diag.view_mut()?;
13639df49d7eSJed Brown     ///             for k in 0..ncomp {
13649df49d7eSJed Brown     ///                 true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
13659df49d7eSJed Brown     ///             }
13669df49d7eSJed Brown     ///         }
13679df49d7eSJed Brown     ///     }
13689df49d7eSJed Brown     /// }
13699df49d7eSJed Brown     ///
13709df49d7eSJed Brown     /// // Check
1371e78171edSJeremy L Thompson     /// diag.view()?
13729df49d7eSJed Brown     ///     .iter()
1373e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
13749df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
13759df49d7eSJed Brown     ///         assert!(
137680a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
13779df49d7eSJed Brown     ///             "Diagonal entry incorrect"
13789df49d7eSJed Brown     ///         );
13799df49d7eSJed Brown     ///     });
1380c68be7a2SJeremy L Thompson     /// # Ok(())
1381c68be7a2SJeremy L Thompson     /// # }
13829df49d7eSJed Brown     /// ```
13839df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
13849df49d7eSJed Brown         &self,
13859df49d7eSJed Brown         assembled: &mut Vector,
13869df49d7eSJed Brown     ) -> crate::Result<i32> {
13879df49d7eSJed Brown         self.op_core.linear_assemble_point_block_diagonal(assembled)
13889df49d7eSJed Brown     }
13899df49d7eSJed Brown 
13909df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
13919df49d7eSJed Brown     ///
13929df49d7eSJed Brown     /// This sums into a Vector with the point block diagonal of a linear
13939df49d7eSJed Brown     /// Operator.
13949df49d7eSJed Brown     ///
13959df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
13969df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
13979df49d7eSJed Brown     ///
13989df49d7eSJed Brown     /// * `op`        -     Operator to assemble QFunction
13999df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
14009df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
14019df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
14029df49d7eSJed Brown     ///                   this vector are derived from the active vector for
14039df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
14049df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
14059df49d7eSJed Brown     ///
14069df49d7eSJed Brown     /// ```
14079df49d7eSJed Brown     /// # use libceed::prelude::*;
14084d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
14099df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
14109df49d7eSJed Brown     /// let ne = 4;
14119df49d7eSJed Brown     /// let p = 3;
14129df49d7eSJed Brown     /// let q = 4;
14139df49d7eSJed Brown     /// let ncomp = 2;
14149df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
14159df49d7eSJed Brown     ///
14169df49d7eSJed Brown     /// // Vectors
1417c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1418c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
14199df49d7eSJed Brown     /// qdata.set_value(0.0);
1420c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ncomp * ndofs)?;
14219df49d7eSJed Brown     /// u.set_value(1.0);
1422c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ncomp * ndofs)?;
14239df49d7eSJed Brown     /// v.set_value(0.0);
14249df49d7eSJed Brown     ///
14259df49d7eSJed Brown     /// // Restrictions
14269df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
14279df49d7eSJed Brown     /// for i in 0..ne {
14289df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
14299df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
14309df49d7eSJed Brown     /// }
1431c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
14329df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
14339df49d7eSJed Brown     /// for i in 0..ne {
14349df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
14359df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
14369df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
14379df49d7eSJed Brown     /// }
1438c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?;
14399df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1440c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
14419df49d7eSJed Brown     ///
14429df49d7eSJed Brown     /// // Bases
1443c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1444c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?;
14459df49d7eSJed Brown     ///
14469df49d7eSJed Brown     /// // Build quadrature data
1447c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1448c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1449c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1450c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1451356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1452c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
14539df49d7eSJed Brown     ///
14549df49d7eSJed Brown     /// // Mass operator
14559df49d7eSJed Brown     /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
14569df49d7eSJed Brown     ///     // Number of quadrature points
14579df49d7eSJed Brown     ///     let q = qdata.len();
14589df49d7eSJed Brown     ///
14599df49d7eSJed Brown     ///     // Iterate over quadrature points
14609df49d7eSJed Brown     ///     for i in 0..q {
14619df49d7eSJed Brown     ///         v[i + 0 * q] = u[i + 1 * q] * qdata[i];
14629df49d7eSJed Brown     ///         v[i + 1 * q] = u[i + 0 * q] * qdata[i];
14639df49d7eSJed Brown     ///     }
14649df49d7eSJed Brown     ///
14659df49d7eSJed Brown     ///     // Return clean error code
14669df49d7eSJed Brown     ///     0
14679df49d7eSJed Brown     /// };
14689df49d7eSJed Brown     ///
14699df49d7eSJed Brown     /// let qf_mass = ceed
1470c68be7a2SJeremy L Thompson     ///     .q_function_interior(1, Box::new(mass_2_comp))?
1471c68be7a2SJeremy L Thompson     ///     .input("u", 2, EvalMode::Interp)?
1472c68be7a2SJeremy L Thompson     ///     .input("qdata", 1, EvalMode::None)?
1473c68be7a2SJeremy L Thompson     ///     .output("v", 2, EvalMode::Interp)?;
14749df49d7eSJed Brown     ///
14759df49d7eSJed Brown     /// let op_mass = ceed
1476c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1477c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1478356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1479c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
14809df49d7eSJed Brown     ///
14819df49d7eSJed Brown     /// // Diagonal
1482c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?;
14839df49d7eSJed Brown     /// diag.set_value(1.0);
1484c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_add_point_block_diagonal(&mut diag)?;
14859df49d7eSJed Brown     ///
14869df49d7eSJed Brown     /// // Manual diagonal computation
1487c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?;
14889c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
14899df49d7eSJed Brown     /// for i in 0..ndofs {
14909df49d7eSJed Brown     ///     for j in 0..ncomp {
14919df49d7eSJed Brown     ///         u.set_value(0.0);
14929df49d7eSJed Brown     ///         {
1493e78171edSJeremy L Thompson     ///             let mut u_array = u.view_mut()?;
14949df49d7eSJed Brown     ///             u_array[i + j * ndofs] = 1.;
14959df49d7eSJed Brown     ///         }
14969df49d7eSJed Brown     ///
1497c68be7a2SJeremy L Thompson     ///         op_mass.apply(&u, &mut v)?;
14989df49d7eSJed Brown     ///
14999df49d7eSJed Brown     ///         {
15009c774eddSJeremy L Thompson     ///             let v_array = v.view()?;
1501e78171edSJeremy L Thompson     ///             let mut true_array = true_diag.view_mut()?;
15029df49d7eSJed Brown     ///             for k in 0..ncomp {
15039df49d7eSJed Brown     ///                 true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
15049df49d7eSJed Brown     ///             }
15059df49d7eSJed Brown     ///         }
15069df49d7eSJed Brown     ///     }
15079df49d7eSJed Brown     /// }
15089df49d7eSJed Brown     ///
15099df49d7eSJed Brown     /// // Check
1510e78171edSJeremy L Thompson     /// diag.view()?
15119df49d7eSJed Brown     ///     .iter()
1512e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
15139df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
15149df49d7eSJed Brown     ///         assert!(
151580a9ef05SNatalie Beams     ///             (*computed - 1.0 - *actual).abs() < 10.0 * libceed::EPSILON,
15169df49d7eSJed Brown     ///             "Diagonal entry incorrect"
15179df49d7eSJed Brown     ///         );
15189df49d7eSJed Brown     ///     });
1519c68be7a2SJeremy L Thompson     /// # Ok(())
1520c68be7a2SJeremy L Thompson     /// # }
15219df49d7eSJed Brown     /// ```
15229df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
15239df49d7eSJed Brown         &self,
15249df49d7eSJed Brown         assembled: &mut Vector,
15259df49d7eSJed Brown     ) -> crate::Result<i32> {
15269df49d7eSJed Brown         self.op_core
15279df49d7eSJed Brown             .linear_assemble_add_point_block_diagonal(assembled)
15289df49d7eSJed Brown     }
15299df49d7eSJed Brown 
15309df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
15319df49d7eSJed Brown     ///   given Operator, creating the prolongation basis from the fine and
15329df49d7eSJed Brown     ///   coarse grid interpolation
15339df49d7eSJed Brown     ///
15349df49d7eSJed Brown     /// * `p_mult_fine`  - Lvector multiplicity in parallel gather/scatter
15359df49d7eSJed Brown     /// * `rstr_coarse`  - Coarse grid restriction
15369df49d7eSJed Brown     /// * `basis_coarse` - Coarse grid active vector basis
15379df49d7eSJed Brown     ///
15389df49d7eSJed Brown     /// ```
15399df49d7eSJed Brown     /// # use libceed::prelude::*;
15404d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
15419df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
15429df49d7eSJed Brown     /// let ne = 15;
15439df49d7eSJed Brown     /// let p_coarse = 3;
15449df49d7eSJed Brown     /// let p_fine = 5;
15459df49d7eSJed Brown     /// let q = 6;
15469df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
15479df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
15489df49d7eSJed Brown     ///
15499df49d7eSJed Brown     /// // Vectors
15509df49d7eSJed Brown     /// let x_array = (0..ne + 1)
155180a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
155280a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1553c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1554c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
15559df49d7eSJed Brown     /// qdata.set_value(0.0);
1556c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
15579df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1558c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
15599df49d7eSJed Brown     /// u_fine.set_value(1.0);
1560c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
15619df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1562c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
15639df49d7eSJed Brown     /// v_fine.set_value(0.0);
1564c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
15659df49d7eSJed Brown     /// multiplicity.set_value(1.0);
15669df49d7eSJed Brown     ///
15679df49d7eSJed Brown     /// // Restrictions
15689df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1569c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
15709df49d7eSJed Brown     ///
15719df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
15729df49d7eSJed Brown     /// for i in 0..ne {
15739df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
15749df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
15759df49d7eSJed Brown     /// }
1576c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
15779df49d7eSJed Brown     ///
15789df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
15799df49d7eSJed Brown     /// for i in 0..ne {
15809df49d7eSJed Brown     ///     for j in 0..p_coarse {
15819df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
15829df49d7eSJed Brown     ///     }
15839df49d7eSJed Brown     /// }
1584c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
15859df49d7eSJed Brown     ///     ne,
15869df49d7eSJed Brown     ///     p_coarse,
15879df49d7eSJed Brown     ///     1,
15889df49d7eSJed Brown     ///     1,
15899df49d7eSJed Brown     ///     ndofs_coarse,
15909df49d7eSJed Brown     ///     MemType::Host,
15919df49d7eSJed Brown     ///     &indu_coarse,
1592c68be7a2SJeremy L Thompson     /// )?;
15939df49d7eSJed Brown     ///
15949df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
15959df49d7eSJed Brown     /// for i in 0..ne {
15969df49d7eSJed Brown     ///     for j in 0..p_fine {
15979df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
15989df49d7eSJed Brown     ///     }
15999df49d7eSJed Brown     /// }
1600c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
16019df49d7eSJed Brown     ///
16029df49d7eSJed Brown     /// // Bases
1603c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1604c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1605c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
16069df49d7eSJed Brown     ///
16079df49d7eSJed Brown     /// // Build quadrature data
1608c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1609c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1610c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1611c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1612356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1613c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
16149df49d7eSJed Brown     ///
16159df49d7eSJed Brown     /// // Mass operator
1616c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
16179df49d7eSJed Brown     /// let op_mass_fine = ceed
1618c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1619c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
1620356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1621c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
16229df49d7eSJed Brown     ///
16239df49d7eSJed Brown     /// // Multigrid setup
1624c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) =
1625c68be7a2SJeremy L Thompson     ///     op_mass_fine.create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)?;
16269df49d7eSJed Brown     ///
16279df49d7eSJed Brown     /// // Coarse problem
16289df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1629c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
16309df49d7eSJed Brown     ///
16319df49d7eSJed Brown     /// // Check
1632e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
16339df49d7eSJed Brown     /// assert!(
163480a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 50.0 * libceed::EPSILON,
16359df49d7eSJed Brown     ///     "Incorrect interval length computed"
16369df49d7eSJed Brown     /// );
16379df49d7eSJed Brown     ///
16389df49d7eSJed Brown     /// // Prolong
1639c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
16409df49d7eSJed Brown     ///
16419df49d7eSJed Brown     /// // Fine problem
1642c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
16439df49d7eSJed Brown     ///
16449df49d7eSJed Brown     /// // Check
1645e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
16469df49d7eSJed Brown     /// assert!(
164780a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 50.0 * libceed::EPSILON,
16489df49d7eSJed Brown     ///     "Incorrect interval length computed"
16499df49d7eSJed Brown     /// );
16509df49d7eSJed Brown     ///
16519df49d7eSJed Brown     /// // Restrict
1652c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
16539df49d7eSJed Brown     ///
16549df49d7eSJed Brown     /// // Check
1655e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
16569df49d7eSJed Brown     /// assert!(
165780a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 50.0 * libceed::EPSILON,
16589df49d7eSJed Brown     ///     "Incorrect interval length computed"
16599df49d7eSJed Brown     /// );
1660c68be7a2SJeremy L Thompson     /// # Ok(())
1661c68be7a2SJeremy L Thompson     /// # }
16629df49d7eSJed Brown     /// ```
1663594ef120SJeremy L Thompson     pub fn create_multigrid_level<'b>(
16649df49d7eSJed Brown         &self,
16659df49d7eSJed Brown         p_mult_fine: &Vector,
16669df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
16679df49d7eSJed Brown         basis_coarse: &Basis,
1668594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
16699df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
16709df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
16719df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
16729df49d7eSJed Brown         let ierr = unsafe {
16739df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreate(
16749df49d7eSJed Brown                 self.op_core.ptr,
16759df49d7eSJed Brown                 p_mult_fine.ptr,
16769df49d7eSJed Brown                 rstr_coarse.ptr,
16779df49d7eSJed Brown                 basis_coarse.ptr,
16789df49d7eSJed Brown                 &mut ptr_coarse,
16799df49d7eSJed Brown                 &mut ptr_prolong,
16809df49d7eSJed Brown                 &mut ptr_restrict,
16819df49d7eSJed Brown             )
16829df49d7eSJed Brown         };
16831142270cSJeremy L Thompson         self.op_core.check_error(ierr)?;
16841142270cSJeremy L Thompson         let op_coarse = Operator::from_raw(ptr_coarse)?;
16851142270cSJeremy L Thompson         let op_prolong = Operator::from_raw(ptr_prolong)?;
16861142270cSJeremy L Thompson         let op_restrict = Operator::from_raw(ptr_restrict)?;
16879df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
16889df49d7eSJed Brown     }
16899df49d7eSJed Brown 
16909df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
16919df49d7eSJed Brown     ///   given Operator with a tensor basis for the active basis
16929df49d7eSJed Brown     ///
16939df49d7eSJed Brown     /// * `p_mult_fine`   - Lvector multiplicity in parallel gather/scatter
16949df49d7eSJed Brown     /// * `rstr_coarse`   - Coarse grid restriction
16959df49d7eSJed Brown     /// * `basis_coarse`  - Coarse grid active vector basis
16969df49d7eSJed Brown     /// * `interp_c_to_f` - Matrix for coarse to fine
16979df49d7eSJed Brown     ///
16989df49d7eSJed Brown     /// ```
16999df49d7eSJed Brown     /// # use libceed::prelude::*;
17004d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
17019df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
17029df49d7eSJed Brown     /// let ne = 15;
17039df49d7eSJed Brown     /// let p_coarse = 3;
17049df49d7eSJed Brown     /// let p_fine = 5;
17059df49d7eSJed Brown     /// let q = 6;
17069df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
17079df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
17089df49d7eSJed Brown     ///
17099df49d7eSJed Brown     /// // Vectors
17109df49d7eSJed Brown     /// let x_array = (0..ne + 1)
171180a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
171280a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1713c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1714c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
17159df49d7eSJed Brown     /// qdata.set_value(0.0);
1716c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
17179df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1718c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
17199df49d7eSJed Brown     /// u_fine.set_value(1.0);
1720c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
17219df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1722c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
17239df49d7eSJed Brown     /// v_fine.set_value(0.0);
1724c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
17259df49d7eSJed Brown     /// multiplicity.set_value(1.0);
17269df49d7eSJed Brown     ///
17279df49d7eSJed Brown     /// // Restrictions
17289df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1729c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
17309df49d7eSJed Brown     ///
17319df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
17329df49d7eSJed Brown     /// for i in 0..ne {
17339df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
17349df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
17359df49d7eSJed Brown     /// }
1736c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
17379df49d7eSJed Brown     ///
17389df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
17399df49d7eSJed Brown     /// for i in 0..ne {
17409df49d7eSJed Brown     ///     for j in 0..p_coarse {
17419df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
17429df49d7eSJed Brown     ///     }
17439df49d7eSJed Brown     /// }
1744c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
17459df49d7eSJed Brown     ///     ne,
17469df49d7eSJed Brown     ///     p_coarse,
17479df49d7eSJed Brown     ///     1,
17489df49d7eSJed Brown     ///     1,
17499df49d7eSJed Brown     ///     ndofs_coarse,
17509df49d7eSJed Brown     ///     MemType::Host,
17519df49d7eSJed Brown     ///     &indu_coarse,
1752c68be7a2SJeremy L Thompson     /// )?;
17539df49d7eSJed Brown     ///
17549df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
17559df49d7eSJed Brown     /// for i in 0..ne {
17569df49d7eSJed Brown     ///     for j in 0..p_fine {
17579df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
17589df49d7eSJed Brown     ///     }
17599df49d7eSJed Brown     /// }
1760c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
17619df49d7eSJed Brown     ///
17629df49d7eSJed Brown     /// // Bases
1763c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1764c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1765c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
17669df49d7eSJed Brown     ///
17679df49d7eSJed Brown     /// // Build quadrature data
1768c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1769c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1770c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1771c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1772356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1773c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
17749df49d7eSJed Brown     ///
17759df49d7eSJed Brown     /// // Mass operator
1776c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
17779df49d7eSJed Brown     /// let op_mass_fine = ceed
1778c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1779c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
1780356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1781c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
17829df49d7eSJed Brown     ///
17839df49d7eSJed Brown     /// // Multigrid setup
178480a9ef05SNatalie Beams     /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine];
17859df49d7eSJed Brown     /// {
1786c68be7a2SJeremy L Thompson     ///     let mut coarse = ceed.vector(p_coarse)?;
1787c68be7a2SJeremy L Thompson     ///     let mut fine = ceed.vector(p_fine)?;
1788c68be7a2SJeremy L Thompson     ///     let basis_c_to_f =
1789c68be7a2SJeremy L Thompson     ///         ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?;
17909df49d7eSJed Brown     ///     for i in 0..p_coarse {
17919df49d7eSJed Brown     ///         coarse.set_value(0.0);
17929df49d7eSJed Brown     ///         {
1793e78171edSJeremy L Thompson     ///             let mut array = coarse.view_mut()?;
17949df49d7eSJed Brown     ///             array[i] = 1.;
17959df49d7eSJed Brown     ///         }
1796c68be7a2SJeremy L Thompson     ///         basis_c_to_f.apply(
17979df49d7eSJed Brown     ///             1,
17989df49d7eSJed Brown     ///             TransposeMode::NoTranspose,
17999df49d7eSJed Brown     ///             EvalMode::Interp,
18009df49d7eSJed Brown     ///             &coarse,
18019df49d7eSJed Brown     ///             &mut fine,
1802c68be7a2SJeremy L Thompson     ///         )?;
1803e78171edSJeremy L Thompson     ///         let array = fine.view()?;
18049df49d7eSJed Brown     ///         for j in 0..p_fine {
18059df49d7eSJed Brown     ///             interp_c_to_f[j * p_coarse + i] = array[j];
18069df49d7eSJed Brown     ///         }
18079df49d7eSJed Brown     ///     }
18089df49d7eSJed Brown     /// }
1809c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_tensor_H1(
1810c68be7a2SJeremy L Thompson     ///     &multiplicity,
1811c68be7a2SJeremy L Thompson     ///     &ru_coarse,
1812c68be7a2SJeremy L Thompson     ///     &bu_coarse,
1813c68be7a2SJeremy L Thompson     ///     &interp_c_to_f,
1814c68be7a2SJeremy L Thompson     /// )?;
18159df49d7eSJed Brown     ///
18169df49d7eSJed Brown     /// // Coarse problem
18179df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1818c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
18199df49d7eSJed Brown     ///
18209df49d7eSJed Brown     /// // Check
1821e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
18229df49d7eSJed Brown     /// assert!(
182380a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
18249df49d7eSJed Brown     ///     "Incorrect interval length computed"
18259df49d7eSJed Brown     /// );
18269df49d7eSJed Brown     ///
18279df49d7eSJed Brown     /// // Prolong
1828c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
18299df49d7eSJed Brown     ///
18309df49d7eSJed Brown     /// // Fine problem
1831c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
18329df49d7eSJed Brown     ///
18339df49d7eSJed Brown     /// // Check
1834e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
18359df49d7eSJed Brown     /// assert!(
183680a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
18379df49d7eSJed Brown     ///     "Incorrect interval length computed"
18389df49d7eSJed Brown     /// );
18399df49d7eSJed Brown     ///
18409df49d7eSJed Brown     /// // Restrict
1841c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
18429df49d7eSJed Brown     ///
18439df49d7eSJed Brown     /// // Check
1844e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
18459df49d7eSJed Brown     /// assert!(
184680a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
18479df49d7eSJed Brown     ///     "Incorrect interval length computed"
18489df49d7eSJed Brown     /// );
1849c68be7a2SJeremy L Thompson     /// # Ok(())
1850c68be7a2SJeremy L Thompson     /// # }
18519df49d7eSJed Brown     /// ```
1852594ef120SJeremy L Thompson     pub fn create_multigrid_level_tensor_H1<'b>(
18539df49d7eSJed Brown         &self,
18549df49d7eSJed Brown         p_mult_fine: &Vector,
18559df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
18569df49d7eSJed Brown         basis_coarse: &Basis,
185780a9ef05SNatalie Beams         interpCtoF: &Vec<Scalar>,
1858594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
18599df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
18609df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
18619df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
18629df49d7eSJed Brown         let ierr = unsafe {
18639df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreateTensorH1(
18649df49d7eSJed Brown                 self.op_core.ptr,
18659df49d7eSJed Brown                 p_mult_fine.ptr,
18669df49d7eSJed Brown                 rstr_coarse.ptr,
18679df49d7eSJed Brown                 basis_coarse.ptr,
18689df49d7eSJed Brown                 interpCtoF.as_ptr(),
18699df49d7eSJed Brown                 &mut ptr_coarse,
18709df49d7eSJed Brown                 &mut ptr_prolong,
18719df49d7eSJed Brown                 &mut ptr_restrict,
18729df49d7eSJed Brown             )
18739df49d7eSJed Brown         };
18741142270cSJeremy L Thompson         self.op_core.check_error(ierr)?;
18751142270cSJeremy L Thompson         let op_coarse = Operator::from_raw(ptr_coarse)?;
18761142270cSJeremy L Thompson         let op_prolong = Operator::from_raw(ptr_prolong)?;
18771142270cSJeremy L Thompson         let op_restrict = Operator::from_raw(ptr_restrict)?;
18789df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
18799df49d7eSJed Brown     }
18809df49d7eSJed Brown 
18819df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
18829df49d7eSJed Brown     ///   given Operator with a non-tensor basis for the active basis
18839df49d7eSJed Brown     ///
18849df49d7eSJed Brown     /// * `p_mult_fine`   - Lvector multiplicity in parallel gather/scatter
18859df49d7eSJed Brown     /// * `rstr_coarse`   - Coarse grid restriction
18869df49d7eSJed Brown     /// * `basis_coarse`  - Coarse grid active vector basis
18879df49d7eSJed Brown     /// * `interp_c_to_f` - Matrix for coarse to fine
18889df49d7eSJed Brown     ///
18899df49d7eSJed Brown     /// ```
18909df49d7eSJed Brown     /// # use libceed::prelude::*;
18914d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
18929df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
18939df49d7eSJed Brown     /// let ne = 15;
18949df49d7eSJed Brown     /// let p_coarse = 3;
18959df49d7eSJed Brown     /// let p_fine = 5;
18969df49d7eSJed Brown     /// let q = 6;
18979df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
18989df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
18999df49d7eSJed Brown     ///
19009df49d7eSJed Brown     /// // Vectors
19019df49d7eSJed Brown     /// let x_array = (0..ne + 1)
190280a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
190380a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1904c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1905c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
19069df49d7eSJed Brown     /// qdata.set_value(0.0);
1907c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
19089df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1909c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
19109df49d7eSJed Brown     /// u_fine.set_value(1.0);
1911c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
19129df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1913c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
19149df49d7eSJed Brown     /// v_fine.set_value(0.0);
1915c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
19169df49d7eSJed Brown     /// multiplicity.set_value(1.0);
19179df49d7eSJed Brown     ///
19189df49d7eSJed Brown     /// // Restrictions
19199df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1920c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
19219df49d7eSJed Brown     ///
19229df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
19239df49d7eSJed Brown     /// for i in 0..ne {
19249df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
19259df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
19269df49d7eSJed Brown     /// }
1927c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
19289df49d7eSJed Brown     ///
19299df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
19309df49d7eSJed Brown     /// for i in 0..ne {
19319df49d7eSJed Brown     ///     for j in 0..p_coarse {
19329df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
19339df49d7eSJed Brown     ///     }
19349df49d7eSJed Brown     /// }
1935c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
19369df49d7eSJed Brown     ///     ne,
19379df49d7eSJed Brown     ///     p_coarse,
19389df49d7eSJed Brown     ///     1,
19399df49d7eSJed Brown     ///     1,
19409df49d7eSJed Brown     ///     ndofs_coarse,
19419df49d7eSJed Brown     ///     MemType::Host,
19429df49d7eSJed Brown     ///     &indu_coarse,
1943c68be7a2SJeremy L Thompson     /// )?;
19449df49d7eSJed Brown     ///
19459df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
19469df49d7eSJed Brown     /// for i in 0..ne {
19479df49d7eSJed Brown     ///     for j in 0..p_fine {
19489df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
19499df49d7eSJed Brown     ///     }
19509df49d7eSJed Brown     /// }
1951c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
19529df49d7eSJed Brown     ///
19539df49d7eSJed Brown     /// // Bases
1954c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1955c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1956c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
19579df49d7eSJed Brown     ///
19589df49d7eSJed Brown     /// // Build quadrature data
1959c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1960c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1961c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1962c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1963356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1964c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
19659df49d7eSJed Brown     ///
19669df49d7eSJed Brown     /// // Mass operator
1967c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
19689df49d7eSJed Brown     /// let op_mass_fine = ceed
1969c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1970c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
1971356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1972c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
19739df49d7eSJed Brown     ///
19749df49d7eSJed Brown     /// // Multigrid setup
197580a9ef05SNatalie Beams     /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine];
19769df49d7eSJed Brown     /// {
1977c68be7a2SJeremy L Thompson     ///     let mut coarse = ceed.vector(p_coarse)?;
1978c68be7a2SJeremy L Thompson     ///     let mut fine = ceed.vector(p_fine)?;
1979c68be7a2SJeremy L Thompson     ///     let basis_c_to_f =
1980c68be7a2SJeremy L Thompson     ///         ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?;
19819df49d7eSJed Brown     ///     for i in 0..p_coarse {
19829df49d7eSJed Brown     ///         coarse.set_value(0.0);
19839df49d7eSJed Brown     ///         {
1984e78171edSJeremy L Thompson     ///             let mut array = coarse.view_mut()?;
19859df49d7eSJed Brown     ///             array[i] = 1.;
19869df49d7eSJed Brown     ///         }
1987c68be7a2SJeremy L Thompson     ///         basis_c_to_f.apply(
19889df49d7eSJed Brown     ///             1,
19899df49d7eSJed Brown     ///             TransposeMode::NoTranspose,
19909df49d7eSJed Brown     ///             EvalMode::Interp,
19919df49d7eSJed Brown     ///             &coarse,
19929df49d7eSJed Brown     ///             &mut fine,
1993c68be7a2SJeremy L Thompson     ///         )?;
1994e78171edSJeremy L Thompson     ///         let array = fine.view()?;
19959df49d7eSJed Brown     ///         for j in 0..p_fine {
19969df49d7eSJed Brown     ///             interp_c_to_f[j * p_coarse + i] = array[j];
19979df49d7eSJed Brown     ///         }
19989df49d7eSJed Brown     ///     }
19999df49d7eSJed Brown     /// }
2000c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_H1(
2001c68be7a2SJeremy L Thompson     ///     &multiplicity,
2002c68be7a2SJeremy L Thompson     ///     &ru_coarse,
2003c68be7a2SJeremy L Thompson     ///     &bu_coarse,
2004c68be7a2SJeremy L Thompson     ///     &interp_c_to_f,
2005c68be7a2SJeremy L Thompson     /// )?;
20069df49d7eSJed Brown     ///
20079df49d7eSJed Brown     /// // Coarse problem
20089df49d7eSJed Brown     /// u_coarse.set_value(1.0);
2009c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
20109df49d7eSJed Brown     ///
20119df49d7eSJed Brown     /// // Check
2012e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
20139df49d7eSJed Brown     /// assert!(
201480a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
20159df49d7eSJed Brown     ///     "Incorrect interval length computed"
20169df49d7eSJed Brown     /// );
20179df49d7eSJed Brown     ///
20189df49d7eSJed Brown     /// // Prolong
2019c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
20209df49d7eSJed Brown     ///
20219df49d7eSJed Brown     /// // Fine problem
2022c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
20239df49d7eSJed Brown     ///
20249df49d7eSJed Brown     /// // Check
2025e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
20269df49d7eSJed Brown     /// assert!(
202780a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
20289df49d7eSJed Brown     ///     "Incorrect interval length computed"
20299df49d7eSJed Brown     /// );
20309df49d7eSJed Brown     ///
20319df49d7eSJed Brown     /// // Restrict
2032c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
20339df49d7eSJed Brown     ///
20349df49d7eSJed Brown     /// // Check
2035e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
20369df49d7eSJed Brown     /// assert!(
203780a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
20389df49d7eSJed Brown     ///     "Incorrect interval length computed"
20399df49d7eSJed Brown     /// );
2040c68be7a2SJeremy L Thompson     /// # Ok(())
2041c68be7a2SJeremy L Thompson     /// # }
20429df49d7eSJed Brown     /// ```
2043594ef120SJeremy L Thompson     pub fn create_multigrid_level_H1<'b>(
20449df49d7eSJed Brown         &self,
20459df49d7eSJed Brown         p_mult_fine: &Vector,
20469df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
20479df49d7eSJed Brown         basis_coarse: &Basis,
204880a9ef05SNatalie Beams         interpCtoF: &[Scalar],
2049594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
20509df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
20519df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
20529df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
20539df49d7eSJed Brown         let ierr = unsafe {
20549df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreateH1(
20559df49d7eSJed Brown                 self.op_core.ptr,
20569df49d7eSJed Brown                 p_mult_fine.ptr,
20579df49d7eSJed Brown                 rstr_coarse.ptr,
20589df49d7eSJed Brown                 basis_coarse.ptr,
20599df49d7eSJed Brown                 interpCtoF.as_ptr(),
20609df49d7eSJed Brown                 &mut ptr_coarse,
20619df49d7eSJed Brown                 &mut ptr_prolong,
20629df49d7eSJed Brown                 &mut ptr_restrict,
20639df49d7eSJed Brown             )
20649df49d7eSJed Brown         };
20651142270cSJeremy L Thompson         self.op_core.check_error(ierr)?;
20661142270cSJeremy L Thompson         let op_coarse = Operator::from_raw(ptr_coarse)?;
20671142270cSJeremy L Thompson         let op_prolong = Operator::from_raw(ptr_prolong)?;
20681142270cSJeremy L Thompson         let op_restrict = Operator::from_raw(ptr_restrict)?;
20699df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
20709df49d7eSJed Brown     }
20719df49d7eSJed Brown }
20729df49d7eSJed Brown 
20739df49d7eSJed Brown // -----------------------------------------------------------------------------
20749df49d7eSJed Brown // Composite Operator
20759df49d7eSJed Brown // -----------------------------------------------------------------------------
20769df49d7eSJed Brown impl<'a> CompositeOperator<'a> {
20779df49d7eSJed Brown     // Constructor
2078594ef120SJeremy L Thompson     pub fn create(ceed: &crate::Ceed) -> crate::Result<Self> {
20799df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
20809df49d7eSJed Brown         let ierr = unsafe { bind_ceed::CeedCompositeOperatorCreate(ceed.ptr, &mut ptr) };
20819df49d7eSJed Brown         ceed.check_error(ierr)?;
20829df49d7eSJed Brown         Ok(Self {
20831142270cSJeremy L Thompson             op_core: OperatorCore {
20841142270cSJeremy L Thompson                 ptr,
20851142270cSJeremy L Thompson                 _lifeline: PhantomData,
20861142270cSJeremy L Thompson             },
20879df49d7eSJed Brown         })
20889df49d7eSJed Brown     }
20899df49d7eSJed Brown 
2090ea6b5821SJeremy L Thompson     /// Set name for CompositeOperator printing
2091ea6b5821SJeremy L Thompson     ///
2092ea6b5821SJeremy L Thompson     /// * 'name' - Name to set
2093ea6b5821SJeremy L Thompson     ///
2094ea6b5821SJeremy L Thompson     /// ```
2095ea6b5821SJeremy L Thompson     /// # use libceed::prelude::*;
2096ea6b5821SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
2097ea6b5821SJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
2098ea6b5821SJeremy L Thompson     ///
2099ea6b5821SJeremy L Thompson     /// // Sub operator field arguments
2100ea6b5821SJeremy L Thompson     /// let ne = 3;
2101ea6b5821SJeremy L Thompson     /// let q = 4 as usize;
2102ea6b5821SJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
2103ea6b5821SJeremy L Thompson     /// for i in 0..ne {
2104ea6b5821SJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
2105ea6b5821SJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
2106ea6b5821SJeremy L Thompson     /// }
2107ea6b5821SJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
2108ea6b5821SJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2109d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
2110ea6b5821SJeremy L Thompson     ///
2111ea6b5821SJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2112ea6b5821SJeremy L Thompson     ///
2113ea6b5821SJeremy L Thompson     /// let qdata_mass = ceed.vector(q * ne)?;
2114ea6b5821SJeremy L Thompson     /// let qdata_diff = ceed.vector(q * ne)?;
2115ea6b5821SJeremy L Thompson     ///
2116ea6b5821SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
2117ea6b5821SJeremy L Thompson     /// let op_mass = ceed
2118ea6b5821SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2119ea6b5821SJeremy L Thompson     ///     .name("Mass term")?
2120ea6b5821SJeremy L Thompson     ///     .field("u", &r, &b, VectorOpt::Active)?
2121356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2122ea6b5821SJeremy L Thompson     ///     .field("v", &r, &b, VectorOpt::Active)?;
2123ea6b5821SJeremy L Thompson     ///
2124ea6b5821SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
2125ea6b5821SJeremy L Thompson     /// let op_diff = ceed
2126ea6b5821SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2127ea6b5821SJeremy L Thompson     ///     .name("Poisson term")?
2128ea6b5821SJeremy L Thompson     ///     .field("du", &r, &b, VectorOpt::Active)?
2129356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2130ea6b5821SJeremy L Thompson     ///     .field("dv", &r, &b, VectorOpt::Active)?;
2131ea6b5821SJeremy L Thompson     ///
2132ea6b5821SJeremy L Thompson     /// let op = ceed
2133ea6b5821SJeremy L Thompson     ///     .composite_operator()?
2134ea6b5821SJeremy L Thompson     ///     .name("Screened Poisson")?
2135ea6b5821SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2136ea6b5821SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
2137ea6b5821SJeremy L Thompson     /// # Ok(())
2138ea6b5821SJeremy L Thompson     /// # }
2139ea6b5821SJeremy L Thompson     /// ```
2140ea6b5821SJeremy L Thompson     #[allow(unused_mut)]
2141ea6b5821SJeremy L Thompson     pub fn name(mut self, name: &str) -> crate::Result<Self> {
2142ea6b5821SJeremy L Thompson         self.op_core.name(name)?;
2143ea6b5821SJeremy L Thompson         Ok(self)
2144ea6b5821SJeremy L Thompson     }
2145ea6b5821SJeremy L Thompson 
21469df49d7eSJed Brown     /// Apply Operator to a vector
21479df49d7eSJed Brown     ///
2148ea6b5821SJeremy L Thompson     /// * `input`  - Inpuht Vector
21499df49d7eSJed Brown     /// * `output` - Output Vector
21509df49d7eSJed Brown     ///
21519df49d7eSJed Brown     /// ```
21529df49d7eSJed Brown     /// # use libceed::prelude::*;
21534d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
21549df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
21559df49d7eSJed Brown     /// let ne = 4;
21569df49d7eSJed Brown     /// let p = 3;
21579df49d7eSJed Brown     /// let q = 4;
21589df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
21599df49d7eSJed Brown     ///
21609df49d7eSJed Brown     /// // Vectors
2161c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
2162c68be7a2SJeremy L Thompson     /// let mut qdata_mass = ceed.vector(ne * q)?;
21639df49d7eSJed Brown     /// qdata_mass.set_value(0.0);
2164c68be7a2SJeremy L Thompson     /// let mut qdata_diff = ceed.vector(ne * q)?;
21659df49d7eSJed Brown     /// qdata_diff.set_value(0.0);
2166c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
21679df49d7eSJed Brown     /// u.set_value(1.0);
2168c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
21699df49d7eSJed Brown     /// v.set_value(0.0);
21709df49d7eSJed Brown     ///
21719df49d7eSJed Brown     /// // Restrictions
21729df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
21739df49d7eSJed Brown     /// for i in 0..ne {
21749df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
21759df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
21769df49d7eSJed Brown     /// }
2177c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
21789df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
21799df49d7eSJed Brown     /// for i in 0..ne {
21809df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
21819df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
21829df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
21839df49d7eSJed Brown     /// }
2184c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
21859df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2186c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
21879df49d7eSJed Brown     ///
21889df49d7eSJed Brown     /// // Bases
2189c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2190c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
21919df49d7eSJed Brown     ///
21929df49d7eSJed Brown     /// // Build quadrature data
2193c68be7a2SJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
2194c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
2195c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2196c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2197356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2198c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_mass)?;
21999df49d7eSJed Brown     ///
2200c68be7a2SJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
2201c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
2202c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2203c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2204356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2205c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_diff)?;
22069df49d7eSJed Brown     ///
22079df49d7eSJed Brown     /// // Application operator
2208c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
22099df49d7eSJed Brown     /// let op_mass = ceed
2210c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2211c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
2212356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2213c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
22149df49d7eSJed Brown     ///
2215c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
22169df49d7eSJed Brown     /// let op_diff = ceed
2217c68be7a2SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2218c68be7a2SJeremy L Thompson     ///     .field("du", &ru, &bu, VectorOpt::Active)?
2219356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2220c68be7a2SJeremy L Thompson     ///     .field("dv", &ru, &bu, VectorOpt::Active)?;
22219df49d7eSJed Brown     ///
22229df49d7eSJed Brown     /// let op_composite = ceed
2223c68be7a2SJeremy L Thompson     ///     .composite_operator()?
2224c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2225c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
22269df49d7eSJed Brown     ///
22279df49d7eSJed Brown     /// v.set_value(0.0);
2228c68be7a2SJeremy L Thompson     /// op_composite.apply(&u, &mut v)?;
22299df49d7eSJed Brown     ///
22309df49d7eSJed Brown     /// // Check
2231e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
22329df49d7eSJed Brown     /// assert!(
223380a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
22349df49d7eSJed Brown     ///     "Incorrect interval length computed"
22359df49d7eSJed Brown     /// );
2236c68be7a2SJeremy L Thompson     /// # Ok(())
2237c68be7a2SJeremy L Thompson     /// # }
22389df49d7eSJed Brown     /// ```
22399df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
22409df49d7eSJed Brown         self.op_core.apply(input, output)
22419df49d7eSJed Brown     }
22429df49d7eSJed Brown 
22439df49d7eSJed Brown     /// Apply Operator to a vector and add result to output vector
22449df49d7eSJed Brown     ///
22459df49d7eSJed Brown     /// * `input`  - Input Vector
22469df49d7eSJed Brown     /// * `output` - Output Vector
22479df49d7eSJed Brown     ///
22489df49d7eSJed Brown     /// ```
22499df49d7eSJed Brown     /// # use libceed::prelude::*;
22504d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
22519df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
22529df49d7eSJed Brown     /// let ne = 4;
22539df49d7eSJed Brown     /// let p = 3;
22549df49d7eSJed Brown     /// let q = 4;
22559df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
22569df49d7eSJed Brown     ///
22579df49d7eSJed Brown     /// // Vectors
2258c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
2259c68be7a2SJeremy L Thompson     /// let mut qdata_mass = ceed.vector(ne * q)?;
22609df49d7eSJed Brown     /// qdata_mass.set_value(0.0);
2261c68be7a2SJeremy L Thompson     /// let mut qdata_diff = ceed.vector(ne * q)?;
22629df49d7eSJed Brown     /// qdata_diff.set_value(0.0);
2263c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
22649df49d7eSJed Brown     /// u.set_value(1.0);
2265c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
22669df49d7eSJed Brown     /// v.set_value(0.0);
22679df49d7eSJed Brown     ///
22689df49d7eSJed Brown     /// // Restrictions
22699df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
22709df49d7eSJed Brown     /// for i in 0..ne {
22719df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
22729df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
22739df49d7eSJed Brown     /// }
2274c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
22759df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
22769df49d7eSJed Brown     /// for i in 0..ne {
22779df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
22789df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
22799df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
22809df49d7eSJed Brown     /// }
2281c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
22829df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2283c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
22849df49d7eSJed Brown     ///
22859df49d7eSJed Brown     /// // Bases
2286c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2287c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
22889df49d7eSJed Brown     ///
22899df49d7eSJed Brown     /// // Build quadrature data
2290c68be7a2SJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
2291c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
2292c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2293c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2294356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2295c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_mass)?;
22969df49d7eSJed Brown     ///
2297c68be7a2SJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
2298c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
2299c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2300c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2301356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2302c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_diff)?;
23039df49d7eSJed Brown     ///
23049df49d7eSJed Brown     /// // Application operator
2305c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
23069df49d7eSJed Brown     /// let op_mass = ceed
2307c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2308c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
2309356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2310c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
23119df49d7eSJed Brown     ///
2312c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
23139df49d7eSJed Brown     /// let op_diff = ceed
2314c68be7a2SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2315c68be7a2SJeremy L Thompson     ///     .field("du", &ru, &bu, VectorOpt::Active)?
2316356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2317c68be7a2SJeremy L Thompson     ///     .field("dv", &ru, &bu, VectorOpt::Active)?;
23189df49d7eSJed Brown     ///
23199df49d7eSJed Brown     /// let op_composite = ceed
2320c68be7a2SJeremy L Thompson     ///     .composite_operator()?
2321c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2322c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
23239df49d7eSJed Brown     ///
23249df49d7eSJed Brown     /// v.set_value(1.0);
2325c68be7a2SJeremy L Thompson     /// op_composite.apply_add(&u, &mut v)?;
23269df49d7eSJed Brown     ///
23279df49d7eSJed Brown     /// // Check
2328e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
23299df49d7eSJed Brown     /// assert!(
233080a9ef05SNatalie Beams     ///     (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON,
23319df49d7eSJed Brown     ///     "Incorrect interval length computed"
23329df49d7eSJed Brown     /// );
2333c68be7a2SJeremy L Thompson     /// # Ok(())
2334c68be7a2SJeremy L Thompson     /// # }
23359df49d7eSJed Brown     /// ```
23369df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
23379df49d7eSJed Brown         self.op_core.apply_add(input, output)
23389df49d7eSJed Brown     }
23399df49d7eSJed Brown 
23409df49d7eSJed Brown     /// Add a sub-Operator to a Composite Operator
23419df49d7eSJed Brown     ///
23429df49d7eSJed Brown     /// * `subop` - Sub-Operator
23439df49d7eSJed Brown     ///
23449df49d7eSJed Brown     /// ```
23459df49d7eSJed Brown     /// # use libceed::prelude::*;
23464d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
23479df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
2348c68be7a2SJeremy L Thompson     /// let mut op = ceed.composite_operator()?;
23499df49d7eSJed Brown     ///
2350c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
2351c68be7a2SJeremy L Thompson     /// let op_mass = ceed.operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?;
2352c68be7a2SJeremy L Thompson     /// op = op.sub_operator(&op_mass)?;
23539df49d7eSJed Brown     ///
2354c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
2355c68be7a2SJeremy L Thompson     /// let op_diff = ceed.operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?;
2356c68be7a2SJeremy L Thompson     /// op = op.sub_operator(&op_diff)?;
2357c68be7a2SJeremy L Thompson     /// # Ok(())
2358c68be7a2SJeremy L Thompson     /// # }
23599df49d7eSJed Brown     /// ```
23609df49d7eSJed Brown     #[allow(unused_mut)]
23619df49d7eSJed Brown     pub fn sub_operator(mut self, subop: &Operator) -> crate::Result<Self> {
23629df49d7eSJed Brown         let ierr =
23639df49d7eSJed Brown             unsafe { bind_ceed::CeedCompositeOperatorAddSub(self.op_core.ptr, subop.op_core.ptr) };
23641142270cSJeremy L Thompson         self.op_core.check_error(ierr)?;
23659df49d7eSJed Brown         Ok(self)
23669df49d7eSJed Brown     }
23679df49d7eSJed Brown 
23686f97ff0aSJeremy L Thompson     /// Check if CompositeOperator is setup correctly
23696f97ff0aSJeremy L Thompson     ///
23706f97ff0aSJeremy L Thompson     /// ```
23716f97ff0aSJeremy L Thompson     /// # use libceed::prelude::*;
23726f97ff0aSJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
23736f97ff0aSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
23746f97ff0aSJeremy L Thompson     /// let ne = 4;
23756f97ff0aSJeremy L Thompson     /// let p = 3;
23766f97ff0aSJeremy L Thompson     /// let q = 4;
23776f97ff0aSJeremy L Thompson     /// let ndofs = p * ne - ne + 1;
23786f97ff0aSJeremy L Thompson     ///
23796f97ff0aSJeremy L Thompson     /// // Restrictions
23806f97ff0aSJeremy L Thompson     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
23816f97ff0aSJeremy L Thompson     /// for i in 0..ne {
23826f97ff0aSJeremy L Thompson     ///     indx[2 * i + 0] = i as i32;
23836f97ff0aSJeremy L Thompson     ///     indx[2 * i + 1] = (i + 1) as i32;
23846f97ff0aSJeremy L Thompson     /// }
23856f97ff0aSJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
23866f97ff0aSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
23876f97ff0aSJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
23886f97ff0aSJeremy L Thompson     ///
23896f97ff0aSJeremy L Thompson     /// // Bases
23906f97ff0aSJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
23916f97ff0aSJeremy L Thompson     ///
23926f97ff0aSJeremy L Thompson     /// // Build quadrature data
23936f97ff0aSJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
23946f97ff0aSJeremy L Thompson     /// let op_build_mass = ceed
23956f97ff0aSJeremy L Thompson     ///     .operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
23966f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
23976f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2398356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
23996f97ff0aSJeremy L Thompson     ///
24006f97ff0aSJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
24016f97ff0aSJeremy L Thompson     /// let op_build_diff = ceed
24026f97ff0aSJeremy L Thompson     ///     .operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
24036f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
24046f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2405356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
24066f97ff0aSJeremy L Thompson     ///
24076f97ff0aSJeremy L Thompson     /// let op_build = ceed
24086f97ff0aSJeremy L Thompson     ///     .composite_operator()?
24096f97ff0aSJeremy L Thompson     ///     .sub_operator(&op_build_mass)?
24106f97ff0aSJeremy L Thompson     ///     .sub_operator(&op_build_diff)?;
24116f97ff0aSJeremy L Thompson     ///
24126f97ff0aSJeremy L Thompson     /// // Check
24136f97ff0aSJeremy L Thompson     /// assert!(op_build.check().is_ok(), "Operator setup incorrectly");
24146f97ff0aSJeremy L Thompson     /// # Ok(())
24156f97ff0aSJeremy L Thompson     /// # }
24166f97ff0aSJeremy L Thompson     /// ```
24176f97ff0aSJeremy L Thompson     pub fn check(self) -> crate::Result<Self> {
24186f97ff0aSJeremy L Thompson         self.op_core.check()?;
24196f97ff0aSJeremy L Thompson         Ok(self)
24206f97ff0aSJeremy L Thompson     }
24216f97ff0aSJeremy L Thompson 
24229df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
24239df49d7eSJed Brown     ///
24249df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
24259df49d7eSJed Brown     ///
24269df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24279df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24289df49d7eSJed Brown     ///
24299df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24309df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
2431b748b478SJeremy L Thompson     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
24329df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
24339df49d7eSJed Brown     }
24349df49d7eSJed Brown 
24359df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
24369df49d7eSJed Brown     ///
24379df49d7eSJed Brown     /// This overwrites a Vector with the point block diagonal of a linear
24389df49d7eSJed Brown     ///   Operator.
24399df49d7eSJed Brown     ///
24409df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24419df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24429df49d7eSJed Brown     ///
24439df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24449df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
24459df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
24469df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
24479df49d7eSJed Brown     }
24489df49d7eSJed Brown 
24499df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
24509df49d7eSJed Brown     ///
24519df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
24529df49d7eSJed Brown     ///
24539df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24549df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24559df49d7eSJed Brown     ///
24569df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24579df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
24589df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
24599df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
24609df49d7eSJed Brown     ///                   this vector are derived from the active vector for
24619df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
24629df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
24639df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
24649df49d7eSJed Brown         &self,
24659df49d7eSJed Brown         assembled: &mut Vector,
24669df49d7eSJed Brown     ) -> crate::Result<i32> {
24679df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
24689df49d7eSJed Brown     }
24699df49d7eSJed Brown 
24709df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
24719df49d7eSJed Brown     ///
24729df49d7eSJed Brown     /// This sums into a Vector with the diagonal of a linear Operator.
24739df49d7eSJed Brown     ///
24749df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24759df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24769df49d7eSJed Brown     ///
24779df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24789df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
24799df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
24809df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
24819df49d7eSJed Brown     ///                   this vector are derived from the active vector for
24829df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
24839df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
24849df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
24859df49d7eSJed Brown         &self,
24869df49d7eSJed Brown         assembled: &mut Vector,
24879df49d7eSJed Brown     ) -> crate::Result<i32> {
24889df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
24899df49d7eSJed Brown     }
24909df49d7eSJed Brown }
24919df49d7eSJed Brown 
24929df49d7eSJed Brown // -----------------------------------------------------------------------------
2493