xref: /libCEED/rust/libceed/src/operator.rs (revision e03fef56705b317edc4a39dfee40c8366660a6d6)
15aed82e4SJeremy L Thompson // Copyright (c) 2017-2024, 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,
20*e03fef56SJeremy L Thompson     pub(crate) vector: crate::Vector<'a>,
21*e03fef56SJeremy L Thompson     pub(crate) elem_restriction: crate::ElemRestriction<'a>,
22*e03fef56SJeremy L Thompson     pub(crate) basis: crate::Basis<'a>,
2308778c6fSJeremy L Thompson     _lifeline: PhantomData<&'a ()>,
2408778c6fSJeremy L Thompson }
2508778c6fSJeremy L Thompson 
2608778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
2708778c6fSJeremy L Thompson // Implementations
2808778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
2908778c6fSJeremy L Thompson impl<'a> OperatorField<'a> {
30*e03fef56SJeremy L Thompson     pub(crate) fn from_raw(
31*e03fef56SJeremy L Thompson         ptr: bind_ceed::CeedOperatorField,
32*e03fef56SJeremy L Thompson         ceed: crate::Ceed,
33*e03fef56SJeremy L Thompson     ) -> crate::Result<Self> {
34*e03fef56SJeremy L Thompson         let vector = {
35*e03fef56SJeremy L Thompson             let mut vector_ptr = std::ptr::null_mut();
36*e03fef56SJeremy L Thompson             let ierr = unsafe { bind_ceed::CeedOperatorFieldGetVector(ptr, &mut vector_ptr) };
37*e03fef56SJeremy L Thompson             ceed.check_error(ierr)?;
38*e03fef56SJeremy L Thompson             crate::Vector::from_raw(vector_ptr)?
39*e03fef56SJeremy L Thompson         };
40*e03fef56SJeremy L Thompson         let elem_restriction = {
41*e03fef56SJeremy L Thompson             let mut elem_restriction_ptr = std::ptr::null_mut();
42*e03fef56SJeremy L Thompson             let ierr = unsafe {
43*e03fef56SJeremy L Thompson                 bind_ceed::CeedOperatorFieldGetElemRestriction(ptr, &mut elem_restriction_ptr)
44*e03fef56SJeremy L Thompson             };
45*e03fef56SJeremy L Thompson             ceed.check_error(ierr)?;
46*e03fef56SJeremy L Thompson             crate::ElemRestriction::from_raw(elem_restriction_ptr)?
47*e03fef56SJeremy L Thompson         };
48*e03fef56SJeremy L Thompson         let basis = {
49*e03fef56SJeremy L Thompson             let mut basis_ptr = std::ptr::null_mut();
50*e03fef56SJeremy L Thompson             let ierr = unsafe { bind_ceed::CeedOperatorFieldGetBasis(ptr, &mut basis_ptr) };
51*e03fef56SJeremy L Thompson             ceed.check_error(ierr)?;
52*e03fef56SJeremy L Thompson             crate::Basis::from_raw(basis_ptr)?
53*e03fef56SJeremy L Thompson         };
54*e03fef56SJeremy L Thompson         Ok(Self {
55*e03fef56SJeremy L Thompson             ptr,
56*e03fef56SJeremy L Thompson             vector,
57*e03fef56SJeremy L Thompson             elem_restriction,
58*e03fef56SJeremy L Thompson             basis,
59*e03fef56SJeremy L Thompson             _lifeline: PhantomData,
60*e03fef56SJeremy L Thompson         })
61*e03fef56SJeremy L Thompson     }
62*e03fef56SJeremy L Thompson 
6308778c6fSJeremy L Thompson     /// Get the name of an OperatorField
6408778c6fSJeremy L Thompson     ///
6508778c6fSJeremy L Thompson     /// ```
6608778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
674d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
6808778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
6908778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
7008778c6fSJeremy L Thompson     ///
7108778c6fSJeremy L Thompson     /// // Operator field arguments
7208778c6fSJeremy L Thompson     /// let ne = 3;
7308778c6fSJeremy L Thompson     /// let q = 4 as usize;
7408778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
7508778c6fSJeremy L Thompson     /// for i in 0..ne {
7608778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
7708778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
7808778c6fSJeremy L Thompson     /// }
7908778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
8008778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
81d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
8208778c6fSJeremy L Thompson     ///
8308778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
8408778c6fSJeremy L Thompson     ///
8508778c6fSJeremy L Thompson     /// // Operator fields
8608778c6fSJeremy L Thompson     /// let op = ceed
8708778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
8808778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
8908778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
90356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
9108778c6fSJeremy L Thompson     ///
9208778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
9308778c6fSJeremy L Thompson     ///
9408778c6fSJeremy L Thompson     /// assert_eq!(inputs[0].name(), "dx", "Incorrect input name");
9508778c6fSJeremy L Thompson     /// assert_eq!(inputs[1].name(), "weights", "Incorrect input name");
9608778c6fSJeremy L Thompson     /// # Ok(())
9708778c6fSJeremy L Thompson     /// # }
9808778c6fSJeremy L Thompson     /// ```
9908778c6fSJeremy L Thompson     pub fn name(&self) -> &str {
10008778c6fSJeremy L Thompson         let mut name_ptr: *mut std::os::raw::c_char = std::ptr::null_mut();
10108778c6fSJeremy L Thompson         unsafe {
1026f8994e9SJeremy L Thompson             bind_ceed::CeedOperatorFieldGetName(
1036f8994e9SJeremy L Thompson                 self.ptr,
1046f8994e9SJeremy L Thompson                 &mut name_ptr as *const _ as *mut *const _,
1056f8994e9SJeremy L Thompson             );
10608778c6fSJeremy L Thompson         }
10708778c6fSJeremy L Thompson         unsafe { CStr::from_ptr(name_ptr) }.to_str().unwrap()
10808778c6fSJeremy L Thompson     }
10908778c6fSJeremy L Thompson 
11008778c6fSJeremy L Thompson     /// Get the ElemRestriction of an OperatorField
11108778c6fSJeremy L Thompson     ///
11208778c6fSJeremy L Thompson     /// ```
11308778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
1144d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
11508778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
11608778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
11708778c6fSJeremy L Thompson     ///
11808778c6fSJeremy L Thompson     /// // Operator field arguments
11908778c6fSJeremy L Thompson     /// let ne = 3;
12008778c6fSJeremy L Thompson     /// let q = 4 as usize;
12108778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
12208778c6fSJeremy L Thompson     /// for i in 0..ne {
12308778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
12408778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
12508778c6fSJeremy L Thompson     /// }
12608778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
12708778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
128d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
12908778c6fSJeremy L Thompson     ///
13008778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
13108778c6fSJeremy L Thompson     ///
13208778c6fSJeremy L Thompson     /// // Operator fields
13308778c6fSJeremy L Thompson     /// let op = ceed
13408778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
13508778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
13608778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
137356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
13808778c6fSJeremy L Thompson     ///
13908778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
14008778c6fSJeremy L Thompson     ///
14108778c6fSJeremy L Thompson     /// assert!(
14208778c6fSJeremy L Thompson     ///     inputs[0].elem_restriction().is_some(),
14308778c6fSJeremy L Thompson     ///     "Incorrect field ElemRestriction"
14408778c6fSJeremy L Thompson     /// );
14508778c6fSJeremy L Thompson     /// assert!(
14608778c6fSJeremy L Thompson     ///     inputs[1].elem_restriction().is_none(),
14708778c6fSJeremy L Thompson     ///     "Incorrect field ElemRestriction"
14808778c6fSJeremy L Thompson     /// );
149*e03fef56SJeremy L Thompson     ///
150*e03fef56SJeremy L Thompson     /// let outputs = op.outputs()?;
151*e03fef56SJeremy L Thompson     ///
152*e03fef56SJeremy L Thompson     /// assert!(
153*e03fef56SJeremy L Thompson     ///     outputs[0].elem_restriction().is_some(),
154*e03fef56SJeremy L Thompson     ///     "Incorrect field ElemRestriction"
155*e03fef56SJeremy L Thompson     /// );
15608778c6fSJeremy L Thompson     /// # Ok(())
15708778c6fSJeremy L Thompson     /// # }
15808778c6fSJeremy L Thompson     /// ```
15908778c6fSJeremy L Thompson     pub fn elem_restriction(&self) -> ElemRestrictionOpt {
160*e03fef56SJeremy L Thompson         if self.elem_restriction.ptr == unsafe { bind_ceed::CEED_ELEMRESTRICTION_NONE } {
16108778c6fSJeremy L Thompson             ElemRestrictionOpt::None
16208778c6fSJeremy L Thompson         } else {
163*e03fef56SJeremy L Thompson             ElemRestrictionOpt::Some(&self.elem_restriction)
16408778c6fSJeremy L Thompson         }
16508778c6fSJeremy L Thompson     }
16608778c6fSJeremy L Thompson 
16708778c6fSJeremy L Thompson     /// Get the Basis of an OperatorField
16808778c6fSJeremy L Thompson     ///
16908778c6fSJeremy L Thompson     /// ```
17008778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
1714d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
17208778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
17308778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
17408778c6fSJeremy L Thompson     ///
17508778c6fSJeremy L Thompson     /// // Operator field arguments
17608778c6fSJeremy L Thompson     /// let ne = 3;
17708778c6fSJeremy L Thompson     /// let q = 4 as usize;
17808778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
17908778c6fSJeremy L Thompson     /// for i in 0..ne {
18008778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
18108778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
18208778c6fSJeremy L Thompson     /// }
18308778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
18408778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
185d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
18608778c6fSJeremy L Thompson     ///
18708778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
18808778c6fSJeremy L Thompson     ///
18908778c6fSJeremy L Thompson     /// // Operator fields
19008778c6fSJeremy L Thompson     /// let op = ceed
19108778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
19208778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
19308778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
194356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
19508778c6fSJeremy L Thompson     ///
19608778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
19708778c6fSJeremy L Thompson     ///
19808778c6fSJeremy L Thompson     /// assert!(inputs[0].basis().is_some(), "Incorrect field Basis");
19908778c6fSJeremy L Thompson     /// assert!(inputs[1].basis().is_some(), "Incorrect field Basis");
20008778c6fSJeremy L Thompson     ///
20108778c6fSJeremy L Thompson     /// let outputs = op.outputs()?;
20208778c6fSJeremy L Thompson     ///
203356036faSJeremy L Thompson     /// assert!(outputs[0].basis().is_none(), "Incorrect field Basis");
20408778c6fSJeremy L Thompson     /// # Ok(())
20508778c6fSJeremy L Thompson     /// # }
20608778c6fSJeremy L Thompson     /// ```
20708778c6fSJeremy L Thompson     pub fn basis(&self) -> BasisOpt {
208*e03fef56SJeremy L Thompson         if self.basis.ptr == unsafe { bind_ceed::CEED_BASIS_NONE } {
209356036faSJeremy L Thompson             BasisOpt::None
21008778c6fSJeremy L Thompson         } else {
211*e03fef56SJeremy L Thompson             BasisOpt::Some(&self.basis)
21208778c6fSJeremy L Thompson         }
21308778c6fSJeremy L Thompson     }
21408778c6fSJeremy L Thompson 
21508778c6fSJeremy L Thompson     /// Get the Vector of an OperatorField
21608778c6fSJeremy L Thompson     ///
21708778c6fSJeremy L Thompson     /// ```
21808778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
2194d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
22008778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
22108778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
22208778c6fSJeremy L Thompson     ///
22308778c6fSJeremy L Thompson     /// // Operator field arguments
22408778c6fSJeremy L Thompson     /// let ne = 3;
22508778c6fSJeremy L Thompson     /// let q = 4 as usize;
22608778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
22708778c6fSJeremy L Thompson     /// for i in 0..ne {
22808778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
22908778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
23008778c6fSJeremy L Thompson     /// }
23108778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
23208778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
233d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
23408778c6fSJeremy L Thompson     ///
23508778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
23608778c6fSJeremy L Thompson     ///
23708778c6fSJeremy L Thompson     /// // Operator fields
23808778c6fSJeremy L Thompson     /// let op = ceed
23908778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
24008778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
24108778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
242356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
24308778c6fSJeremy L Thompson     ///
24408778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
24508778c6fSJeremy L Thompson     ///
24608778c6fSJeremy L Thompson     /// assert!(inputs[0].vector().is_active(), "Incorrect field Vector");
24708778c6fSJeremy L Thompson     /// assert!(inputs[1].vector().is_none(), "Incorrect field Vector");
248*e03fef56SJeremy L Thompson     ///
249*e03fef56SJeremy L Thompson     /// let outputs = op.outputs()?;
250*e03fef56SJeremy L Thompson     ///
251*e03fef56SJeremy L Thompson     /// assert!(outputs[0].vector().is_active(), "Incorrect field Vector");
25208778c6fSJeremy L Thompson     /// # Ok(())
25308778c6fSJeremy L Thompson     /// # }
25408778c6fSJeremy L Thompson     /// ```
25508778c6fSJeremy L Thompson     pub fn vector(&self) -> VectorOpt {
256*e03fef56SJeremy L Thompson         if self.vector.ptr == unsafe { bind_ceed::CEED_VECTOR_ACTIVE } {
25708778c6fSJeremy L Thompson             VectorOpt::Active
258*e03fef56SJeremy L Thompson         } else if self.vector.ptr == unsafe { bind_ceed::CEED_VECTOR_NONE } {
25908778c6fSJeremy L Thompson             VectorOpt::None
26008778c6fSJeremy L Thompson         } else {
261*e03fef56SJeremy L Thompson             VectorOpt::Some(&self.vector)
26208778c6fSJeremy L Thompson         }
26308778c6fSJeremy L Thompson     }
26408778c6fSJeremy L Thompson }
26508778c6fSJeremy L Thompson 
26608778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
2677ed177dbSJed Brown // Operator context wrapper
2689df49d7eSJed Brown // -----------------------------------------------------------------------------
269c68be7a2SJeremy L Thompson #[derive(Debug)]
2709df49d7eSJed Brown pub(crate) struct OperatorCore<'a> {
2719df49d7eSJed Brown     ptr: bind_ceed::CeedOperator,
2721142270cSJeremy L Thompson     _lifeline: PhantomData<&'a ()>,
2739df49d7eSJed Brown }
2749df49d7eSJed Brown 
275c68be7a2SJeremy L Thompson #[derive(Debug)]
2769df49d7eSJed Brown pub struct Operator<'a> {
2779df49d7eSJed Brown     op_core: OperatorCore<'a>,
2789df49d7eSJed Brown }
2799df49d7eSJed Brown 
280c68be7a2SJeremy L Thompson #[derive(Debug)]
2819df49d7eSJed Brown pub struct CompositeOperator<'a> {
2829df49d7eSJed Brown     op_core: OperatorCore<'a>,
2839df49d7eSJed Brown }
2849df49d7eSJed Brown 
2859df49d7eSJed Brown // -----------------------------------------------------------------------------
2869df49d7eSJed Brown // Destructor
2879df49d7eSJed Brown // -----------------------------------------------------------------------------
2889df49d7eSJed Brown impl<'a> Drop for OperatorCore<'a> {
2899df49d7eSJed Brown     fn drop(&mut self) {
2909df49d7eSJed Brown         unsafe {
2919df49d7eSJed Brown             bind_ceed::CeedOperatorDestroy(&mut self.ptr);
2929df49d7eSJed Brown         }
2939df49d7eSJed Brown     }
2949df49d7eSJed Brown }
2959df49d7eSJed Brown 
2969df49d7eSJed Brown // -----------------------------------------------------------------------------
2979df49d7eSJed Brown // Display
2989df49d7eSJed Brown // -----------------------------------------------------------------------------
2999df49d7eSJed Brown impl<'a> fmt::Display for OperatorCore<'a> {
3009df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3019df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
3029df49d7eSJed Brown         let mut sizeloc = crate::MAX_BUFFER_LENGTH;
3039df49d7eSJed Brown         let cstring = unsafe {
3049df49d7eSJed Brown             let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc);
3059df49d7eSJed Brown             bind_ceed::CeedOperatorView(self.ptr, file);
3069df49d7eSJed Brown             bind_ceed::fclose(file);
3079df49d7eSJed Brown             CString::from_raw(ptr)
3089df49d7eSJed Brown         };
3099df49d7eSJed Brown         cstring.to_string_lossy().fmt(f)
3109df49d7eSJed Brown     }
3119df49d7eSJed Brown }
3129df49d7eSJed Brown 
3139df49d7eSJed Brown /// View an Operator
3149df49d7eSJed Brown ///
3159df49d7eSJed Brown /// ```
3169df49d7eSJed Brown /// # use libceed::prelude::*;
3174d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
3189df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
319c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
3209df49d7eSJed Brown ///
3219df49d7eSJed Brown /// // Operator field arguments
3229df49d7eSJed Brown /// let ne = 3;
3239df49d7eSJed Brown /// let q = 4 as usize;
3249df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne];
3259df49d7eSJed Brown /// for i in 0..ne {
3269df49d7eSJed Brown ///     ind[2 * i + 0] = i as i32;
3279df49d7eSJed Brown ///     ind[2 * i + 1] = (i + 1) as i32;
3289df49d7eSJed Brown /// }
329c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
3309df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32];
331d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
3329df49d7eSJed Brown ///
333c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
3349df49d7eSJed Brown ///
3359df49d7eSJed Brown /// // Operator fields
3369df49d7eSJed Brown /// let op = ceed
337c68be7a2SJeremy L Thompson ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
338ea6b5821SJeremy L Thompson ///     .name("mass")?
339c68be7a2SJeremy L Thompson ///     .field("dx", &r, &b, VectorOpt::Active)?
340c68be7a2SJeremy L Thompson ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
341356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
3429df49d7eSJed Brown ///
3439df49d7eSJed Brown /// println!("{}", op);
344c68be7a2SJeremy L Thompson /// # Ok(())
345c68be7a2SJeremy L Thompson /// # }
3469df49d7eSJed Brown /// ```
3479df49d7eSJed Brown impl<'a> fmt::Display for Operator<'a> {
3489df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3499df49d7eSJed Brown         self.op_core.fmt(f)
3509df49d7eSJed Brown     }
3519df49d7eSJed Brown }
3529df49d7eSJed Brown 
3539df49d7eSJed Brown /// View a composite Operator
3549df49d7eSJed Brown ///
3559df49d7eSJed Brown /// ```
3569df49d7eSJed Brown /// # use libceed::prelude::*;
3574d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
3589df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
3599df49d7eSJed Brown ///
3609df49d7eSJed Brown /// // Sub operator field arguments
3619df49d7eSJed Brown /// let ne = 3;
3629df49d7eSJed Brown /// let q = 4 as usize;
3639df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne];
3649df49d7eSJed Brown /// for i in 0..ne {
3659df49d7eSJed Brown ///     ind[2 * i + 0] = i as i32;
3669df49d7eSJed Brown ///     ind[2 * i + 1] = (i + 1) as i32;
3679df49d7eSJed Brown /// }
368c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
3699df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32];
370d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
3719df49d7eSJed Brown ///
372c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
3739df49d7eSJed Brown ///
374c68be7a2SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?;
375c68be7a2SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?;
3769df49d7eSJed Brown ///
377c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
3789df49d7eSJed Brown /// let op_mass = ceed
379c68be7a2SJeremy L Thompson ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
380ea6b5821SJeremy L Thompson ///     .name("Mass term")?
381c68be7a2SJeremy L Thompson ///     .field("u", &r, &b, VectorOpt::Active)?
382356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
383c68be7a2SJeremy L Thompson ///     .field("v", &r, &b, VectorOpt::Active)?;
3849df49d7eSJed Brown ///
385c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
3869df49d7eSJed Brown /// let op_diff = ceed
387c68be7a2SJeremy L Thompson ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
388ea6b5821SJeremy L Thompson ///     .name("Poisson term")?
389c68be7a2SJeremy L Thompson ///     .field("du", &r, &b, VectorOpt::Active)?
390356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
391c68be7a2SJeremy L Thompson ///     .field("dv", &r, &b, VectorOpt::Active)?;
3929df49d7eSJed Brown ///
3939df49d7eSJed Brown /// let op = ceed
394c68be7a2SJeremy L Thompson ///     .composite_operator()?
395ea6b5821SJeremy L Thompson ///     .name("Screened Poisson")?
396c68be7a2SJeremy L Thompson ///     .sub_operator(&op_mass)?
397c68be7a2SJeremy L Thompson ///     .sub_operator(&op_diff)?;
3989df49d7eSJed Brown ///
3999df49d7eSJed Brown /// println!("{}", op);
400c68be7a2SJeremy L Thompson /// # Ok(())
401c68be7a2SJeremy L Thompson /// # }
4029df49d7eSJed Brown /// ```
4039df49d7eSJed Brown impl<'a> fmt::Display for CompositeOperator<'a> {
4049df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4059df49d7eSJed Brown         self.op_core.fmt(f)
4069df49d7eSJed Brown     }
4079df49d7eSJed Brown }
4089df49d7eSJed Brown 
4099df49d7eSJed Brown // -----------------------------------------------------------------------------
4109df49d7eSJed Brown // Core functionality
4119df49d7eSJed Brown // -----------------------------------------------------------------------------
4129df49d7eSJed Brown impl<'a> OperatorCore<'a> {
4131142270cSJeremy L Thompson     // Error handling
4141142270cSJeremy L Thompson     #[doc(hidden)]
4151142270cSJeremy L Thompson     fn check_error(&self, ierr: i32) -> crate::Result<i32> {
4161142270cSJeremy L Thompson         let mut ptr = std::ptr::null_mut();
4171142270cSJeremy L Thompson         unsafe {
4181142270cSJeremy L Thompson             bind_ceed::CeedOperatorGetCeed(self.ptr, &mut ptr);
4191142270cSJeremy L Thompson         }
4201142270cSJeremy L Thompson         crate::check_error(ptr, ierr)
4211142270cSJeremy L Thompson     }
4221142270cSJeremy L Thompson 
4239df49d7eSJed Brown     // Common implementations
4246f97ff0aSJeremy L Thompson     pub fn check(&self) -> crate::Result<i32> {
4256f97ff0aSJeremy L Thompson         let ierr = unsafe { bind_ceed::CeedOperatorCheckReady(self.ptr) };
4266f97ff0aSJeremy L Thompson         self.check_error(ierr)
4276f97ff0aSJeremy L Thompson     }
4286f97ff0aSJeremy L Thompson 
429ea6b5821SJeremy L Thompson     pub fn name(&self, name: &str) -> crate::Result<i32> {
430ea6b5821SJeremy L Thompson         let name_c = CString::new(name).expect("CString::new failed");
431ea6b5821SJeremy L Thompson         let ierr = unsafe { bind_ceed::CeedOperatorSetName(self.ptr, name_c.as_ptr()) };
432ea6b5821SJeremy L Thompson         self.check_error(ierr)
433ea6b5821SJeremy L Thompson     }
434ea6b5821SJeremy L Thompson 
4359df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
4369df49d7eSJed Brown         let ierr = unsafe {
4379df49d7eSJed Brown             bind_ceed::CeedOperatorApply(
4389df49d7eSJed Brown                 self.ptr,
4399df49d7eSJed Brown                 input.ptr,
4409df49d7eSJed Brown                 output.ptr,
4419df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4429df49d7eSJed Brown             )
4439df49d7eSJed Brown         };
4441142270cSJeremy L Thompson         self.check_error(ierr)
4459df49d7eSJed Brown     }
4469df49d7eSJed Brown 
4479df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
4489df49d7eSJed Brown         let ierr = unsafe {
4499df49d7eSJed Brown             bind_ceed::CeedOperatorApplyAdd(
4509df49d7eSJed Brown                 self.ptr,
4519df49d7eSJed Brown                 input.ptr,
4529df49d7eSJed Brown                 output.ptr,
4539df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4549df49d7eSJed Brown             )
4559df49d7eSJed Brown         };
4561142270cSJeremy L Thompson         self.check_error(ierr)
4579df49d7eSJed Brown     }
4589df49d7eSJed Brown 
4599df49d7eSJed Brown     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
4609df49d7eSJed Brown         let ierr = unsafe {
4619df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleDiagonal(
4629df49d7eSJed Brown                 self.ptr,
4639df49d7eSJed Brown                 assembled.ptr,
4649df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4659df49d7eSJed Brown             )
4669df49d7eSJed Brown         };
4671142270cSJeremy L Thompson         self.check_error(ierr)
4689df49d7eSJed Brown     }
4699df49d7eSJed Brown 
4709df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
4719df49d7eSJed Brown         let ierr = unsafe {
4729df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleAddDiagonal(
4739df49d7eSJed Brown                 self.ptr,
4749df49d7eSJed Brown                 assembled.ptr,
4759df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4769df49d7eSJed Brown             )
4779df49d7eSJed Brown         };
4781142270cSJeremy L Thompson         self.check_error(ierr)
4799df49d7eSJed Brown     }
4809df49d7eSJed Brown 
4819df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
4829df49d7eSJed Brown         &self,
4839df49d7eSJed Brown         assembled: &mut Vector,
4849df49d7eSJed Brown     ) -> crate::Result<i32> {
4859df49d7eSJed Brown         let ierr = unsafe {
4869df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssemblePointBlockDiagonal(
4879df49d7eSJed Brown                 self.ptr,
4889df49d7eSJed Brown                 assembled.ptr,
4899df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4909df49d7eSJed Brown             )
4919df49d7eSJed Brown         };
4921142270cSJeremy L Thompson         self.check_error(ierr)
4939df49d7eSJed Brown     }
4949df49d7eSJed Brown 
4959df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
4969df49d7eSJed Brown         &self,
4979df49d7eSJed Brown         assembled: &mut Vector,
4989df49d7eSJed Brown     ) -> crate::Result<i32> {
4999df49d7eSJed Brown         let ierr = unsafe {
5009df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleAddPointBlockDiagonal(
5019df49d7eSJed Brown                 self.ptr,
5029df49d7eSJed Brown                 assembled.ptr,
5039df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
5049df49d7eSJed Brown             )
5059df49d7eSJed Brown         };
5061142270cSJeremy L Thompson         self.check_error(ierr)
5079df49d7eSJed Brown     }
5089df49d7eSJed Brown }
5099df49d7eSJed Brown 
5109df49d7eSJed Brown // -----------------------------------------------------------------------------
5119df49d7eSJed Brown // Operator
5129df49d7eSJed Brown // -----------------------------------------------------------------------------
5139df49d7eSJed Brown impl<'a> Operator<'a> {
5149df49d7eSJed Brown     // Constructor
5159df49d7eSJed Brown     pub fn create<'b>(
516594ef120SJeremy L Thompson         ceed: &crate::Ceed,
5179df49d7eSJed Brown         qf: impl Into<QFunctionOpt<'b>>,
5189df49d7eSJed Brown         dqf: impl Into<QFunctionOpt<'b>>,
5199df49d7eSJed Brown         dqfT: impl Into<QFunctionOpt<'b>>,
5209df49d7eSJed Brown     ) -> crate::Result<Self> {
5219df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
5229df49d7eSJed Brown         let ierr = unsafe {
5239df49d7eSJed Brown             bind_ceed::CeedOperatorCreate(
5249df49d7eSJed Brown                 ceed.ptr,
5259df49d7eSJed Brown                 qf.into().to_raw(),
5269df49d7eSJed Brown                 dqf.into().to_raw(),
5279df49d7eSJed Brown                 dqfT.into().to_raw(),
5289df49d7eSJed Brown                 &mut ptr,
5299df49d7eSJed Brown             )
5309df49d7eSJed Brown         };
5319df49d7eSJed Brown         ceed.check_error(ierr)?;
5329df49d7eSJed Brown         Ok(Self {
5331142270cSJeremy L Thompson             op_core: OperatorCore {
5341142270cSJeremy L Thompson                 ptr,
5351142270cSJeremy L Thompson                 _lifeline: PhantomData,
5361142270cSJeremy L Thompson             },
5379df49d7eSJed Brown         })
5389df49d7eSJed Brown     }
5399df49d7eSJed Brown 
5401142270cSJeremy L Thompson     fn from_raw(ptr: bind_ceed::CeedOperator) -> crate::Result<Self> {
5419df49d7eSJed Brown         Ok(Self {
5421142270cSJeremy L Thompson             op_core: OperatorCore {
5431142270cSJeremy L Thompson                 ptr,
5441142270cSJeremy L Thompson                 _lifeline: PhantomData,
5451142270cSJeremy L Thompson             },
5469df49d7eSJed Brown         })
5479df49d7eSJed Brown     }
5489df49d7eSJed Brown 
549ea6b5821SJeremy L Thompson     /// Set name for Operator printing
550ea6b5821SJeremy L Thompson     ///
551ea6b5821SJeremy L Thompson     /// * 'name' - Name to set
552ea6b5821SJeremy L Thompson     ///
553ea6b5821SJeremy L Thompson     /// ```
554ea6b5821SJeremy L Thompson     /// # use libceed::prelude::*;
555ea6b5821SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
556ea6b5821SJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
557ea6b5821SJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
558ea6b5821SJeremy L Thompson     ///
559ea6b5821SJeremy L Thompson     /// // Operator field arguments
560ea6b5821SJeremy L Thompson     /// let ne = 3;
561ea6b5821SJeremy L Thompson     /// let q = 4 as usize;
562ea6b5821SJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
563ea6b5821SJeremy L Thompson     /// for i in 0..ne {
564ea6b5821SJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
565ea6b5821SJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
566ea6b5821SJeremy L Thompson     /// }
567ea6b5821SJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
568ea6b5821SJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
569d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
570ea6b5821SJeremy L Thompson     ///
571ea6b5821SJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
572ea6b5821SJeremy L Thompson     ///
573ea6b5821SJeremy L Thompson     /// // Operator fields
574ea6b5821SJeremy L Thompson     /// let op = ceed
575ea6b5821SJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
576ea6b5821SJeremy L Thompson     ///     .name("mass")?
577ea6b5821SJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
578ea6b5821SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
579356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
580ea6b5821SJeremy L Thompson     /// # Ok(())
581ea6b5821SJeremy L Thompson     /// # }
582ea6b5821SJeremy L Thompson     /// ```
583ea6b5821SJeremy L Thompson     #[allow(unused_mut)]
584ea6b5821SJeremy L Thompson     pub fn name(mut self, name: &str) -> crate::Result<Self> {
585ea6b5821SJeremy L Thompson         self.op_core.name(name)?;
586ea6b5821SJeremy L Thompson         Ok(self)
587ea6b5821SJeremy L Thompson     }
588ea6b5821SJeremy L Thompson 
5899df49d7eSJed Brown     /// Apply Operator to a vector
5909df49d7eSJed Brown     ///
5919df49d7eSJed Brown     /// * `input`  - Input Vector
5929df49d7eSJed Brown     /// * `output` - Output Vector
5939df49d7eSJed Brown     ///
5949df49d7eSJed Brown     /// ```
5959df49d7eSJed Brown     /// # use libceed::prelude::*;
5964d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
5979df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
5989df49d7eSJed Brown     /// let ne = 4;
5999df49d7eSJed Brown     /// let p = 3;
6009df49d7eSJed Brown     /// let q = 4;
6019df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
6029df49d7eSJed Brown     ///
6039df49d7eSJed Brown     /// // Vectors
604c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
605c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
6069df49d7eSJed Brown     /// qdata.set_value(0.0);
607c68be7a2SJeremy L Thompson     /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?;
608c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
6099df49d7eSJed Brown     /// v.set_value(0.0);
6109df49d7eSJed Brown     ///
6119df49d7eSJed Brown     /// // Restrictions
6129df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
6139df49d7eSJed Brown     /// for i in 0..ne {
6149df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
6159df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
6169df49d7eSJed Brown     /// }
617c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
6189df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
6199df49d7eSJed Brown     /// for i in 0..ne {
6209df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
6219df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
6229df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
6239df49d7eSJed Brown     /// }
624c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
6259df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
626c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
6279df49d7eSJed Brown     ///
6289df49d7eSJed Brown     /// // Bases
629c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
630c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
6319df49d7eSJed Brown     ///
6329df49d7eSJed Brown     /// // Build quadrature data
633c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
634c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
635c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
636c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
637356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
638c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
6399df49d7eSJed Brown     ///
6409df49d7eSJed Brown     /// // Mass operator
641c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
6429df49d7eSJed Brown     /// let op_mass = ceed
643c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
644c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
645356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
646c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
6479df49d7eSJed Brown     ///
6489df49d7eSJed Brown     /// v.set_value(0.0);
649c68be7a2SJeremy L Thompson     /// op_mass.apply(&u, &mut v)?;
6509df49d7eSJed Brown     ///
6519df49d7eSJed Brown     /// // Check
652e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
6534b61a5a0SRezgar Shakeri     /// let error: Scalar = (sum - 2.0).abs();
6549df49d7eSJed Brown     /// assert!(
6554b61a5a0SRezgar Shakeri     ///     error < 50.0 * libceed::EPSILON,
6564b61a5a0SRezgar Shakeri     ///     "Incorrect interval length computed. Expected: 2.0, Found: {}, Error: {:.12e}",
6574b61a5a0SRezgar Shakeri     ///     sum,
6584b61a5a0SRezgar Shakeri     ///     error
6599df49d7eSJed Brown     /// );
660c68be7a2SJeremy L Thompson     /// # Ok(())
661c68be7a2SJeremy L Thompson     /// # }
6629df49d7eSJed Brown     /// ```
6639df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
6649df49d7eSJed Brown         self.op_core.apply(input, output)
6659df49d7eSJed Brown     }
6669df49d7eSJed Brown 
6679df49d7eSJed Brown     /// Apply Operator to a vector and add result to output vector
6689df49d7eSJed Brown     ///
6699df49d7eSJed Brown     /// * `input`  - Input Vector
6709df49d7eSJed Brown     /// * `output` - Output Vector
6719df49d7eSJed Brown     ///
6729df49d7eSJed Brown     /// ```
6739df49d7eSJed Brown     /// # use libceed::prelude::*;
6744d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
6759df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
6769df49d7eSJed Brown     /// let ne = 4;
6779df49d7eSJed Brown     /// let p = 3;
6789df49d7eSJed Brown     /// let q = 4;
6799df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
6809df49d7eSJed Brown     ///
6819df49d7eSJed Brown     /// // Vectors
682c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
683c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
6849df49d7eSJed Brown     /// qdata.set_value(0.0);
685c68be7a2SJeremy L Thompson     /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?;
686c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
6879df49d7eSJed Brown     ///
6889df49d7eSJed Brown     /// // Restrictions
6899df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
6909df49d7eSJed Brown     /// for i in 0..ne {
6919df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
6929df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
6939df49d7eSJed Brown     /// }
694c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
6959df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
6969df49d7eSJed Brown     /// for i in 0..ne {
6979df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
6989df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
6999df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
7009df49d7eSJed Brown     /// }
701c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
7029df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
703c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
7049df49d7eSJed Brown     ///
7059df49d7eSJed Brown     /// // Bases
706c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
707c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
7089df49d7eSJed Brown     ///
7099df49d7eSJed Brown     /// // Build quadrature data
710c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
711c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
712c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
713c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
714356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
715c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
7169df49d7eSJed Brown     ///
7179df49d7eSJed Brown     /// // Mass operator
718c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
7199df49d7eSJed Brown     /// let op_mass = ceed
720c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
721c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
722356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
723c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
7249df49d7eSJed Brown     ///
7259df49d7eSJed Brown     /// v.set_value(1.0);
726c68be7a2SJeremy L Thompson     /// op_mass.apply_add(&u, &mut v)?;
7279df49d7eSJed Brown     ///
7289df49d7eSJed Brown     /// // Check
729e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
7309df49d7eSJed Brown     /// assert!(
73180a9ef05SNatalie Beams     ///     (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON,
7329df49d7eSJed Brown     ///     "Incorrect interval length computed and added"
7339df49d7eSJed Brown     /// );
734c68be7a2SJeremy L Thompson     /// # Ok(())
735c68be7a2SJeremy L Thompson     /// # }
7369df49d7eSJed Brown     /// ```
7379df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
7389df49d7eSJed Brown         self.op_core.apply_add(input, output)
7399df49d7eSJed Brown     }
7409df49d7eSJed Brown 
7419df49d7eSJed Brown     /// Provide a field to a Operator for use by its QFunction
7429df49d7eSJed Brown     ///
7439df49d7eSJed Brown     /// * `fieldname` - Name of the field (to be matched with the name used by
7449df49d7eSJed Brown     ///                   the QFunction)
7459df49d7eSJed Brown     /// * `r`         - ElemRestriction
746356036faSJeremy L Thompson     /// * `b`         - Basis in which the field resides or `BasisOpt::None`
747356036faSJeremy L Thompson     /// * `v`         - Vector to be used by Operator or `VectorOpt::Active` if field
748356036faSJeremy L Thompson     ///                   is active or `VectorOpt::None` 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];
817d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
81808778c6fSJeremy L Thompson     ///
81908778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
82008778c6fSJeremy L Thompson     ///
82108778c6fSJeremy L Thompson     /// // Operator fields
82208778c6fSJeremy L Thompson     /// let op = ceed
82308778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
82408778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
82508778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
826356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, 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     /// ```
834*e03fef56SJeremy L Thompson     pub fn inputs(&self) -> crate::Result<Vec<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(
851*e03fef56SJeremy L Thompson                 inputs_ptr as *mut bind_ceed::CeedOperatorField,
85208778c6fSJeremy L Thompson                 num_inputs as usize,
85308778c6fSJeremy L Thompson             )
85408778c6fSJeremy L Thompson         };
855*e03fef56SJeremy L Thompson         // And finally build vec
856*e03fef56SJeremy L Thompson         let ceed = {
857*e03fef56SJeremy L Thompson             let mut ptr = std::ptr::null_mut();
858*e03fef56SJeremy L Thompson             let mut ptr_copy = std::ptr::null_mut();
859*e03fef56SJeremy L Thompson             unsafe {
860*e03fef56SJeremy L Thompson                 bind_ceed::CeedOperatorGetCeed(self.op_core.ptr, &mut ptr);
861*e03fef56SJeremy L Thompson                 bind_ceed::CeedReferenceCopy(ptr, &mut ptr_copy); // refcount
862*e03fef56SJeremy L Thompson             }
863*e03fef56SJeremy L Thompson             crate::Ceed { ptr }
864*e03fef56SJeremy L Thompson         };
865*e03fef56SJeremy L Thompson         let inputs = (0..num_inputs as usize)
866*e03fef56SJeremy L Thompson             .map(|i| crate::OperatorField::from_raw(inputs_slice[i], ceed.clone()))
867*e03fef56SJeremy L Thompson             .collect::<crate::Result<Vec<_>>>()?;
868*e03fef56SJeremy L Thompson         Ok(inputs)
86908778c6fSJeremy L Thompson     }
87008778c6fSJeremy L Thompson 
87108778c6fSJeremy L Thompson     /// Get a slice of Operator outputs
87208778c6fSJeremy L Thompson     ///
87308778c6fSJeremy L Thompson     /// ```
87408778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
8754d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
87608778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
87708778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
87808778c6fSJeremy L Thompson     ///
87908778c6fSJeremy L Thompson     /// // Operator field arguments
88008778c6fSJeremy L Thompson     /// let ne = 3;
88108778c6fSJeremy L Thompson     /// let q = 4 as usize;
88208778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
88308778c6fSJeremy L Thompson     /// for i in 0..ne {
88408778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
88508778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
88608778c6fSJeremy L Thompson     /// }
88708778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
88808778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
889d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
89008778c6fSJeremy L Thompson     ///
89108778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
89208778c6fSJeremy L Thompson     ///
89308778c6fSJeremy L Thompson     /// // Operator fields
89408778c6fSJeremy L Thompson     /// let op = ceed
89508778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
89608778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
89708778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
898356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
89908778c6fSJeremy L Thompson     ///
90008778c6fSJeremy L Thompson     /// let outputs = op.outputs()?;
90108778c6fSJeremy L Thompson     ///
90208778c6fSJeremy L Thompson     /// assert_eq!(outputs.len(), 1, "Incorrect outputs array");
90308778c6fSJeremy L Thompson     /// # Ok(())
90408778c6fSJeremy L Thompson     /// # }
90508778c6fSJeremy L Thompson     /// ```
906*e03fef56SJeremy L Thompson     pub fn outputs(&self) -> crate::Result<Vec<crate::OperatorField>> {
90708778c6fSJeremy L Thompson         // Get array of raw C pointers for outputs
90808778c6fSJeremy L Thompson         let mut num_outputs = 0;
90908778c6fSJeremy L Thompson         let mut outputs_ptr = std::ptr::null_mut();
91008778c6fSJeremy L Thompson         let ierr = unsafe {
91108778c6fSJeremy L Thompson             bind_ceed::CeedOperatorGetFields(
91208778c6fSJeremy L Thompson                 self.op_core.ptr,
91308778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut bind_ceed::CeedInt,
91408778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField,
91508778c6fSJeremy L Thompson                 &mut num_outputs,
91608778c6fSJeremy L Thompson                 &mut outputs_ptr,
91708778c6fSJeremy L Thompson             )
91808778c6fSJeremy L Thompson         };
91908778c6fSJeremy L Thompson         self.op_core.check_error(ierr)?;
92008778c6fSJeremy L Thompson         // Convert raw C pointers to fixed length slice
92108778c6fSJeremy L Thompson         let outputs_slice = unsafe {
92208778c6fSJeremy L Thompson             std::slice::from_raw_parts(
923*e03fef56SJeremy L Thompson                 outputs_ptr as *mut bind_ceed::CeedOperatorField,
92408778c6fSJeremy L Thompson                 num_outputs as usize,
92508778c6fSJeremy L Thompson             )
92608778c6fSJeremy L Thompson         };
927*e03fef56SJeremy L Thompson         // And finally build vec
928*e03fef56SJeremy L Thompson         let ceed = {
929*e03fef56SJeremy L Thompson             let mut ptr = std::ptr::null_mut();
930*e03fef56SJeremy L Thompson             let mut ptr_copy = std::ptr::null_mut();
931*e03fef56SJeremy L Thompson             unsafe {
932*e03fef56SJeremy L Thompson                 bind_ceed::CeedOperatorGetCeed(self.op_core.ptr, &mut ptr);
933*e03fef56SJeremy L Thompson                 bind_ceed::CeedReferenceCopy(ptr, &mut ptr_copy); // refcount
934*e03fef56SJeremy L Thompson             }
935*e03fef56SJeremy L Thompson             crate::Ceed { ptr }
936*e03fef56SJeremy L Thompson         };
937*e03fef56SJeremy L Thompson         let outputs = (0..num_outputs as usize)
938*e03fef56SJeremy L Thompson             .map(|i| crate::OperatorField::from_raw(outputs_slice[i], ceed.clone()))
939*e03fef56SJeremy L Thompson             .collect::<crate::Result<Vec<_>>>()?;
940*e03fef56SJeremy L Thompson         Ok(outputs)
94108778c6fSJeremy L Thompson     }
94208778c6fSJeremy L Thompson 
9436f97ff0aSJeremy L Thompson     /// Check if Operator is setup correctly
9446f97ff0aSJeremy L Thompson     ///
9456f97ff0aSJeremy L Thompson     /// ```
9466f97ff0aSJeremy L Thompson     /// # use libceed::prelude::*;
9476f97ff0aSJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
9486f97ff0aSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
9496f97ff0aSJeremy L Thompson     /// let ne = 4;
9506f97ff0aSJeremy L Thompson     /// let p = 3;
9516f97ff0aSJeremy L Thompson     /// let q = 4;
9526f97ff0aSJeremy L Thompson     /// let ndofs = p * ne - ne + 1;
9536f97ff0aSJeremy L Thompson     ///
9546f97ff0aSJeremy L Thompson     /// // Restrictions
9556f97ff0aSJeremy L Thompson     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
9566f97ff0aSJeremy L Thompson     /// for i in 0..ne {
9576f97ff0aSJeremy L Thompson     ///     indx[2 * i + 0] = i as i32;
9586f97ff0aSJeremy L Thompson     ///     indx[2 * i + 1] = (i + 1) as i32;
9596f97ff0aSJeremy L Thompson     /// }
9606f97ff0aSJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
9616f97ff0aSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
9626f97ff0aSJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
9636f97ff0aSJeremy L Thompson     ///
9646f97ff0aSJeremy L Thompson     /// // Bases
9656f97ff0aSJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
9666f97ff0aSJeremy L Thompson     ///
9676f97ff0aSJeremy L Thompson     /// // Build quadrature data
9686f97ff0aSJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
9696f97ff0aSJeremy L Thompson     /// let op_build = ceed
9706f97ff0aSJeremy L Thompson     ///     .operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
9716f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
9726f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
973356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
9746f97ff0aSJeremy L Thompson     ///
9756f97ff0aSJeremy L Thompson     /// // Check
9766f97ff0aSJeremy L Thompson     /// assert!(op_build.check().is_ok(), "Operator setup incorrectly");
9776f97ff0aSJeremy L Thompson     /// # Ok(())
9786f97ff0aSJeremy L Thompson     /// # }
9796f97ff0aSJeremy L Thompson     /// ```
9806f97ff0aSJeremy L Thompson     pub fn check(self) -> crate::Result<Self> {
9816f97ff0aSJeremy L Thompson         self.op_core.check()?;
9826f97ff0aSJeremy L Thompson         Ok(self)
9836f97ff0aSJeremy L Thompson     }
9846f97ff0aSJeremy L Thompson 
9853f2759cfSJeremy L Thompson     /// Get the number of elements associated with an Operator
9863f2759cfSJeremy L Thompson     ///
9873f2759cfSJeremy L Thompson     ///
9883f2759cfSJeremy L Thompson     /// ```
9893f2759cfSJeremy L Thompson     /// # use libceed::prelude::*;
9904d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
9913f2759cfSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
9923f2759cfSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
9933f2759cfSJeremy L Thompson     /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;
9943f2759cfSJeremy L Thompson     ///
9953f2759cfSJeremy L Thompson     /// // Operator field arguments
9963f2759cfSJeremy L Thompson     /// let ne = 3;
9973f2759cfSJeremy L Thompson     /// let q = 4;
9983f2759cfSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
9993f2759cfSJeremy L Thompson     /// for i in 0..ne {
10003f2759cfSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
10013f2759cfSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
10023f2759cfSJeremy L Thompson     /// }
10033f2759cfSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
10043f2759cfSJeremy L Thompson     ///
10053f2759cfSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
10063f2759cfSJeremy L Thompson     ///
10073f2759cfSJeremy L Thompson     /// // Operator field
10083f2759cfSJeremy L Thompson     /// op = op.field("dx", &r, &b, VectorOpt::Active)?;
10093f2759cfSJeremy L Thompson     ///
10103f2759cfSJeremy L Thompson     /// // Check number of elements
10113f2759cfSJeremy L Thompson     /// assert_eq!(op.num_elements(), ne, "Incorrect number of elements");
10123f2759cfSJeremy L Thompson     /// # Ok(())
10133f2759cfSJeremy L Thompson     /// # }
10143f2759cfSJeremy L Thompson     /// ```
10153f2759cfSJeremy L Thompson     pub fn num_elements(&self) -> usize {
10163f2759cfSJeremy L Thompson         let mut nelem = 0;
10173f2759cfSJeremy L Thompson         unsafe { bind_ceed::CeedOperatorGetNumElements(self.op_core.ptr, &mut nelem) };
10183f2759cfSJeremy L Thompson         usize::try_from(nelem).unwrap()
10193f2759cfSJeremy L Thompson     }
10203f2759cfSJeremy L Thompson 
10213f2759cfSJeremy L Thompson     /// Get the number of quadrature points associated with each element of
10223f2759cfSJeremy L Thompson     ///   an Operator
10233f2759cfSJeremy L Thompson     ///
10243f2759cfSJeremy L Thompson     ///
10253f2759cfSJeremy L Thompson     /// ```
10263f2759cfSJeremy L Thompson     /// # use libceed::prelude::*;
10274d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
10283f2759cfSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
10293f2759cfSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
10303f2759cfSJeremy L Thompson     /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;
10313f2759cfSJeremy L Thompson     ///
10323f2759cfSJeremy L Thompson     /// // Operator field arguments
10333f2759cfSJeremy L Thompson     /// let ne = 3;
10343f2759cfSJeremy L Thompson     /// let q = 4;
10353f2759cfSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
10363f2759cfSJeremy L Thompson     /// for i in 0..ne {
10373f2759cfSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
10383f2759cfSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
10393f2759cfSJeremy L Thompson     /// }
10403f2759cfSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
10413f2759cfSJeremy L Thompson     ///
10423f2759cfSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
10433f2759cfSJeremy L Thompson     ///
10443f2759cfSJeremy L Thompson     /// // Operator field
10453f2759cfSJeremy L Thompson     /// op = op.field("dx", &r, &b, VectorOpt::Active)?;
10463f2759cfSJeremy L Thompson     ///
10473f2759cfSJeremy L Thompson     /// // Check number of quadrature points
10483f2759cfSJeremy L Thompson     /// assert_eq!(
10493f2759cfSJeremy L Thompson     ///     op.num_quadrature_points(),
10503f2759cfSJeremy L Thompson     ///     q,
10513f2759cfSJeremy L Thompson     ///     "Incorrect number of quadrature points"
10523f2759cfSJeremy L Thompson     /// );
10533f2759cfSJeremy L Thompson     /// # Ok(())
10543f2759cfSJeremy L Thompson     /// # }
10553f2759cfSJeremy L Thompson     /// ```
10563f2759cfSJeremy L Thompson     pub fn num_quadrature_points(&self) -> usize {
10573f2759cfSJeremy L Thompson         let mut Q = 0;
10583f2759cfSJeremy L Thompson         unsafe { bind_ceed::CeedOperatorGetNumQuadraturePoints(self.op_core.ptr, &mut Q) };
10593f2759cfSJeremy L Thompson         usize::try_from(Q).unwrap()
10603f2759cfSJeremy L Thompson     }
10613f2759cfSJeremy L Thompson 
10629df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
10639df49d7eSJed Brown     ///
10649df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
10659df49d7eSJed Brown     ///
10669df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
10679df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
10689df49d7eSJed Brown     ///
10699df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
10709df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
10719df49d7eSJed Brown     ///
10729df49d7eSJed Brown     /// ```
10739df49d7eSJed Brown     /// # use libceed::prelude::*;
10744d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
10759df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
10769df49d7eSJed Brown     /// let ne = 4;
10779df49d7eSJed Brown     /// let p = 3;
10789df49d7eSJed Brown     /// let q = 4;
10799df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
10809df49d7eSJed Brown     ///
10819df49d7eSJed Brown     /// // Vectors
1082c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1083c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
10849df49d7eSJed Brown     /// qdata.set_value(0.0);
1085c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
10869df49d7eSJed Brown     /// u.set_value(1.0);
1087c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
10889df49d7eSJed Brown     /// v.set_value(0.0);
10899df49d7eSJed Brown     ///
10909df49d7eSJed Brown     /// // Restrictions
10919df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
10929df49d7eSJed Brown     /// for i in 0..ne {
10939df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
10949df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
10959df49d7eSJed Brown     /// }
1096c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
10979df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
10989df49d7eSJed Brown     /// for i in 0..ne {
10999df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
11009df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
11019df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
11029df49d7eSJed Brown     /// }
1103c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?;
11049df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1105c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
11069df49d7eSJed Brown     ///
11079df49d7eSJed Brown     /// // Bases
1108c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1109c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
11109df49d7eSJed Brown     ///
11119df49d7eSJed Brown     /// // Build quadrature data
1112c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1113c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1114c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1115c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1116356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1117c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
11189df49d7eSJed Brown     ///
11199df49d7eSJed Brown     /// // Mass operator
1120c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
11219df49d7eSJed Brown     /// let op_mass = ceed
1122c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1123c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1124356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1125c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
11269df49d7eSJed Brown     ///
11279df49d7eSJed Brown     /// // Diagonal
1128c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ndofs)?;
11299df49d7eSJed Brown     /// diag.set_value(0.0);
1130c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_diagonal(&mut diag)?;
11319df49d7eSJed Brown     ///
11329df49d7eSJed Brown     /// // Manual diagonal computation
1133c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ndofs)?;
11349c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
11359df49d7eSJed Brown     /// for i in 0..ndofs {
11369df49d7eSJed Brown     ///     u.set_value(0.0);
11379df49d7eSJed Brown     ///     {
1138e78171edSJeremy L Thompson     ///         let mut u_array = u.view_mut()?;
11399df49d7eSJed Brown     ///         u_array[i] = 1.;
11409df49d7eSJed Brown     ///     }
11419df49d7eSJed Brown     ///
1142c68be7a2SJeremy L Thompson     ///     op_mass.apply(&u, &mut v)?;
11439df49d7eSJed Brown     ///
11449df49d7eSJed Brown     ///     {
11459c774eddSJeremy L Thompson     ///         let v_array = v.view()?;
1146e78171edSJeremy L Thompson     ///         let mut true_array = true_diag.view_mut()?;
11479df49d7eSJed Brown     ///         true_array[i] = v_array[i];
11489df49d7eSJed Brown     ///     }
11499df49d7eSJed Brown     /// }
11509df49d7eSJed Brown     ///
11519df49d7eSJed Brown     /// // Check
1152e78171edSJeremy L Thompson     /// diag.view()?
11539df49d7eSJed Brown     ///     .iter()
1154e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
11559df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
11569df49d7eSJed Brown     ///         assert!(
115780a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
11589df49d7eSJed Brown     ///             "Diagonal entry incorrect"
11599df49d7eSJed Brown     ///         );
11609df49d7eSJed Brown     ///     });
1161c68be7a2SJeremy L Thompson     /// # Ok(())
1162c68be7a2SJeremy L Thompson     /// # }
11639df49d7eSJed Brown     /// ```
11649df49d7eSJed Brown     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
11659df49d7eSJed Brown         self.op_core.linear_assemble_diagonal(assembled)
11669df49d7eSJed Brown     }
11679df49d7eSJed Brown 
11689df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
11699df49d7eSJed Brown     ///
11709df49d7eSJed Brown     /// This sums into a Vector with the diagonal of a linear Operator.
11719df49d7eSJed Brown     ///
11729df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
11739df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
11749df49d7eSJed Brown     ///
11759df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
11769df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
11779df49d7eSJed Brown     ///
11789df49d7eSJed Brown     ///
11799df49d7eSJed Brown     /// ```
11809df49d7eSJed Brown     /// # use libceed::prelude::*;
11814d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
11829df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
11839df49d7eSJed Brown     /// let ne = 4;
11849df49d7eSJed Brown     /// let p = 3;
11859df49d7eSJed Brown     /// let q = 4;
11869df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
11879df49d7eSJed Brown     ///
11889df49d7eSJed Brown     /// // Vectors
1189c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1190c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
11919df49d7eSJed Brown     /// qdata.set_value(0.0);
1192c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
11939df49d7eSJed Brown     /// u.set_value(1.0);
1194c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
11959df49d7eSJed Brown     /// v.set_value(0.0);
11969df49d7eSJed Brown     ///
11979df49d7eSJed Brown     /// // Restrictions
11989df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
11999df49d7eSJed Brown     /// for i in 0..ne {
12009df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
12019df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
12029df49d7eSJed Brown     /// }
1203c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
12049df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
12059df49d7eSJed Brown     /// for i in 0..ne {
12069df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
12079df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
12089df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
12099df49d7eSJed Brown     /// }
1210c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?;
12119df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1212c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
12139df49d7eSJed Brown     ///
12149df49d7eSJed Brown     /// // Bases
1215c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1216c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
12179df49d7eSJed Brown     ///
12189df49d7eSJed Brown     /// // Build quadrature data
1219c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1220c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1221c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1222c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1223356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1224c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
12259df49d7eSJed Brown     ///
12269df49d7eSJed Brown     /// // Mass operator
1227c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
12289df49d7eSJed Brown     /// let op_mass = ceed
1229c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1230c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1231356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1232c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
12339df49d7eSJed Brown     ///
12349df49d7eSJed Brown     /// // Diagonal
1235c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ndofs)?;
12369df49d7eSJed Brown     /// diag.set_value(1.0);
1237c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_add_diagonal(&mut diag)?;
12389df49d7eSJed Brown     ///
12399df49d7eSJed Brown     /// // Manual diagonal computation
1240c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ndofs)?;
12419c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
12429df49d7eSJed Brown     /// for i in 0..ndofs {
12439df49d7eSJed Brown     ///     u.set_value(0.0);
12449df49d7eSJed Brown     ///     {
1245e78171edSJeremy L Thompson     ///         let mut u_array = u.view_mut()?;
12469df49d7eSJed Brown     ///         u_array[i] = 1.;
12479df49d7eSJed Brown     ///     }
12489df49d7eSJed Brown     ///
1249c68be7a2SJeremy L Thompson     ///     op_mass.apply(&u, &mut v)?;
12509df49d7eSJed Brown     ///
12519df49d7eSJed Brown     ///     {
12529c774eddSJeremy L Thompson     ///         let v_array = v.view()?;
1253e78171edSJeremy L Thompson     ///         let mut true_array = true_diag.view_mut()?;
12549df49d7eSJed Brown     ///         true_array[i] = v_array[i] + 1.0;
12559df49d7eSJed Brown     ///     }
12569df49d7eSJed Brown     /// }
12579df49d7eSJed Brown     ///
12589df49d7eSJed Brown     /// // Check
1259e78171edSJeremy L Thompson     /// diag.view()?
12609df49d7eSJed Brown     ///     .iter()
1261e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
12629df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
12639df49d7eSJed Brown     ///         assert!(
126480a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
12659df49d7eSJed Brown     ///             "Diagonal entry incorrect"
12669df49d7eSJed Brown     ///         );
12679df49d7eSJed Brown     ///     });
1268c68be7a2SJeremy L Thompson     /// # Ok(())
1269c68be7a2SJeremy L Thompson     /// # }
12709df49d7eSJed Brown     /// ```
12719df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
12729df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
12739df49d7eSJed Brown     }
12749df49d7eSJed Brown 
12759df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
12769df49d7eSJed Brown     ///
12779df49d7eSJed Brown     /// This overwrites a Vector with the point block diagonal of a linear
12789df49d7eSJed Brown     /// Operator.
12799df49d7eSJed Brown     ///
12809df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
12819df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
12829df49d7eSJed Brown     ///
12839df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
12849df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
12859df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
12869df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
12879df49d7eSJed Brown     ///                   this vector are derived from the active vector for
12889df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
12899df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
12909df49d7eSJed Brown     ///
12919df49d7eSJed Brown     /// ```
12929df49d7eSJed Brown     /// # use libceed::prelude::*;
12934d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
12949df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
12959df49d7eSJed Brown     /// let ne = 4;
12969df49d7eSJed Brown     /// let p = 3;
12979df49d7eSJed Brown     /// let q = 4;
12989df49d7eSJed Brown     /// let ncomp = 2;
12999df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
13009df49d7eSJed Brown     ///
13019df49d7eSJed Brown     /// // Vectors
1302c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1303c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
13049df49d7eSJed Brown     /// qdata.set_value(0.0);
1305c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ncomp * ndofs)?;
13069df49d7eSJed Brown     /// u.set_value(1.0);
1307c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ncomp * ndofs)?;
13089df49d7eSJed Brown     /// v.set_value(0.0);
13099df49d7eSJed Brown     ///
13109df49d7eSJed Brown     /// // Restrictions
13119df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
13129df49d7eSJed Brown     /// for i in 0..ne {
13139df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
13149df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
13159df49d7eSJed Brown     /// }
1316c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
13179df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
13189df49d7eSJed Brown     /// for i in 0..ne {
13199df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
13209df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
13219df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
13229df49d7eSJed Brown     /// }
1323c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?;
13249df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1325c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
13269df49d7eSJed Brown     ///
13279df49d7eSJed Brown     /// // Bases
1328c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1329c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?;
13309df49d7eSJed Brown     ///
13319df49d7eSJed Brown     /// // Build quadrature data
1332c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1333c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1334c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1335c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1336356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1337c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
13389df49d7eSJed Brown     ///
13399df49d7eSJed Brown     /// // Mass operator
13409df49d7eSJed Brown     /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
13419df49d7eSJed Brown     ///     // Number of quadrature points
13429df49d7eSJed Brown     ///     let q = qdata.len();
13439df49d7eSJed Brown     ///
13449df49d7eSJed Brown     ///     // Iterate over quadrature points
13459df49d7eSJed Brown     ///     for i in 0..q {
13469df49d7eSJed Brown     ///         v[i + 0 * q] = u[i + 1 * q] * qdata[i];
13479df49d7eSJed Brown     ///         v[i + 1 * q] = u[i + 0 * q] * qdata[i];
13489df49d7eSJed Brown     ///     }
13499df49d7eSJed Brown     ///
13509df49d7eSJed Brown     ///     // Return clean error code
13519df49d7eSJed Brown     ///     0
13529df49d7eSJed Brown     /// };
13539df49d7eSJed Brown     ///
13549df49d7eSJed Brown     /// let qf_mass = ceed
1355c68be7a2SJeremy L Thompson     ///     .q_function_interior(1, Box::new(mass_2_comp))?
1356c68be7a2SJeremy L Thompson     ///     .input("u", 2, EvalMode::Interp)?
1357c68be7a2SJeremy L Thompson     ///     .input("qdata", 1, EvalMode::None)?
1358c68be7a2SJeremy L Thompson     ///     .output("v", 2, EvalMode::Interp)?;
13599df49d7eSJed Brown     ///
13609df49d7eSJed Brown     /// let op_mass = ceed
1361c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1362c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1363356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1364c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
13659df49d7eSJed Brown     ///
13669df49d7eSJed Brown     /// // Diagonal
1367c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?;
13689df49d7eSJed Brown     /// diag.set_value(0.0);
1369c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_point_block_diagonal(&mut diag)?;
13709df49d7eSJed Brown     ///
13719df49d7eSJed Brown     /// // Manual diagonal computation
1372c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?;
13739c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
13749df49d7eSJed Brown     /// for i in 0..ndofs {
13759df49d7eSJed Brown     ///     for j in 0..ncomp {
13769df49d7eSJed Brown     ///         u.set_value(0.0);
13779df49d7eSJed Brown     ///         {
1378e78171edSJeremy L Thompson     ///             let mut u_array = u.view_mut()?;
13799df49d7eSJed Brown     ///             u_array[i + j * ndofs] = 1.;
13809df49d7eSJed Brown     ///         }
13819df49d7eSJed Brown     ///
1382c68be7a2SJeremy L Thompson     ///         op_mass.apply(&u, &mut v)?;
13839df49d7eSJed Brown     ///
13849df49d7eSJed Brown     ///         {
13859c774eddSJeremy L Thompson     ///             let v_array = v.view()?;
1386e78171edSJeremy L Thompson     ///             let mut true_array = true_diag.view_mut()?;
13879df49d7eSJed Brown     ///             for k in 0..ncomp {
13889df49d7eSJed Brown     ///                 true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
13899df49d7eSJed Brown     ///             }
13909df49d7eSJed Brown     ///         }
13919df49d7eSJed Brown     ///     }
13929df49d7eSJed Brown     /// }
13939df49d7eSJed Brown     ///
13949df49d7eSJed Brown     /// // Check
1395e78171edSJeremy L Thompson     /// diag.view()?
13969df49d7eSJed Brown     ///     .iter()
1397e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
13989df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
13999df49d7eSJed Brown     ///         assert!(
140080a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
14019df49d7eSJed Brown     ///             "Diagonal entry incorrect"
14029df49d7eSJed Brown     ///         );
14039df49d7eSJed Brown     ///     });
1404c68be7a2SJeremy L Thompson     /// # Ok(())
1405c68be7a2SJeremy L Thompson     /// # }
14069df49d7eSJed Brown     /// ```
14079df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
14089df49d7eSJed Brown         &self,
14099df49d7eSJed Brown         assembled: &mut Vector,
14109df49d7eSJed Brown     ) -> crate::Result<i32> {
14119df49d7eSJed Brown         self.op_core.linear_assemble_point_block_diagonal(assembled)
14129df49d7eSJed Brown     }
14139df49d7eSJed Brown 
14149df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
14159df49d7eSJed Brown     ///
14169df49d7eSJed Brown     /// This sums into a Vector with the point block diagonal of a linear
14179df49d7eSJed Brown     /// Operator.
14189df49d7eSJed Brown     ///
14199df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
14209df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
14219df49d7eSJed Brown     ///
14229df49d7eSJed Brown     /// * `op`        -     Operator to assemble QFunction
14239df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
14249df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
14259df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
14269df49d7eSJed Brown     ///                   this vector are derived from the active vector for
14279df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
14289df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
14299df49d7eSJed Brown     ///
14309df49d7eSJed Brown     /// ```
14319df49d7eSJed Brown     /// # use libceed::prelude::*;
14324d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
14339df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
14349df49d7eSJed Brown     /// let ne = 4;
14359df49d7eSJed Brown     /// let p = 3;
14369df49d7eSJed Brown     /// let q = 4;
14379df49d7eSJed Brown     /// let ncomp = 2;
14389df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
14399df49d7eSJed Brown     ///
14409df49d7eSJed Brown     /// // Vectors
1441c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1442c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
14439df49d7eSJed Brown     /// qdata.set_value(0.0);
1444c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ncomp * ndofs)?;
14459df49d7eSJed Brown     /// u.set_value(1.0);
1446c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ncomp * ndofs)?;
14479df49d7eSJed Brown     /// v.set_value(0.0);
14489df49d7eSJed Brown     ///
14499df49d7eSJed Brown     /// // Restrictions
14509df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
14519df49d7eSJed Brown     /// for i in 0..ne {
14529df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
14539df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
14549df49d7eSJed Brown     /// }
1455c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
14569df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
14579df49d7eSJed Brown     /// for i in 0..ne {
14589df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
14599df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
14609df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
14619df49d7eSJed Brown     /// }
1462c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?;
14639df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1464c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
14659df49d7eSJed Brown     ///
14669df49d7eSJed Brown     /// // Bases
1467c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1468c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?;
14699df49d7eSJed Brown     ///
14709df49d7eSJed Brown     /// // Build quadrature data
1471c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1472c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1473c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1474c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1475356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1476c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
14779df49d7eSJed Brown     ///
14789df49d7eSJed Brown     /// // Mass operator
14799df49d7eSJed Brown     /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
14809df49d7eSJed Brown     ///     // Number of quadrature points
14819df49d7eSJed Brown     ///     let q = qdata.len();
14829df49d7eSJed Brown     ///
14839df49d7eSJed Brown     ///     // Iterate over quadrature points
14849df49d7eSJed Brown     ///     for i in 0..q {
14859df49d7eSJed Brown     ///         v[i + 0 * q] = u[i + 1 * q] * qdata[i];
14869df49d7eSJed Brown     ///         v[i + 1 * q] = u[i + 0 * q] * qdata[i];
14879df49d7eSJed Brown     ///     }
14889df49d7eSJed Brown     ///
14899df49d7eSJed Brown     ///     // Return clean error code
14909df49d7eSJed Brown     ///     0
14919df49d7eSJed Brown     /// };
14929df49d7eSJed Brown     ///
14939df49d7eSJed Brown     /// let qf_mass = ceed
1494c68be7a2SJeremy L Thompson     ///     .q_function_interior(1, Box::new(mass_2_comp))?
1495c68be7a2SJeremy L Thompson     ///     .input("u", 2, EvalMode::Interp)?
1496c68be7a2SJeremy L Thompson     ///     .input("qdata", 1, EvalMode::None)?
1497c68be7a2SJeremy L Thompson     ///     .output("v", 2, EvalMode::Interp)?;
14989df49d7eSJed Brown     ///
14999df49d7eSJed Brown     /// let op_mass = ceed
1500c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1501c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1502356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1503c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
15049df49d7eSJed Brown     ///
15059df49d7eSJed Brown     /// // Diagonal
1506c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?;
15079df49d7eSJed Brown     /// diag.set_value(1.0);
1508c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_add_point_block_diagonal(&mut diag)?;
15099df49d7eSJed Brown     ///
15109df49d7eSJed Brown     /// // Manual diagonal computation
1511c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?;
15129c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
15139df49d7eSJed Brown     /// for i in 0..ndofs {
15149df49d7eSJed Brown     ///     for j in 0..ncomp {
15159df49d7eSJed Brown     ///         u.set_value(0.0);
15169df49d7eSJed Brown     ///         {
1517e78171edSJeremy L Thompson     ///             let mut u_array = u.view_mut()?;
15189df49d7eSJed Brown     ///             u_array[i + j * ndofs] = 1.;
15199df49d7eSJed Brown     ///         }
15209df49d7eSJed Brown     ///
1521c68be7a2SJeremy L Thompson     ///         op_mass.apply(&u, &mut v)?;
15229df49d7eSJed Brown     ///
15239df49d7eSJed Brown     ///         {
15249c774eddSJeremy L Thompson     ///             let v_array = v.view()?;
1525e78171edSJeremy L Thompson     ///             let mut true_array = true_diag.view_mut()?;
15269df49d7eSJed Brown     ///             for k in 0..ncomp {
15279df49d7eSJed Brown     ///                 true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
15289df49d7eSJed Brown     ///             }
15299df49d7eSJed Brown     ///         }
15309df49d7eSJed Brown     ///     }
15319df49d7eSJed Brown     /// }
15329df49d7eSJed Brown     ///
15339df49d7eSJed Brown     /// // Check
1534e78171edSJeremy L Thompson     /// diag.view()?
15359df49d7eSJed Brown     ///     .iter()
1536e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
15379df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
15389df49d7eSJed Brown     ///         assert!(
153980a9ef05SNatalie Beams     ///             (*computed - 1.0 - *actual).abs() < 10.0 * libceed::EPSILON,
15409df49d7eSJed Brown     ///             "Diagonal entry incorrect"
15419df49d7eSJed Brown     ///         );
15429df49d7eSJed Brown     ///     });
1543c68be7a2SJeremy L Thompson     /// # Ok(())
1544c68be7a2SJeremy L Thompson     /// # }
15459df49d7eSJed Brown     /// ```
15469df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
15479df49d7eSJed Brown         &self,
15489df49d7eSJed Brown         assembled: &mut Vector,
15499df49d7eSJed Brown     ) -> crate::Result<i32> {
15509df49d7eSJed Brown         self.op_core
15519df49d7eSJed Brown             .linear_assemble_add_point_block_diagonal(assembled)
15529df49d7eSJed Brown     }
15539df49d7eSJed Brown 
15549df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
15559df49d7eSJed Brown     ///   given Operator, creating the prolongation basis from the fine and
15569df49d7eSJed Brown     ///   coarse grid interpolation
15579df49d7eSJed Brown     ///
15589df49d7eSJed Brown     /// * `p_mult_fine`  - Lvector multiplicity in parallel gather/scatter
15599df49d7eSJed Brown     /// * `rstr_coarse`  - Coarse grid restriction
15609df49d7eSJed Brown     /// * `basis_coarse` - Coarse grid active vector basis
15619df49d7eSJed Brown     ///
15629df49d7eSJed Brown     /// ```
15639df49d7eSJed Brown     /// # use libceed::prelude::*;
15644d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
15659df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
15669df49d7eSJed Brown     /// let ne = 15;
15679df49d7eSJed Brown     /// let p_coarse = 3;
15689df49d7eSJed Brown     /// let p_fine = 5;
15699df49d7eSJed Brown     /// let q = 6;
15709df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
15719df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
15729df49d7eSJed Brown     ///
15739df49d7eSJed Brown     /// // Vectors
15749df49d7eSJed Brown     /// let x_array = (0..ne + 1)
157580a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
157680a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1577c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1578c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
15799df49d7eSJed Brown     /// qdata.set_value(0.0);
1580c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
15819df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1582c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
15839df49d7eSJed Brown     /// u_fine.set_value(1.0);
1584c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
15859df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1586c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
15879df49d7eSJed Brown     /// v_fine.set_value(0.0);
1588c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
15899df49d7eSJed Brown     /// multiplicity.set_value(1.0);
15909df49d7eSJed Brown     ///
15919df49d7eSJed Brown     /// // Restrictions
15929df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1593c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
15949df49d7eSJed Brown     ///
15959df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
15969df49d7eSJed Brown     /// for i in 0..ne {
15979df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
15989df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
15999df49d7eSJed Brown     /// }
1600c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
16019df49d7eSJed Brown     ///
16029df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
16039df49d7eSJed Brown     /// for i in 0..ne {
16049df49d7eSJed Brown     ///     for j in 0..p_coarse {
16059df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
16069df49d7eSJed Brown     ///     }
16079df49d7eSJed Brown     /// }
1608c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
16099df49d7eSJed Brown     ///     ne,
16109df49d7eSJed Brown     ///     p_coarse,
16119df49d7eSJed Brown     ///     1,
16129df49d7eSJed Brown     ///     1,
16139df49d7eSJed Brown     ///     ndofs_coarse,
16149df49d7eSJed Brown     ///     MemType::Host,
16159df49d7eSJed Brown     ///     &indu_coarse,
1616c68be7a2SJeremy L Thompson     /// )?;
16179df49d7eSJed Brown     ///
16189df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
16199df49d7eSJed Brown     /// for i in 0..ne {
16209df49d7eSJed Brown     ///     for j in 0..p_fine {
16219df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
16229df49d7eSJed Brown     ///     }
16239df49d7eSJed Brown     /// }
1624c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
16259df49d7eSJed Brown     ///
16269df49d7eSJed Brown     /// // Bases
1627c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1628c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1629c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
16309df49d7eSJed Brown     ///
16319df49d7eSJed Brown     /// // Build quadrature data
1632c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1633c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1634c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1635c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1636356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1637c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
16389df49d7eSJed Brown     ///
16399df49d7eSJed Brown     /// // Mass operator
1640c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
16419df49d7eSJed Brown     /// let op_mass_fine = ceed
1642c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1643c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
1644356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1645c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
16469df49d7eSJed Brown     ///
16479df49d7eSJed Brown     /// // Multigrid setup
1648c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) =
1649c68be7a2SJeremy L Thompson     ///     op_mass_fine.create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)?;
16509df49d7eSJed Brown     ///
16519df49d7eSJed Brown     /// // Coarse problem
16529df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1653c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
16549df49d7eSJed Brown     ///
16559df49d7eSJed Brown     /// // Check
1656e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
16579df49d7eSJed Brown     /// assert!(
165880a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 50.0 * libceed::EPSILON,
16599df49d7eSJed Brown     ///     "Incorrect interval length computed"
16609df49d7eSJed Brown     /// );
16619df49d7eSJed Brown     ///
16629df49d7eSJed Brown     /// // Prolong
1663c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
16649df49d7eSJed Brown     ///
16659df49d7eSJed Brown     /// // Fine problem
1666c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
16679df49d7eSJed Brown     ///
16689df49d7eSJed Brown     /// // Check
1669e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
16709df49d7eSJed Brown     /// assert!(
1671392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
16729df49d7eSJed Brown     ///     "Incorrect interval length computed"
16739df49d7eSJed Brown     /// );
16749df49d7eSJed Brown     ///
16759df49d7eSJed Brown     /// // Restrict
1676c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
16779df49d7eSJed Brown     ///
16789df49d7eSJed Brown     /// // Check
1679e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
16809df49d7eSJed Brown     /// assert!(
1681392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
16829df49d7eSJed Brown     ///     "Incorrect interval length computed"
16839df49d7eSJed Brown     /// );
1684c68be7a2SJeremy L Thompson     /// # Ok(())
1685c68be7a2SJeremy L Thompson     /// # }
16869df49d7eSJed Brown     /// ```
1687594ef120SJeremy L Thompson     pub fn create_multigrid_level<'b>(
16889df49d7eSJed Brown         &self,
16899df49d7eSJed Brown         p_mult_fine: &Vector,
16909df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
16919df49d7eSJed Brown         basis_coarse: &Basis,
1692594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
16939df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
16949df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
16959df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
16969df49d7eSJed Brown         let ierr = unsafe {
16979df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreate(
16989df49d7eSJed Brown                 self.op_core.ptr,
16999df49d7eSJed Brown                 p_mult_fine.ptr,
17009df49d7eSJed Brown                 rstr_coarse.ptr,
17019df49d7eSJed Brown                 basis_coarse.ptr,
17029df49d7eSJed Brown                 &mut ptr_coarse,
17039df49d7eSJed Brown                 &mut ptr_prolong,
17049df49d7eSJed Brown                 &mut ptr_restrict,
17059df49d7eSJed Brown             )
17069df49d7eSJed Brown         };
17071142270cSJeremy L Thompson         self.op_core.check_error(ierr)?;
17081142270cSJeremy L Thompson         let op_coarse = Operator::from_raw(ptr_coarse)?;
17091142270cSJeremy L Thompson         let op_prolong = Operator::from_raw(ptr_prolong)?;
17101142270cSJeremy L Thompson         let op_restrict = Operator::from_raw(ptr_restrict)?;
17119df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
17129df49d7eSJed Brown     }
17139df49d7eSJed Brown 
17149df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
17159df49d7eSJed Brown     ///   given Operator with a tensor basis for the active basis
17169df49d7eSJed Brown     ///
17179df49d7eSJed Brown     /// * `p_mult_fine`   - Lvector multiplicity in parallel gather/scatter
17189df49d7eSJed Brown     /// * `rstr_coarse`   - Coarse grid restriction
17199df49d7eSJed Brown     /// * `basis_coarse`  - Coarse grid active vector basis
17209df49d7eSJed Brown     /// * `interp_c_to_f` - Matrix for coarse to fine
17219df49d7eSJed Brown     ///
17229df49d7eSJed Brown     /// ```
17239df49d7eSJed Brown     /// # use libceed::prelude::*;
17244d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
17259df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
17269df49d7eSJed Brown     /// let ne = 15;
17279df49d7eSJed Brown     /// let p_coarse = 3;
17289df49d7eSJed Brown     /// let p_fine = 5;
17299df49d7eSJed Brown     /// let q = 6;
17309df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
17319df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
17329df49d7eSJed Brown     ///
17339df49d7eSJed Brown     /// // Vectors
17349df49d7eSJed Brown     /// let x_array = (0..ne + 1)
173580a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
173680a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1737c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1738c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
17399df49d7eSJed Brown     /// qdata.set_value(0.0);
1740c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
17419df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1742c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
17439df49d7eSJed Brown     /// u_fine.set_value(1.0);
1744c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
17459df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1746c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
17479df49d7eSJed Brown     /// v_fine.set_value(0.0);
1748c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
17499df49d7eSJed Brown     /// multiplicity.set_value(1.0);
17509df49d7eSJed Brown     ///
17519df49d7eSJed Brown     /// // Restrictions
17529df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1753c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
17549df49d7eSJed Brown     ///
17559df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
17569df49d7eSJed Brown     /// for i in 0..ne {
17579df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
17589df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
17599df49d7eSJed Brown     /// }
1760c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
17619df49d7eSJed Brown     ///
17629df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
17639df49d7eSJed Brown     /// for i in 0..ne {
17649df49d7eSJed Brown     ///     for j in 0..p_coarse {
17659df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
17669df49d7eSJed Brown     ///     }
17679df49d7eSJed Brown     /// }
1768c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
17699df49d7eSJed Brown     ///     ne,
17709df49d7eSJed Brown     ///     p_coarse,
17719df49d7eSJed Brown     ///     1,
17729df49d7eSJed Brown     ///     1,
17739df49d7eSJed Brown     ///     ndofs_coarse,
17749df49d7eSJed Brown     ///     MemType::Host,
17759df49d7eSJed Brown     ///     &indu_coarse,
1776c68be7a2SJeremy L Thompson     /// )?;
17779df49d7eSJed Brown     ///
17789df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
17799df49d7eSJed Brown     /// for i in 0..ne {
17809df49d7eSJed Brown     ///     for j in 0..p_fine {
17819df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
17829df49d7eSJed Brown     ///     }
17839df49d7eSJed Brown     /// }
1784c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
17859df49d7eSJed Brown     ///
17869df49d7eSJed Brown     /// // Bases
1787c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1788c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1789c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
17909df49d7eSJed Brown     ///
17919df49d7eSJed Brown     /// // Build quadrature data
1792c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1793c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1794c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1795c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1796356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1797c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
17989df49d7eSJed Brown     ///
17999df49d7eSJed Brown     /// // Mass operator
1800c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
18019df49d7eSJed Brown     /// let op_mass_fine = ceed
1802c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1803c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
1804356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1805c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
18069df49d7eSJed Brown     ///
18079df49d7eSJed Brown     /// // Multigrid setup
180880a9ef05SNatalie Beams     /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine];
18099df49d7eSJed Brown     /// {
1810c68be7a2SJeremy L Thompson     ///     let mut coarse = ceed.vector(p_coarse)?;
1811c68be7a2SJeremy L Thompson     ///     let mut fine = ceed.vector(p_fine)?;
1812c68be7a2SJeremy L Thompson     ///     let basis_c_to_f =
1813c68be7a2SJeremy L Thompson     ///         ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?;
18149df49d7eSJed Brown     ///     for i in 0..p_coarse {
18159df49d7eSJed Brown     ///         coarse.set_value(0.0);
18169df49d7eSJed Brown     ///         {
1817e78171edSJeremy L Thompson     ///             let mut array = coarse.view_mut()?;
18189df49d7eSJed Brown     ///             array[i] = 1.;
18199df49d7eSJed Brown     ///         }
1820c68be7a2SJeremy L Thompson     ///         basis_c_to_f.apply(
18219df49d7eSJed Brown     ///             1,
18229df49d7eSJed Brown     ///             TransposeMode::NoTranspose,
18239df49d7eSJed Brown     ///             EvalMode::Interp,
18249df49d7eSJed Brown     ///             &coarse,
18259df49d7eSJed Brown     ///             &mut fine,
1826c68be7a2SJeremy L Thompson     ///         )?;
1827e78171edSJeremy L Thompson     ///         let array = fine.view()?;
18289df49d7eSJed Brown     ///         for j in 0..p_fine {
18299df49d7eSJed Brown     ///             interp_c_to_f[j * p_coarse + i] = array[j];
18309df49d7eSJed Brown     ///         }
18319df49d7eSJed Brown     ///     }
18329df49d7eSJed Brown     /// }
1833c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_tensor_H1(
1834c68be7a2SJeremy L Thompson     ///     &multiplicity,
1835c68be7a2SJeremy L Thompson     ///     &ru_coarse,
1836c68be7a2SJeremy L Thompson     ///     &bu_coarse,
1837c68be7a2SJeremy L Thompson     ///     &interp_c_to_f,
1838c68be7a2SJeremy L Thompson     /// )?;
18399df49d7eSJed Brown     ///
18409df49d7eSJed Brown     /// // Coarse problem
18419df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1842c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
18439df49d7eSJed Brown     ///
18449df49d7eSJed Brown     /// // Check
1845e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
18469df49d7eSJed Brown     /// assert!(
184780a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
18489df49d7eSJed Brown     ///     "Incorrect interval length computed"
18499df49d7eSJed Brown     /// );
18509df49d7eSJed Brown     ///
18519df49d7eSJed Brown     /// // Prolong
1852c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
18539df49d7eSJed Brown     ///
18549df49d7eSJed Brown     /// // Fine problem
1855c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
18569df49d7eSJed Brown     ///
18579df49d7eSJed Brown     /// // Check
1858e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
18599df49d7eSJed Brown     /// assert!(
1860392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
18619df49d7eSJed Brown     ///     "Incorrect interval length computed"
18629df49d7eSJed Brown     /// );
18639df49d7eSJed Brown     ///
18649df49d7eSJed Brown     /// // Restrict
1865c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
18669df49d7eSJed Brown     ///
18679df49d7eSJed Brown     /// // Check
1868e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
18699df49d7eSJed Brown     /// assert!(
1870392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
18719df49d7eSJed Brown     ///     "Incorrect interval length computed"
18729df49d7eSJed Brown     /// );
1873c68be7a2SJeremy L Thompson     /// # Ok(())
1874c68be7a2SJeremy L Thompson     /// # }
18759df49d7eSJed Brown     /// ```
1876594ef120SJeremy L Thompson     pub fn create_multigrid_level_tensor_H1<'b>(
18779df49d7eSJed Brown         &self,
18789df49d7eSJed Brown         p_mult_fine: &Vector,
18799df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
18809df49d7eSJed Brown         basis_coarse: &Basis,
188180a9ef05SNatalie Beams         interpCtoF: &Vec<Scalar>,
1882594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
18839df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
18849df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
18859df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
18869df49d7eSJed Brown         let ierr = unsafe {
18879df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreateTensorH1(
18889df49d7eSJed Brown                 self.op_core.ptr,
18899df49d7eSJed Brown                 p_mult_fine.ptr,
18909df49d7eSJed Brown                 rstr_coarse.ptr,
18919df49d7eSJed Brown                 basis_coarse.ptr,
18929df49d7eSJed Brown                 interpCtoF.as_ptr(),
18939df49d7eSJed Brown                 &mut ptr_coarse,
18949df49d7eSJed Brown                 &mut ptr_prolong,
18959df49d7eSJed Brown                 &mut ptr_restrict,
18969df49d7eSJed Brown             )
18979df49d7eSJed Brown         };
18981142270cSJeremy L Thompson         self.op_core.check_error(ierr)?;
18991142270cSJeremy L Thompson         let op_coarse = Operator::from_raw(ptr_coarse)?;
19001142270cSJeremy L Thompson         let op_prolong = Operator::from_raw(ptr_prolong)?;
19011142270cSJeremy L Thompson         let op_restrict = Operator::from_raw(ptr_restrict)?;
19029df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
19039df49d7eSJed Brown     }
19049df49d7eSJed Brown 
19059df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
19069df49d7eSJed Brown     ///   given Operator with a non-tensor basis for the active basis
19079df49d7eSJed Brown     ///
19089df49d7eSJed Brown     /// * `p_mult_fine`   - Lvector multiplicity in parallel gather/scatter
19099df49d7eSJed Brown     /// * `rstr_coarse`   - Coarse grid restriction
19109df49d7eSJed Brown     /// * `basis_coarse`  - Coarse grid active vector basis
19119df49d7eSJed Brown     /// * `interp_c_to_f` - Matrix for coarse to fine
19129df49d7eSJed Brown     ///
19139df49d7eSJed Brown     /// ```
19149df49d7eSJed Brown     /// # use libceed::prelude::*;
19154d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
19169df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
19179df49d7eSJed Brown     /// let ne = 15;
19189df49d7eSJed Brown     /// let p_coarse = 3;
19199df49d7eSJed Brown     /// let p_fine = 5;
19209df49d7eSJed Brown     /// let q = 6;
19219df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
19229df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
19239df49d7eSJed Brown     ///
19249df49d7eSJed Brown     /// // Vectors
19259df49d7eSJed Brown     /// let x_array = (0..ne + 1)
192680a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
192780a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1928c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1929c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
19309df49d7eSJed Brown     /// qdata.set_value(0.0);
1931c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
19329df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1933c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
19349df49d7eSJed Brown     /// u_fine.set_value(1.0);
1935c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
19369df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1937c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
19389df49d7eSJed Brown     /// v_fine.set_value(0.0);
1939c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
19409df49d7eSJed Brown     /// multiplicity.set_value(1.0);
19419df49d7eSJed Brown     ///
19429df49d7eSJed Brown     /// // Restrictions
19439df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1944c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
19459df49d7eSJed Brown     ///
19469df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
19479df49d7eSJed Brown     /// for i in 0..ne {
19489df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
19499df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
19509df49d7eSJed Brown     /// }
1951c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
19529df49d7eSJed Brown     ///
19539df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
19549df49d7eSJed Brown     /// for i in 0..ne {
19559df49d7eSJed Brown     ///     for j in 0..p_coarse {
19569df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
19579df49d7eSJed Brown     ///     }
19589df49d7eSJed Brown     /// }
1959c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
19609df49d7eSJed Brown     ///     ne,
19619df49d7eSJed Brown     ///     p_coarse,
19629df49d7eSJed Brown     ///     1,
19639df49d7eSJed Brown     ///     1,
19649df49d7eSJed Brown     ///     ndofs_coarse,
19659df49d7eSJed Brown     ///     MemType::Host,
19669df49d7eSJed Brown     ///     &indu_coarse,
1967c68be7a2SJeremy L Thompson     /// )?;
19689df49d7eSJed Brown     ///
19699df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
19709df49d7eSJed Brown     /// for i in 0..ne {
19719df49d7eSJed Brown     ///     for j in 0..p_fine {
19729df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
19739df49d7eSJed Brown     ///     }
19749df49d7eSJed Brown     /// }
1975c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
19769df49d7eSJed Brown     ///
19779df49d7eSJed Brown     /// // Bases
1978c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1979c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1980c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
19819df49d7eSJed Brown     ///
19829df49d7eSJed Brown     /// // Build quadrature data
1983c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1984c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1985c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1986c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1987356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1988c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
19899df49d7eSJed Brown     ///
19909df49d7eSJed Brown     /// // Mass operator
1991c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
19929df49d7eSJed Brown     /// let op_mass_fine = ceed
1993c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1994c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
1995356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1996c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
19979df49d7eSJed Brown     ///
19989df49d7eSJed Brown     /// // Multigrid setup
199980a9ef05SNatalie Beams     /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine];
20009df49d7eSJed Brown     /// {
2001c68be7a2SJeremy L Thompson     ///     let mut coarse = ceed.vector(p_coarse)?;
2002c68be7a2SJeremy L Thompson     ///     let mut fine = ceed.vector(p_fine)?;
2003c68be7a2SJeremy L Thompson     ///     let basis_c_to_f =
2004c68be7a2SJeremy L Thompson     ///         ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?;
20059df49d7eSJed Brown     ///     for i in 0..p_coarse {
20069df49d7eSJed Brown     ///         coarse.set_value(0.0);
20079df49d7eSJed Brown     ///         {
2008e78171edSJeremy L Thompson     ///             let mut array = coarse.view_mut()?;
20099df49d7eSJed Brown     ///             array[i] = 1.;
20109df49d7eSJed Brown     ///         }
2011c68be7a2SJeremy L Thompson     ///         basis_c_to_f.apply(
20129df49d7eSJed Brown     ///             1,
20139df49d7eSJed Brown     ///             TransposeMode::NoTranspose,
20149df49d7eSJed Brown     ///             EvalMode::Interp,
20159df49d7eSJed Brown     ///             &coarse,
20169df49d7eSJed Brown     ///             &mut fine,
2017c68be7a2SJeremy L Thompson     ///         )?;
2018e78171edSJeremy L Thompson     ///         let array = fine.view()?;
20199df49d7eSJed Brown     ///         for j in 0..p_fine {
20209df49d7eSJed Brown     ///             interp_c_to_f[j * p_coarse + i] = array[j];
20219df49d7eSJed Brown     ///         }
20229df49d7eSJed Brown     ///     }
20239df49d7eSJed Brown     /// }
2024c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_H1(
2025c68be7a2SJeremy L Thompson     ///     &multiplicity,
2026c68be7a2SJeremy L Thompson     ///     &ru_coarse,
2027c68be7a2SJeremy L Thompson     ///     &bu_coarse,
2028c68be7a2SJeremy L Thompson     ///     &interp_c_to_f,
2029c68be7a2SJeremy L Thompson     /// )?;
20309df49d7eSJed Brown     ///
20319df49d7eSJed Brown     /// // Coarse problem
20329df49d7eSJed Brown     /// u_coarse.set_value(1.0);
2033c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
20349df49d7eSJed Brown     ///
20359df49d7eSJed Brown     /// // Check
2036e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
20379df49d7eSJed Brown     /// assert!(
203880a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
20399df49d7eSJed Brown     ///     "Incorrect interval length computed"
20409df49d7eSJed Brown     /// );
20419df49d7eSJed Brown     ///
20429df49d7eSJed Brown     /// // Prolong
2043c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
20449df49d7eSJed Brown     ///
20459df49d7eSJed Brown     /// // Fine problem
2046c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
20479df49d7eSJed Brown     ///
20489df49d7eSJed Brown     /// // Check
2049e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
20509df49d7eSJed Brown     /// assert!(
2051392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
20529df49d7eSJed Brown     ///     "Incorrect interval length computed"
20539df49d7eSJed Brown     /// );
20549df49d7eSJed Brown     ///
20559df49d7eSJed Brown     /// // Restrict
2056c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
20579df49d7eSJed Brown     ///
20589df49d7eSJed Brown     /// // Check
2059e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
20609df49d7eSJed Brown     /// assert!(
2061392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
20629df49d7eSJed Brown     ///     "Incorrect interval length computed"
20639df49d7eSJed Brown     /// );
2064c68be7a2SJeremy L Thompson     /// # Ok(())
2065c68be7a2SJeremy L Thompson     /// # }
20669df49d7eSJed Brown     /// ```
2067594ef120SJeremy L Thompson     pub fn create_multigrid_level_H1<'b>(
20689df49d7eSJed Brown         &self,
20699df49d7eSJed Brown         p_mult_fine: &Vector,
20709df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
20719df49d7eSJed Brown         basis_coarse: &Basis,
207280a9ef05SNatalie Beams         interpCtoF: &[Scalar],
2073594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
20749df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
20759df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
20769df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
20779df49d7eSJed Brown         let ierr = unsafe {
20789df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreateH1(
20799df49d7eSJed Brown                 self.op_core.ptr,
20809df49d7eSJed Brown                 p_mult_fine.ptr,
20819df49d7eSJed Brown                 rstr_coarse.ptr,
20829df49d7eSJed Brown                 basis_coarse.ptr,
20839df49d7eSJed Brown                 interpCtoF.as_ptr(),
20849df49d7eSJed Brown                 &mut ptr_coarse,
20859df49d7eSJed Brown                 &mut ptr_prolong,
20869df49d7eSJed Brown                 &mut ptr_restrict,
20879df49d7eSJed Brown             )
20889df49d7eSJed Brown         };
20891142270cSJeremy L Thompson         self.op_core.check_error(ierr)?;
20901142270cSJeremy L Thompson         let op_coarse = Operator::from_raw(ptr_coarse)?;
20911142270cSJeremy L Thompson         let op_prolong = Operator::from_raw(ptr_prolong)?;
20921142270cSJeremy L Thompson         let op_restrict = Operator::from_raw(ptr_restrict)?;
20939df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
20949df49d7eSJed Brown     }
20959df49d7eSJed Brown }
20969df49d7eSJed Brown 
20979df49d7eSJed Brown // -----------------------------------------------------------------------------
20989df49d7eSJed Brown // Composite Operator
20999df49d7eSJed Brown // -----------------------------------------------------------------------------
21009df49d7eSJed Brown impl<'a> CompositeOperator<'a> {
21019df49d7eSJed Brown     // Constructor
2102594ef120SJeremy L Thompson     pub fn create(ceed: &crate::Ceed) -> crate::Result<Self> {
21039df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
21049df49d7eSJed Brown         let ierr = unsafe { bind_ceed::CeedCompositeOperatorCreate(ceed.ptr, &mut ptr) };
21059df49d7eSJed Brown         ceed.check_error(ierr)?;
21069df49d7eSJed Brown         Ok(Self {
21071142270cSJeremy L Thompson             op_core: OperatorCore {
21081142270cSJeremy L Thompson                 ptr,
21091142270cSJeremy L Thompson                 _lifeline: PhantomData,
21101142270cSJeremy L Thompson             },
21119df49d7eSJed Brown         })
21129df49d7eSJed Brown     }
21139df49d7eSJed Brown 
2114ea6b5821SJeremy L Thompson     /// Set name for CompositeOperator printing
2115ea6b5821SJeremy L Thompson     ///
2116ea6b5821SJeremy L Thompson     /// * 'name' - Name to set
2117ea6b5821SJeremy L Thompson     ///
2118ea6b5821SJeremy L Thompson     /// ```
2119ea6b5821SJeremy L Thompson     /// # use libceed::prelude::*;
2120ea6b5821SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
2121ea6b5821SJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
2122ea6b5821SJeremy L Thompson     ///
2123ea6b5821SJeremy L Thompson     /// // Sub operator field arguments
2124ea6b5821SJeremy L Thompson     /// let ne = 3;
2125ea6b5821SJeremy L Thompson     /// let q = 4 as usize;
2126ea6b5821SJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
2127ea6b5821SJeremy L Thompson     /// for i in 0..ne {
2128ea6b5821SJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
2129ea6b5821SJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
2130ea6b5821SJeremy L Thompson     /// }
2131ea6b5821SJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
2132ea6b5821SJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2133d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
2134ea6b5821SJeremy L Thompson     ///
2135ea6b5821SJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2136ea6b5821SJeremy L Thompson     ///
2137ea6b5821SJeremy L Thompson     /// let qdata_mass = ceed.vector(q * ne)?;
2138ea6b5821SJeremy L Thompson     /// let qdata_diff = ceed.vector(q * ne)?;
2139ea6b5821SJeremy L Thompson     ///
2140ea6b5821SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
2141ea6b5821SJeremy L Thompson     /// let op_mass = ceed
2142ea6b5821SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2143ea6b5821SJeremy L Thompson     ///     .name("Mass term")?
2144ea6b5821SJeremy L Thompson     ///     .field("u", &r, &b, VectorOpt::Active)?
2145356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2146ea6b5821SJeremy L Thompson     ///     .field("v", &r, &b, VectorOpt::Active)?;
2147ea6b5821SJeremy L Thompson     ///
2148ea6b5821SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
2149ea6b5821SJeremy L Thompson     /// let op_diff = ceed
2150ea6b5821SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2151ea6b5821SJeremy L Thompson     ///     .name("Poisson term")?
2152ea6b5821SJeremy L Thompson     ///     .field("du", &r, &b, VectorOpt::Active)?
2153356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2154ea6b5821SJeremy L Thompson     ///     .field("dv", &r, &b, VectorOpt::Active)?;
2155ea6b5821SJeremy L Thompson     ///
2156ea6b5821SJeremy L Thompson     /// let op = ceed
2157ea6b5821SJeremy L Thompson     ///     .composite_operator()?
2158ea6b5821SJeremy L Thompson     ///     .name("Screened Poisson")?
2159ea6b5821SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2160ea6b5821SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
2161ea6b5821SJeremy L Thompson     /// # Ok(())
2162ea6b5821SJeremy L Thompson     /// # }
2163ea6b5821SJeremy L Thompson     /// ```
2164ea6b5821SJeremy L Thompson     #[allow(unused_mut)]
2165ea6b5821SJeremy L Thompson     pub fn name(mut self, name: &str) -> crate::Result<Self> {
2166ea6b5821SJeremy L Thompson         self.op_core.name(name)?;
2167ea6b5821SJeremy L Thompson         Ok(self)
2168ea6b5821SJeremy L Thompson     }
2169ea6b5821SJeremy L Thompson 
21709df49d7eSJed Brown     /// Apply Operator to a vector
21719df49d7eSJed Brown     ///
2172ea6b5821SJeremy L Thompson     /// * `input`  - Inpuht Vector
21739df49d7eSJed Brown     /// * `output` - Output Vector
21749df49d7eSJed Brown     ///
21759df49d7eSJed Brown     /// ```
21769df49d7eSJed Brown     /// # use libceed::prelude::*;
21774d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
21789df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
21799df49d7eSJed Brown     /// let ne = 4;
21809df49d7eSJed Brown     /// let p = 3;
21819df49d7eSJed Brown     /// let q = 4;
21829df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
21839df49d7eSJed Brown     ///
21849df49d7eSJed Brown     /// // Vectors
2185c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
2186c68be7a2SJeremy L Thompson     /// let mut qdata_mass = ceed.vector(ne * q)?;
21879df49d7eSJed Brown     /// qdata_mass.set_value(0.0);
2188c68be7a2SJeremy L Thompson     /// let mut qdata_diff = ceed.vector(ne * q)?;
21899df49d7eSJed Brown     /// qdata_diff.set_value(0.0);
2190c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
21919df49d7eSJed Brown     /// u.set_value(1.0);
2192c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
21939df49d7eSJed Brown     /// v.set_value(0.0);
21949df49d7eSJed Brown     ///
21959df49d7eSJed Brown     /// // Restrictions
21969df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
21979df49d7eSJed Brown     /// for i in 0..ne {
21989df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
21999df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
22009df49d7eSJed Brown     /// }
2201c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
22029df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
22039df49d7eSJed Brown     /// for i in 0..ne {
22049df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
22059df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
22069df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
22079df49d7eSJed Brown     /// }
2208c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
22099df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2210c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
22119df49d7eSJed Brown     ///
22129df49d7eSJed Brown     /// // Bases
2213c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2214c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
22159df49d7eSJed Brown     ///
22169df49d7eSJed Brown     /// // Build quadrature data
2217c68be7a2SJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
2218c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
2219c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2220c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2221356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2222c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_mass)?;
22239df49d7eSJed Brown     ///
2224c68be7a2SJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
2225c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
2226c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2227c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2228356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2229c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_diff)?;
22309df49d7eSJed Brown     ///
22319df49d7eSJed Brown     /// // Application operator
2232c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
22339df49d7eSJed Brown     /// let op_mass = ceed
2234c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2235c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
2236356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2237c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
22389df49d7eSJed Brown     ///
2239c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
22409df49d7eSJed Brown     /// let op_diff = ceed
2241c68be7a2SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2242c68be7a2SJeremy L Thompson     ///     .field("du", &ru, &bu, VectorOpt::Active)?
2243356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2244c68be7a2SJeremy L Thompson     ///     .field("dv", &ru, &bu, VectorOpt::Active)?;
22459df49d7eSJed Brown     ///
22469df49d7eSJed Brown     /// let op_composite = ceed
2247c68be7a2SJeremy L Thompson     ///     .composite_operator()?
2248c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2249c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
22509df49d7eSJed Brown     ///
22519df49d7eSJed Brown     /// v.set_value(0.0);
2252c68be7a2SJeremy L Thompson     /// op_composite.apply(&u, &mut v)?;
22539df49d7eSJed Brown     ///
22549df49d7eSJed Brown     /// // Check
2255e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
22569df49d7eSJed Brown     /// assert!(
225780a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
22589df49d7eSJed Brown     ///     "Incorrect interval length computed"
22599df49d7eSJed Brown     /// );
2260c68be7a2SJeremy L Thompson     /// # Ok(())
2261c68be7a2SJeremy L Thompson     /// # }
22629df49d7eSJed Brown     /// ```
22639df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
22649df49d7eSJed Brown         self.op_core.apply(input, output)
22659df49d7eSJed Brown     }
22669df49d7eSJed Brown 
22679df49d7eSJed Brown     /// Apply Operator to a vector and add result to output vector
22689df49d7eSJed Brown     ///
22699df49d7eSJed Brown     /// * `input`  - Input Vector
22709df49d7eSJed Brown     /// * `output` - Output Vector
22719df49d7eSJed Brown     ///
22729df49d7eSJed Brown     /// ```
22739df49d7eSJed Brown     /// # use libceed::prelude::*;
22744d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
22759df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
22769df49d7eSJed Brown     /// let ne = 4;
22779df49d7eSJed Brown     /// let p = 3;
22789df49d7eSJed Brown     /// let q = 4;
22799df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
22809df49d7eSJed Brown     ///
22819df49d7eSJed Brown     /// // Vectors
2282c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
2283c68be7a2SJeremy L Thompson     /// let mut qdata_mass = ceed.vector(ne * q)?;
22849df49d7eSJed Brown     /// qdata_mass.set_value(0.0);
2285c68be7a2SJeremy L Thompson     /// let mut qdata_diff = ceed.vector(ne * q)?;
22869df49d7eSJed Brown     /// qdata_diff.set_value(0.0);
2287c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
22889df49d7eSJed Brown     /// u.set_value(1.0);
2289c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
22909df49d7eSJed Brown     /// v.set_value(0.0);
22919df49d7eSJed Brown     ///
22929df49d7eSJed Brown     /// // Restrictions
22939df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
22949df49d7eSJed Brown     /// for i in 0..ne {
22959df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
22969df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
22979df49d7eSJed Brown     /// }
2298c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
22999df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
23009df49d7eSJed Brown     /// for i in 0..ne {
23019df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
23029df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
23039df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
23049df49d7eSJed Brown     /// }
2305c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
23069df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2307c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
23089df49d7eSJed Brown     ///
23099df49d7eSJed Brown     /// // Bases
2310c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2311c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
23129df49d7eSJed Brown     ///
23139df49d7eSJed Brown     /// // Build quadrature data
2314c68be7a2SJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
2315c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
2316c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2317c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2318356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2319c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_mass)?;
23209df49d7eSJed Brown     ///
2321c68be7a2SJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
2322c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
2323c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2324c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2325356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2326c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_diff)?;
23279df49d7eSJed Brown     ///
23289df49d7eSJed Brown     /// // Application operator
2329c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
23309df49d7eSJed Brown     /// let op_mass = ceed
2331c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2332c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
2333356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2334c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
23359df49d7eSJed Brown     ///
2336c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
23379df49d7eSJed Brown     /// let op_diff = ceed
2338c68be7a2SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2339c68be7a2SJeremy L Thompson     ///     .field("du", &ru, &bu, VectorOpt::Active)?
2340356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2341c68be7a2SJeremy L Thompson     ///     .field("dv", &ru, &bu, VectorOpt::Active)?;
23429df49d7eSJed Brown     ///
23439df49d7eSJed Brown     /// let op_composite = ceed
2344c68be7a2SJeremy L Thompson     ///     .composite_operator()?
2345c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2346c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
23479df49d7eSJed Brown     ///
23489df49d7eSJed Brown     /// v.set_value(1.0);
2349c68be7a2SJeremy L Thompson     /// op_composite.apply_add(&u, &mut v)?;
23509df49d7eSJed Brown     ///
23519df49d7eSJed Brown     /// // Check
2352e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
23539df49d7eSJed Brown     /// assert!(
235480a9ef05SNatalie Beams     ///     (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON,
23559df49d7eSJed Brown     ///     "Incorrect interval length computed"
23569df49d7eSJed Brown     /// );
2357c68be7a2SJeremy L Thompson     /// # Ok(())
2358c68be7a2SJeremy L Thompson     /// # }
23599df49d7eSJed Brown     /// ```
23609df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
23619df49d7eSJed Brown         self.op_core.apply_add(input, output)
23629df49d7eSJed Brown     }
23639df49d7eSJed Brown 
23649df49d7eSJed Brown     /// Add a sub-Operator to a Composite Operator
23659df49d7eSJed Brown     ///
23669df49d7eSJed Brown     /// * `subop` - Sub-Operator
23679df49d7eSJed Brown     ///
23689df49d7eSJed Brown     /// ```
23699df49d7eSJed Brown     /// # use libceed::prelude::*;
23704d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
23719df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
2372c68be7a2SJeremy L Thompson     /// let mut op = ceed.composite_operator()?;
23739df49d7eSJed Brown     ///
2374c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
2375c68be7a2SJeremy L Thompson     /// let op_mass = ceed.operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?;
2376c68be7a2SJeremy L Thompson     /// op = op.sub_operator(&op_mass)?;
23779df49d7eSJed Brown     ///
2378c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
2379c68be7a2SJeremy L Thompson     /// let op_diff = ceed.operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?;
2380c68be7a2SJeremy L Thompson     /// op = op.sub_operator(&op_diff)?;
2381c68be7a2SJeremy L Thompson     /// # Ok(())
2382c68be7a2SJeremy L Thompson     /// # }
23839df49d7eSJed Brown     /// ```
23849df49d7eSJed Brown     #[allow(unused_mut)]
23859df49d7eSJed Brown     pub fn sub_operator(mut self, subop: &Operator) -> crate::Result<Self> {
23869df49d7eSJed Brown         let ierr =
23879df49d7eSJed Brown             unsafe { bind_ceed::CeedCompositeOperatorAddSub(self.op_core.ptr, subop.op_core.ptr) };
23881142270cSJeremy L Thompson         self.op_core.check_error(ierr)?;
23899df49d7eSJed Brown         Ok(self)
23909df49d7eSJed Brown     }
23919df49d7eSJed Brown 
23926f97ff0aSJeremy L Thompson     /// Check if CompositeOperator is setup correctly
23936f97ff0aSJeremy L Thompson     ///
23946f97ff0aSJeremy L Thompson     /// ```
23956f97ff0aSJeremy L Thompson     /// # use libceed::prelude::*;
23966f97ff0aSJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
23976f97ff0aSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
23986f97ff0aSJeremy L Thompson     /// let ne = 4;
23996f97ff0aSJeremy L Thompson     /// let p = 3;
24006f97ff0aSJeremy L Thompson     /// let q = 4;
24016f97ff0aSJeremy L Thompson     /// let ndofs = p * ne - ne + 1;
24026f97ff0aSJeremy L Thompson     ///
24036f97ff0aSJeremy L Thompson     /// // Restrictions
24046f97ff0aSJeremy L Thompson     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
24056f97ff0aSJeremy L Thompson     /// for i in 0..ne {
24066f97ff0aSJeremy L Thompson     ///     indx[2 * i + 0] = i as i32;
24076f97ff0aSJeremy L Thompson     ///     indx[2 * i + 1] = (i + 1) as i32;
24086f97ff0aSJeremy L Thompson     /// }
24096f97ff0aSJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
24106f97ff0aSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
24116f97ff0aSJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
24126f97ff0aSJeremy L Thompson     ///
24136f97ff0aSJeremy L Thompson     /// // Bases
24146f97ff0aSJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
24156f97ff0aSJeremy L Thompson     ///
24166f97ff0aSJeremy L Thompson     /// // Build quadrature data
24176f97ff0aSJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
24186f97ff0aSJeremy L Thompson     /// let op_build_mass = ceed
24196f97ff0aSJeremy L Thompson     ///     .operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
24206f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
24216f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2422356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
24236f97ff0aSJeremy L Thompson     ///
24246f97ff0aSJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
24256f97ff0aSJeremy L Thompson     /// let op_build_diff = ceed
24266f97ff0aSJeremy L Thompson     ///     .operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
24276f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
24286f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2429356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
24306f97ff0aSJeremy L Thompson     ///
24316f97ff0aSJeremy L Thompson     /// let op_build = ceed
24326f97ff0aSJeremy L Thompson     ///     .composite_operator()?
24336f97ff0aSJeremy L Thompson     ///     .sub_operator(&op_build_mass)?
24346f97ff0aSJeremy L Thompson     ///     .sub_operator(&op_build_diff)?;
24356f97ff0aSJeremy L Thompson     ///
24366f97ff0aSJeremy L Thompson     /// // Check
24376f97ff0aSJeremy L Thompson     /// assert!(op_build.check().is_ok(), "Operator setup incorrectly");
24386f97ff0aSJeremy L Thompson     /// # Ok(())
24396f97ff0aSJeremy L Thompson     /// # }
24406f97ff0aSJeremy L Thompson     /// ```
24416f97ff0aSJeremy L Thompson     pub fn check(self) -> crate::Result<Self> {
24426f97ff0aSJeremy L Thompson         self.op_core.check()?;
24436f97ff0aSJeremy L Thompson         Ok(self)
24446f97ff0aSJeremy L Thompson     }
24456f97ff0aSJeremy L Thompson 
24469df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
24479df49d7eSJed Brown     ///
24489df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
24499df49d7eSJed Brown     ///
24509df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24519df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24529df49d7eSJed Brown     ///
24539df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24549df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
2455b748b478SJeremy L Thompson     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
24569df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
24579df49d7eSJed Brown     }
24589df49d7eSJed Brown 
24599df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
24609df49d7eSJed Brown     ///
24619df49d7eSJed Brown     /// This overwrites a Vector with the point block diagonal of a linear
24629df49d7eSJed Brown     ///   Operator.
24639df49d7eSJed Brown     ///
24649df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24659df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24669df49d7eSJed Brown     ///
24679df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24689df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
24699df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
24709df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
24719df49d7eSJed Brown     }
24729df49d7eSJed Brown 
24739df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
24749df49d7eSJed Brown     ///
24759df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
24769df49d7eSJed Brown     ///
24779df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24789df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24799df49d7eSJed Brown     ///
24809df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24819df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
24829df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
24839df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
24849df49d7eSJed Brown     ///                   this vector are derived from the active vector for
24859df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
24869df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
24879df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
24889df49d7eSJed Brown         &self,
24899df49d7eSJed Brown         assembled: &mut Vector,
24909df49d7eSJed Brown     ) -> crate::Result<i32> {
24919df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
24929df49d7eSJed Brown     }
24939df49d7eSJed Brown 
24949df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
24959df49d7eSJed Brown     ///
24969df49d7eSJed Brown     /// This sums into a Vector with the diagonal of a linear Operator.
24979df49d7eSJed Brown     ///
24989df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24999df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
25009df49d7eSJed Brown     ///
25019df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
25029df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
25039df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
25049df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
25059df49d7eSJed Brown     ///                   this vector are derived from the active vector for
25069df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
25079df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
25089df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
25099df49d7eSJed Brown         &self,
25109df49d7eSJed Brown         assembled: &mut Vector,
25119df49d7eSJed Brown     ) -> crate::Result<i32> {
25129df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
25139df49d7eSJed Brown     }
25149df49d7eSJed Brown }
25159df49d7eSJed Brown 
25169df49d7eSJed Brown // -----------------------------------------------------------------------------
2517