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