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