xref: /libCEED/rust/libceed/src/operator.rs (revision 2b671a0a8bf5062b196159b6c524acbfbb639e7b)
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,
20e03fef56SJeremy L Thompson     pub(crate) vector: crate::Vector<'a>,
21e03fef56SJeremy L Thompson     pub(crate) elem_restriction: crate::ElemRestriction<'a>,
22e03fef56SJeremy 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*2b671a0aSJeremy L Thompson     pub(crate) unsafe fn from_raw(
31e03fef56SJeremy L Thompson         ptr: bind_ceed::CeedOperatorField,
32e03fef56SJeremy L Thompson         ceed: crate::Ceed,
33e03fef56SJeremy L Thompson     ) -> crate::Result<Self> {
34e03fef56SJeremy L Thompson         let vector = {
35e03fef56SJeremy L Thompson             let mut vector_ptr = std::ptr::null_mut();
36*2b671a0aSJeremy L Thompson             ceed.check_error(bind_ceed::CeedOperatorFieldGetVector(ptr, &mut vector_ptr))?;
37e03fef56SJeremy L Thompson             crate::Vector::from_raw(vector_ptr)?
38e03fef56SJeremy L Thompson         };
39e03fef56SJeremy L Thompson         let elem_restriction = {
40e03fef56SJeremy L Thompson             let mut elem_restriction_ptr = std::ptr::null_mut();
41*2b671a0aSJeremy L Thompson             ceed.check_error(bind_ceed::CeedOperatorFieldGetElemRestriction(
42*2b671a0aSJeremy L Thompson                 ptr,
43*2b671a0aSJeremy L Thompson                 &mut elem_restriction_ptr,
44*2b671a0aSJeremy L Thompson             ))?;
45e03fef56SJeremy L Thompson             crate::ElemRestriction::from_raw(elem_restriction_ptr)?
46e03fef56SJeremy L Thompson         };
47e03fef56SJeremy L Thompson         let basis = {
48e03fef56SJeremy L Thompson             let mut basis_ptr = std::ptr::null_mut();
49*2b671a0aSJeremy L Thompson             ceed.check_error(bind_ceed::CeedOperatorFieldGetBasis(ptr, &mut basis_ptr))?;
50e03fef56SJeremy L Thompson             crate::Basis::from_raw(basis_ptr)?
51e03fef56SJeremy L Thompson         };
52e03fef56SJeremy L Thompson         Ok(Self {
53e03fef56SJeremy L Thompson             ptr,
54e03fef56SJeremy L Thompson             vector,
55e03fef56SJeremy L Thompson             elem_restriction,
56e03fef56SJeremy L Thompson             basis,
57e03fef56SJeremy L Thompson             _lifeline: PhantomData,
58e03fef56SJeremy L Thompson         })
59e03fef56SJeremy L Thompson     }
60e03fef56SJeremy L Thompson 
6108778c6fSJeremy L Thompson     /// Get the name of an OperatorField
6208778c6fSJeremy L Thompson     ///
6308778c6fSJeremy L Thompson     /// ```
6408778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
654d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
6608778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
6708778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
6808778c6fSJeremy L Thompson     ///
6908778c6fSJeremy L Thompson     /// // Operator field arguments
7008778c6fSJeremy L Thompson     /// let ne = 3;
7108778c6fSJeremy L Thompson     /// let q = 4 as usize;
7208778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
7308778c6fSJeremy L Thompson     /// for i in 0..ne {
7408778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
7508778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
7608778c6fSJeremy L Thompson     /// }
7708778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
7808778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
79d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
8008778c6fSJeremy L Thompson     ///
8108778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
8208778c6fSJeremy L Thompson     ///
8308778c6fSJeremy L Thompson     /// // Operator fields
8408778c6fSJeremy L Thompson     /// let op = ceed
8508778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
8608778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
8708778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
88356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
8908778c6fSJeremy L Thompson     ///
9008778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
9108778c6fSJeremy L Thompson     ///
9208778c6fSJeremy L Thompson     /// assert_eq!(inputs[0].name(), "dx", "Incorrect input name");
9308778c6fSJeremy L Thompson     /// assert_eq!(inputs[1].name(), "weights", "Incorrect input name");
9408778c6fSJeremy L Thompson     /// # Ok(())
9508778c6fSJeremy L Thompson     /// # }
9608778c6fSJeremy L Thompson     /// ```
9708778c6fSJeremy L Thompson     pub fn name(&self) -> &str {
9808778c6fSJeremy L Thompson         let mut name_ptr: *mut std::os::raw::c_char = std::ptr::null_mut();
9908778c6fSJeremy L Thompson         unsafe {
1006f8994e9SJeremy L Thompson             bind_ceed::CeedOperatorFieldGetName(
1016f8994e9SJeremy L Thompson                 self.ptr,
1026f8994e9SJeremy L Thompson                 &mut name_ptr as *const _ as *mut *const _,
1036f8994e9SJeremy L Thompson             );
10408778c6fSJeremy L Thompson         }
10508778c6fSJeremy L Thompson         unsafe { CStr::from_ptr(name_ptr) }.to_str().unwrap()
10608778c6fSJeremy L Thompson     }
10708778c6fSJeremy L Thompson 
10808778c6fSJeremy L Thompson     /// Get the ElemRestriction of an OperatorField
10908778c6fSJeremy L Thompson     ///
11008778c6fSJeremy L Thompson     /// ```
11108778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
1124d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
11308778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
11408778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
11508778c6fSJeremy L Thompson     ///
11608778c6fSJeremy L Thompson     /// // Operator field arguments
11708778c6fSJeremy L Thompson     /// let ne = 3;
11808778c6fSJeremy L Thompson     /// let q = 4 as usize;
11908778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
12008778c6fSJeremy L Thompson     /// for i in 0..ne {
12108778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
12208778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
12308778c6fSJeremy L Thompson     /// }
12408778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
12508778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
126d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
12708778c6fSJeremy L Thompson     ///
12808778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
12908778c6fSJeremy L Thompson     ///
13008778c6fSJeremy L Thompson     /// // Operator fields
13108778c6fSJeremy L Thompson     /// let op = ceed
13208778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
13308778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
13408778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
135356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
13608778c6fSJeremy L Thompson     ///
13708778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
13808778c6fSJeremy L Thompson     ///
13908778c6fSJeremy L Thompson     /// assert!(
14008778c6fSJeremy L Thompson     ///     inputs[0].elem_restriction().is_some(),
14108778c6fSJeremy L Thompson     ///     "Incorrect field ElemRestriction"
14208778c6fSJeremy L Thompson     /// );
143567c3c29SJeremy L Thompson     /// if let ElemRestrictionOpt::Some(r) = inputs[0].elem_restriction() {
144567c3c29SJeremy L Thompson     ///     assert_eq!(
145567c3c29SJeremy L Thompson     ///         r.num_elements(),
146567c3c29SJeremy L Thompson     ///         ne,
147567c3c29SJeremy L Thompson     ///         "Incorrect field ElemRestriction number of elements"
148567c3c29SJeremy L Thompson     ///     );
149567c3c29SJeremy L Thompson     /// }
150567c3c29SJeremy L Thompson     ///
15108778c6fSJeremy L Thompson     /// assert!(
15208778c6fSJeremy L Thompson     ///     inputs[1].elem_restriction().is_none(),
15308778c6fSJeremy L Thompson     ///     "Incorrect field ElemRestriction"
15408778c6fSJeremy L Thompson     /// );
155e03fef56SJeremy L Thompson     ///
156e03fef56SJeremy L Thompson     /// let outputs = op.outputs()?;
157e03fef56SJeremy L Thompson     ///
158e03fef56SJeremy L Thompson     /// assert!(
159e03fef56SJeremy L Thompson     ///     outputs[0].elem_restriction().is_some(),
160e03fef56SJeremy L Thompson     ///     "Incorrect field ElemRestriction"
161e03fef56SJeremy L Thompson     /// );
162567c3c29SJeremy L Thompson     /// if let ElemRestrictionOpt::Some(r) = outputs[0].elem_restriction() {
163567c3c29SJeremy L Thompson     ///     assert_eq!(
164567c3c29SJeremy L Thompson     ///         r.num_elements(),
165567c3c29SJeremy L Thompson     ///         ne,
166567c3c29SJeremy L Thompson     ///         "Incorrect field ElemRestriction number of elements"
167567c3c29SJeremy L Thompson     ///     );
168567c3c29SJeremy L Thompson     /// }
16908778c6fSJeremy L Thompson     /// # Ok(())
17008778c6fSJeremy L Thompson     /// # }
17108778c6fSJeremy L Thompson     /// ```
17208778c6fSJeremy L Thompson     pub fn elem_restriction(&self) -> ElemRestrictionOpt {
173e03fef56SJeremy L Thompson         if self.elem_restriction.ptr == unsafe { bind_ceed::CEED_ELEMRESTRICTION_NONE } {
17408778c6fSJeremy L Thompson             ElemRestrictionOpt::None
17508778c6fSJeremy L Thompson         } else {
176e03fef56SJeremy L Thompson             ElemRestrictionOpt::Some(&self.elem_restriction)
17708778c6fSJeremy L Thompson         }
17808778c6fSJeremy L Thompson     }
17908778c6fSJeremy L Thompson 
18008778c6fSJeremy L Thompson     /// Get the Basis of an OperatorField
18108778c6fSJeremy L Thompson     ///
18208778c6fSJeremy L Thompson     /// ```
18308778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
1844d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
18508778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
18608778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
18708778c6fSJeremy L Thompson     ///
18808778c6fSJeremy L Thompson     /// // Operator field arguments
18908778c6fSJeremy L Thompson     /// let ne = 3;
19008778c6fSJeremy L Thompson     /// let q = 4 as usize;
19108778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
19208778c6fSJeremy L Thompson     /// for i in 0..ne {
19308778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
19408778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
19508778c6fSJeremy L Thompson     /// }
19608778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
19708778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
198d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
19908778c6fSJeremy L Thompson     ///
20008778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
20108778c6fSJeremy L Thompson     ///
20208778c6fSJeremy L Thompson     /// // Operator fields
20308778c6fSJeremy L Thompson     /// let op = ceed
20408778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
20508778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
20608778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
207356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
20808778c6fSJeremy L Thompson     ///
20908778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
21008778c6fSJeremy L Thompson     ///
21108778c6fSJeremy L Thompson     /// assert!(inputs[0].basis().is_some(), "Incorrect field Basis");
212567c3c29SJeremy L Thompson     /// if let BasisOpt::Some(b) = inputs[0].basis() {
213567c3c29SJeremy L Thompson     ///     assert_eq!(
214567c3c29SJeremy L Thompson     ///         b.num_quadrature_points(),
215567c3c29SJeremy L Thompson     ///         q,
216567c3c29SJeremy L Thompson     ///         "Incorrect field Basis number of quadrature points"
217567c3c29SJeremy L Thompson     ///     );
218567c3c29SJeremy L Thompson     /// }
21908778c6fSJeremy L Thompson     /// assert!(inputs[1].basis().is_some(), "Incorrect field Basis");
220567c3c29SJeremy L Thompson     /// if let BasisOpt::Some(b) = inputs[1].basis() {
221567c3c29SJeremy L Thompson     ///     assert_eq!(
222567c3c29SJeremy L Thompson     ///         b.num_quadrature_points(),
223567c3c29SJeremy L Thompson     ///         q,
224567c3c29SJeremy L Thompson     ///         "Incorrect field Basis number of quadrature points"
225567c3c29SJeremy L Thompson     ///     );
226567c3c29SJeremy L Thompson     /// }
22708778c6fSJeremy L Thompson     ///
22808778c6fSJeremy L Thompson     /// let outputs = op.outputs()?;
22908778c6fSJeremy L Thompson     ///
230356036faSJeremy L Thompson     /// assert!(outputs[0].basis().is_none(), "Incorrect field Basis");
23108778c6fSJeremy L Thompson     /// # Ok(())
23208778c6fSJeremy L Thompson     /// # }
23308778c6fSJeremy L Thompson     /// ```
23408778c6fSJeremy L Thompson     pub fn basis(&self) -> BasisOpt {
235e03fef56SJeremy L Thompson         if self.basis.ptr == unsafe { bind_ceed::CEED_BASIS_NONE } {
236356036faSJeremy L Thompson             BasisOpt::None
23708778c6fSJeremy L Thompson         } else {
238e03fef56SJeremy L Thompson             BasisOpt::Some(&self.basis)
23908778c6fSJeremy L Thompson         }
24008778c6fSJeremy L Thompson     }
24108778c6fSJeremy L Thompson 
24208778c6fSJeremy L Thompson     /// Get the Vector of an OperatorField
24308778c6fSJeremy L Thompson     ///
24408778c6fSJeremy L Thompson     /// ```
24508778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
2464d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
24708778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
24808778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
24908778c6fSJeremy L Thompson     ///
25008778c6fSJeremy L Thompson     /// // Operator field arguments
25108778c6fSJeremy L Thompson     /// let ne = 3;
25208778c6fSJeremy L Thompson     /// let q = 4 as usize;
25308778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
25408778c6fSJeremy L Thompson     /// for i in 0..ne {
25508778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
25608778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
25708778c6fSJeremy L Thompson     /// }
25808778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
25908778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
260d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
26108778c6fSJeremy L Thompson     ///
26208778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
26308778c6fSJeremy L Thompson     ///
26408778c6fSJeremy L Thompson     /// // Operator fields
26508778c6fSJeremy L Thompson     /// let op = ceed
26608778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
26708778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
26808778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
269356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
27008778c6fSJeremy L Thompson     ///
27108778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
27208778c6fSJeremy L Thompson     ///
27308778c6fSJeremy L Thompson     /// assert!(inputs[0].vector().is_active(), "Incorrect field Vector");
27408778c6fSJeremy L Thompson     /// assert!(inputs[1].vector().is_none(), "Incorrect field Vector");
275e03fef56SJeremy L Thompson     ///
276e03fef56SJeremy L Thompson     /// let outputs = op.outputs()?;
277e03fef56SJeremy L Thompson     ///
278e03fef56SJeremy L Thompson     /// assert!(outputs[0].vector().is_active(), "Incorrect field Vector");
27908778c6fSJeremy L Thompson     /// # Ok(())
28008778c6fSJeremy L Thompson     /// # }
28108778c6fSJeremy L Thompson     /// ```
28208778c6fSJeremy L Thompson     pub fn vector(&self) -> VectorOpt {
283e03fef56SJeremy L Thompson         if self.vector.ptr == unsafe { bind_ceed::CEED_VECTOR_ACTIVE } {
28408778c6fSJeremy L Thompson             VectorOpt::Active
285e03fef56SJeremy L Thompson         } else if self.vector.ptr == unsafe { bind_ceed::CEED_VECTOR_NONE } {
28608778c6fSJeremy L Thompson             VectorOpt::None
28708778c6fSJeremy L Thompson         } else {
288e03fef56SJeremy L Thompson             VectorOpt::Some(&self.vector)
28908778c6fSJeremy L Thompson         }
29008778c6fSJeremy L Thompson     }
29108778c6fSJeremy L Thompson }
29208778c6fSJeremy L Thompson 
29308778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
2947ed177dbSJed Brown // Operator context wrapper
2959df49d7eSJed Brown // -----------------------------------------------------------------------------
296c68be7a2SJeremy L Thompson #[derive(Debug)]
2979df49d7eSJed Brown pub(crate) struct OperatorCore<'a> {
2989df49d7eSJed Brown     ptr: bind_ceed::CeedOperator,
2991142270cSJeremy L Thompson     _lifeline: PhantomData<&'a ()>,
3009df49d7eSJed Brown }
3019df49d7eSJed Brown 
302c68be7a2SJeremy L Thompson #[derive(Debug)]
3039df49d7eSJed Brown pub struct Operator<'a> {
3049df49d7eSJed Brown     op_core: OperatorCore<'a>,
3059df49d7eSJed Brown }
3069df49d7eSJed Brown 
307c68be7a2SJeremy L Thompson #[derive(Debug)]
3089df49d7eSJed Brown pub struct CompositeOperator<'a> {
3099df49d7eSJed Brown     op_core: OperatorCore<'a>,
3109df49d7eSJed Brown }
3119df49d7eSJed Brown 
3129df49d7eSJed Brown // -----------------------------------------------------------------------------
3139df49d7eSJed Brown // Destructor
3149df49d7eSJed Brown // -----------------------------------------------------------------------------
3159df49d7eSJed Brown impl<'a> Drop for OperatorCore<'a> {
3169df49d7eSJed Brown     fn drop(&mut self) {
3179df49d7eSJed Brown         unsafe {
3189df49d7eSJed Brown             bind_ceed::CeedOperatorDestroy(&mut self.ptr);
3199df49d7eSJed Brown         }
3209df49d7eSJed Brown     }
3219df49d7eSJed Brown }
3229df49d7eSJed Brown 
3239df49d7eSJed Brown // -----------------------------------------------------------------------------
3249df49d7eSJed Brown // Display
3259df49d7eSJed Brown // -----------------------------------------------------------------------------
3269df49d7eSJed Brown impl<'a> fmt::Display for OperatorCore<'a> {
3279df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3289df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
3299df49d7eSJed Brown         let mut sizeloc = crate::MAX_BUFFER_LENGTH;
3309df49d7eSJed Brown         let cstring = unsafe {
3319df49d7eSJed Brown             let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc);
3329df49d7eSJed Brown             bind_ceed::CeedOperatorView(self.ptr, file);
3339df49d7eSJed Brown             bind_ceed::fclose(file);
3349df49d7eSJed Brown             CString::from_raw(ptr)
3359df49d7eSJed Brown         };
3369df49d7eSJed Brown         cstring.to_string_lossy().fmt(f)
3379df49d7eSJed Brown     }
3389df49d7eSJed Brown }
3399df49d7eSJed Brown 
3409df49d7eSJed Brown /// View an Operator
3419df49d7eSJed Brown ///
3429df49d7eSJed Brown /// ```
3439df49d7eSJed Brown /// # use libceed::prelude::*;
3444d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
3459df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
346c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
3479df49d7eSJed Brown ///
3489df49d7eSJed Brown /// // Operator field arguments
3499df49d7eSJed Brown /// let ne = 3;
3509df49d7eSJed Brown /// let q = 4 as usize;
3519df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne];
3529df49d7eSJed Brown /// for i in 0..ne {
3539df49d7eSJed Brown ///     ind[2 * i + 0] = i as i32;
3549df49d7eSJed Brown ///     ind[2 * i + 1] = (i + 1) as i32;
3559df49d7eSJed Brown /// }
356c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
3579df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32];
358d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
3599df49d7eSJed Brown ///
360c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
3619df49d7eSJed Brown ///
3629df49d7eSJed Brown /// // Operator fields
3639df49d7eSJed Brown /// let op = ceed
364c68be7a2SJeremy L Thompson ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
365ea6b5821SJeremy L Thompson ///     .name("mass")?
366c68be7a2SJeremy L Thompson ///     .field("dx", &r, &b, VectorOpt::Active)?
367c68be7a2SJeremy L Thompson ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
368356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
3699df49d7eSJed Brown ///
3709df49d7eSJed Brown /// println!("{}", op);
371c68be7a2SJeremy L Thompson /// # Ok(())
372c68be7a2SJeremy L Thompson /// # }
3739df49d7eSJed Brown /// ```
3749df49d7eSJed Brown impl<'a> fmt::Display for Operator<'a> {
3759df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3769df49d7eSJed Brown         self.op_core.fmt(f)
3779df49d7eSJed Brown     }
3789df49d7eSJed Brown }
3799df49d7eSJed Brown 
3809df49d7eSJed Brown /// View a composite Operator
3819df49d7eSJed Brown ///
3829df49d7eSJed Brown /// ```
3839df49d7eSJed Brown /// # use libceed::prelude::*;
3844d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
3859df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
3869df49d7eSJed Brown ///
3879df49d7eSJed Brown /// // Sub operator field arguments
3889df49d7eSJed Brown /// let ne = 3;
3899df49d7eSJed Brown /// let q = 4 as usize;
3909df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne];
3919df49d7eSJed Brown /// for i in 0..ne {
3929df49d7eSJed Brown ///     ind[2 * i + 0] = i as i32;
3939df49d7eSJed Brown ///     ind[2 * i + 1] = (i + 1) as i32;
3949df49d7eSJed Brown /// }
395c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
3969df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32];
397d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
3989df49d7eSJed Brown ///
399c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
4009df49d7eSJed Brown ///
401c68be7a2SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?;
402c68be7a2SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?;
4039df49d7eSJed Brown ///
404c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
4059df49d7eSJed Brown /// let op_mass = ceed
406c68be7a2SJeremy L Thompson ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
407ea6b5821SJeremy L Thompson ///     .name("Mass term")?
408c68be7a2SJeremy L Thompson ///     .field("u", &r, &b, VectorOpt::Active)?
409356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
410c68be7a2SJeremy L Thompson ///     .field("v", &r, &b, VectorOpt::Active)?;
4119df49d7eSJed Brown ///
412c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
4139df49d7eSJed Brown /// let op_diff = ceed
414c68be7a2SJeremy L Thompson ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
415ea6b5821SJeremy L Thompson ///     .name("Poisson term")?
416c68be7a2SJeremy L Thompson ///     .field("du", &r, &b, VectorOpt::Active)?
417356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
418c68be7a2SJeremy L Thompson ///     .field("dv", &r, &b, VectorOpt::Active)?;
4199df49d7eSJed Brown ///
4209df49d7eSJed Brown /// let op = ceed
421c68be7a2SJeremy L Thompson ///     .composite_operator()?
422ea6b5821SJeremy L Thompson ///     .name("Screened Poisson")?
423c68be7a2SJeremy L Thompson ///     .sub_operator(&op_mass)?
424c68be7a2SJeremy L Thompson ///     .sub_operator(&op_diff)?;
4259df49d7eSJed Brown ///
4269df49d7eSJed Brown /// println!("{}", op);
427c68be7a2SJeremy L Thompson /// # Ok(())
428c68be7a2SJeremy L Thompson /// # }
4299df49d7eSJed Brown /// ```
4309df49d7eSJed Brown impl<'a> fmt::Display for CompositeOperator<'a> {
4319df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4329df49d7eSJed Brown         self.op_core.fmt(f)
4339df49d7eSJed Brown     }
4349df49d7eSJed Brown }
4359df49d7eSJed Brown 
4369df49d7eSJed Brown // -----------------------------------------------------------------------------
4379df49d7eSJed Brown // Core functionality
4389df49d7eSJed Brown // -----------------------------------------------------------------------------
4399df49d7eSJed Brown impl<'a> OperatorCore<'a> {
44011544396SJeremy L Thompson     // Raw Ceed for error handling
44111544396SJeremy L Thompson     #[doc(hidden)]
44211544396SJeremy L Thompson     fn ceed(&self) -> bind_ceed::Ceed {
44311544396SJeremy L Thompson         unsafe { bind_ceed::CeedOperatorReturnCeed(self.ptr) }
44411544396SJeremy L Thompson     }
44511544396SJeremy L Thompson 
4461142270cSJeremy L Thompson     // Error handling
4471142270cSJeremy L Thompson     #[doc(hidden)]
4481142270cSJeremy L Thompson     fn check_error(&self, ierr: i32) -> crate::Result<i32> {
44911544396SJeremy L Thompson         crate::check_error(|| self.ceed(), ierr)
4501142270cSJeremy L Thompson     }
4511142270cSJeremy L Thompson 
4529df49d7eSJed Brown     // Common implementations
4536f97ff0aSJeremy L Thompson     pub fn check(&self) -> crate::Result<i32> {
454656ef1e5SJeremy L Thompson         self.check_error(unsafe { bind_ceed::CeedOperatorCheckReady(self.ptr) })
4556f97ff0aSJeremy L Thompson     }
4566f97ff0aSJeremy L Thompson 
457ea6b5821SJeremy L Thompson     pub fn name(&self, name: &str) -> crate::Result<i32> {
458ea6b5821SJeremy L Thompson         let name_c = CString::new(name).expect("CString::new failed");
459656ef1e5SJeremy L Thompson         self.check_error(unsafe { bind_ceed::CeedOperatorSetName(self.ptr, name_c.as_ptr()) })
460ea6b5821SJeremy L Thompson     }
461ea6b5821SJeremy L Thompson 
4629df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
463656ef1e5SJeremy L Thompson         self.check_error(unsafe {
4649df49d7eSJed Brown             bind_ceed::CeedOperatorApply(
4659df49d7eSJed Brown                 self.ptr,
4669df49d7eSJed Brown                 input.ptr,
4679df49d7eSJed Brown                 output.ptr,
4689df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4699df49d7eSJed Brown             )
470656ef1e5SJeremy L Thompson         })
4719df49d7eSJed Brown     }
4729df49d7eSJed Brown 
4739df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
474656ef1e5SJeremy L Thompson         self.check_error(unsafe {
4759df49d7eSJed Brown             bind_ceed::CeedOperatorApplyAdd(
4769df49d7eSJed Brown                 self.ptr,
4779df49d7eSJed Brown                 input.ptr,
4789df49d7eSJed Brown                 output.ptr,
4799df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4809df49d7eSJed Brown             )
481656ef1e5SJeremy L Thompson         })
4829df49d7eSJed Brown     }
4839df49d7eSJed Brown 
4849df49d7eSJed Brown     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
485656ef1e5SJeremy L Thompson         self.check_error(unsafe {
4869df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleDiagonal(
4879df49d7eSJed Brown                 self.ptr,
4889df49d7eSJed Brown                 assembled.ptr,
4899df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4909df49d7eSJed Brown             )
491656ef1e5SJeremy L Thompson         })
4929df49d7eSJed Brown     }
4939df49d7eSJed Brown 
4949df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
495656ef1e5SJeremy L Thompson         self.check_error(unsafe {
4969df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleAddDiagonal(
4979df49d7eSJed Brown                 self.ptr,
4989df49d7eSJed Brown                 assembled.ptr,
4999df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
5009df49d7eSJed Brown             )
501656ef1e5SJeremy L Thompson         })
5029df49d7eSJed Brown     }
5039df49d7eSJed Brown 
5049df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
5059df49d7eSJed Brown         &self,
5069df49d7eSJed Brown         assembled: &mut Vector,
5079df49d7eSJed Brown     ) -> crate::Result<i32> {
508656ef1e5SJeremy L Thompson         self.check_error(unsafe {
5099df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssemblePointBlockDiagonal(
5109df49d7eSJed Brown                 self.ptr,
5119df49d7eSJed Brown                 assembled.ptr,
5129df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
5139df49d7eSJed Brown             )
514656ef1e5SJeremy L Thompson         })
5159df49d7eSJed Brown     }
5169df49d7eSJed Brown 
5179df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
5189df49d7eSJed Brown         &self,
5199df49d7eSJed Brown         assembled: &mut Vector,
5209df49d7eSJed Brown     ) -> crate::Result<i32> {
521656ef1e5SJeremy L Thompson         self.check_error(unsafe {
5229df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleAddPointBlockDiagonal(
5239df49d7eSJed Brown                 self.ptr,
5249df49d7eSJed Brown                 assembled.ptr,
5259df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
5269df49d7eSJed Brown             )
527656ef1e5SJeremy L Thompson         })
5289df49d7eSJed Brown     }
5299df49d7eSJed Brown }
5309df49d7eSJed Brown 
5319df49d7eSJed Brown // -----------------------------------------------------------------------------
5329df49d7eSJed Brown // Operator
5339df49d7eSJed Brown // -----------------------------------------------------------------------------
5349df49d7eSJed Brown impl<'a> Operator<'a> {
5359df49d7eSJed Brown     // Constructor
5369df49d7eSJed Brown     pub fn create<'b>(
537594ef120SJeremy L Thompson         ceed: &crate::Ceed,
5389df49d7eSJed Brown         qf: impl Into<QFunctionOpt<'b>>,
5399df49d7eSJed Brown         dqf: impl Into<QFunctionOpt<'b>>,
5409df49d7eSJed Brown         dqfT: impl Into<QFunctionOpt<'b>>,
5419df49d7eSJed Brown     ) -> crate::Result<Self> {
5429df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
543656ef1e5SJeremy L Thompson         ceed.check_error(unsafe {
5449df49d7eSJed Brown             bind_ceed::CeedOperatorCreate(
5459df49d7eSJed Brown                 ceed.ptr,
5469df49d7eSJed Brown                 qf.into().to_raw(),
5479df49d7eSJed Brown                 dqf.into().to_raw(),
5489df49d7eSJed Brown                 dqfT.into().to_raw(),
5499df49d7eSJed Brown                 &mut ptr,
5509df49d7eSJed Brown             )
551656ef1e5SJeremy L Thompson         })?;
5529df49d7eSJed Brown         Ok(Self {
5531142270cSJeremy L Thompson             op_core: OperatorCore {
5541142270cSJeremy L Thompson                 ptr,
5551142270cSJeremy L Thompson                 _lifeline: PhantomData,
5561142270cSJeremy L Thompson             },
5579df49d7eSJed Brown         })
5589df49d7eSJed Brown     }
5599df49d7eSJed Brown 
560*2b671a0aSJeremy L Thompson     unsafe fn from_raw(ptr: bind_ceed::CeedOperator) -> crate::Result<Self> {
5619df49d7eSJed Brown         Ok(Self {
5621142270cSJeremy L Thompson             op_core: OperatorCore {
5631142270cSJeremy L Thompson                 ptr,
5641142270cSJeremy L Thompson                 _lifeline: PhantomData,
5651142270cSJeremy L Thompson             },
5669df49d7eSJed Brown         })
5679df49d7eSJed Brown     }
5689df49d7eSJed Brown 
569ea6b5821SJeremy L Thompson     /// Set name for Operator printing
570ea6b5821SJeremy L Thompson     ///
571ea6b5821SJeremy L Thompson     /// * 'name' - Name to set
572ea6b5821SJeremy L Thompson     ///
573ea6b5821SJeremy L Thompson     /// ```
574ea6b5821SJeremy L Thompson     /// # use libceed::prelude::*;
575ea6b5821SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
576ea6b5821SJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
577ea6b5821SJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
578ea6b5821SJeremy L Thompson     ///
579ea6b5821SJeremy L Thompson     /// // Operator field arguments
580ea6b5821SJeremy L Thompson     /// let ne = 3;
581ea6b5821SJeremy L Thompson     /// let q = 4 as usize;
582ea6b5821SJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
583ea6b5821SJeremy L Thompson     /// for i in 0..ne {
584ea6b5821SJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
585ea6b5821SJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
586ea6b5821SJeremy L Thompson     /// }
587ea6b5821SJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
588ea6b5821SJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
589d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
590ea6b5821SJeremy L Thompson     ///
591ea6b5821SJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
592ea6b5821SJeremy L Thompson     ///
593ea6b5821SJeremy L Thompson     /// // Operator fields
594ea6b5821SJeremy L Thompson     /// let op = ceed
595ea6b5821SJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
596ea6b5821SJeremy L Thompson     ///     .name("mass")?
597ea6b5821SJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
598ea6b5821SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
599356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
600ea6b5821SJeremy L Thompson     /// # Ok(())
601ea6b5821SJeremy L Thompson     /// # }
602ea6b5821SJeremy L Thompson     /// ```
603ea6b5821SJeremy L Thompson     #[allow(unused_mut)]
604ea6b5821SJeremy L Thompson     pub fn name(mut self, name: &str) -> crate::Result<Self> {
605ea6b5821SJeremy L Thompson         self.op_core.name(name)?;
606ea6b5821SJeremy L Thompson         Ok(self)
607ea6b5821SJeremy L Thompson     }
608ea6b5821SJeremy L Thompson 
6099df49d7eSJed Brown     /// Apply Operator to a vector
6109df49d7eSJed Brown     ///
6119df49d7eSJed Brown     /// * `input`  - Input Vector
6129df49d7eSJed Brown     /// * `output` - Output Vector
6139df49d7eSJed Brown     ///
6149df49d7eSJed Brown     /// ```
6159df49d7eSJed Brown     /// # use libceed::prelude::*;
6164d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
6179df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
6189df49d7eSJed Brown     /// let ne = 4;
6199df49d7eSJed Brown     /// let p = 3;
6209df49d7eSJed Brown     /// let q = 4;
6219df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
6229df49d7eSJed Brown     ///
6239df49d7eSJed Brown     /// // Vectors
624c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
625c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
6269df49d7eSJed Brown     /// qdata.set_value(0.0);
627c68be7a2SJeremy L Thompson     /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?;
628c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
6299df49d7eSJed Brown     /// v.set_value(0.0);
6309df49d7eSJed Brown     ///
6319df49d7eSJed Brown     /// // Restrictions
6329df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
6339df49d7eSJed Brown     /// for i in 0..ne {
6349df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
6359df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
6369df49d7eSJed Brown     /// }
637c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
6389df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
6399df49d7eSJed Brown     /// for i in 0..ne {
6409df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
6419df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
6429df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
6439df49d7eSJed Brown     /// }
644c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
6459df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
646c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
6479df49d7eSJed Brown     ///
6489df49d7eSJed Brown     /// // Bases
649c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
650c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
6519df49d7eSJed Brown     ///
6529df49d7eSJed Brown     /// // Build quadrature data
653c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
654c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
655c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
656c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
657356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
658c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
6599df49d7eSJed Brown     ///
6609df49d7eSJed Brown     /// // Mass operator
661c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
6629df49d7eSJed Brown     /// let op_mass = ceed
663c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
664c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
665356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
666c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
6679df49d7eSJed Brown     ///
6689df49d7eSJed Brown     /// v.set_value(0.0);
669c68be7a2SJeremy L Thompson     /// op_mass.apply(&u, &mut v)?;
6709df49d7eSJed Brown     ///
6719df49d7eSJed Brown     /// // Check
672e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
6734b61a5a0SRezgar Shakeri     /// let error: Scalar = (sum - 2.0).abs();
6749df49d7eSJed Brown     /// assert!(
6754b61a5a0SRezgar Shakeri     ///     error < 50.0 * libceed::EPSILON,
6764b61a5a0SRezgar Shakeri     ///     "Incorrect interval length computed. Expected: 2.0, Found: {}, Error: {:.12e}",
6774b61a5a0SRezgar Shakeri     ///     sum,
6784b61a5a0SRezgar Shakeri     ///     error
6799df49d7eSJed Brown     /// );
680c68be7a2SJeremy L Thompson     /// # Ok(())
681c68be7a2SJeremy L Thompson     /// # }
6829df49d7eSJed Brown     /// ```
6839df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
6849df49d7eSJed Brown         self.op_core.apply(input, output)
6859df49d7eSJed Brown     }
6869df49d7eSJed Brown 
6879df49d7eSJed Brown     /// Apply Operator to a vector and add result to output vector
6889df49d7eSJed Brown     ///
6899df49d7eSJed Brown     /// * `input`  - Input Vector
6909df49d7eSJed Brown     /// * `output` - Output Vector
6919df49d7eSJed Brown     ///
6929df49d7eSJed Brown     /// ```
6939df49d7eSJed Brown     /// # use libceed::prelude::*;
6944d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
6959df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
6969df49d7eSJed Brown     /// let ne = 4;
6979df49d7eSJed Brown     /// let p = 3;
6989df49d7eSJed Brown     /// let q = 4;
6999df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
7009df49d7eSJed Brown     ///
7019df49d7eSJed Brown     /// // Vectors
702c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
703c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
7049df49d7eSJed Brown     /// qdata.set_value(0.0);
705c68be7a2SJeremy L Thompson     /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?;
706c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
7079df49d7eSJed Brown     ///
7089df49d7eSJed Brown     /// // Restrictions
7099df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
7109df49d7eSJed Brown     /// for i in 0..ne {
7119df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
7129df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
7139df49d7eSJed Brown     /// }
714c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
7159df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
7169df49d7eSJed Brown     /// for i in 0..ne {
7179df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
7189df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
7199df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
7209df49d7eSJed Brown     /// }
721c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
7229df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
723c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
7249df49d7eSJed Brown     ///
7259df49d7eSJed Brown     /// // Bases
726c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
727c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
7289df49d7eSJed Brown     ///
7299df49d7eSJed Brown     /// // Build quadrature data
730c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
731c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
732c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
733c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
734356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
735c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
7369df49d7eSJed Brown     ///
7379df49d7eSJed Brown     /// // Mass operator
738c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
7399df49d7eSJed Brown     /// let op_mass = ceed
740c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
741c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
742356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
743c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
7449df49d7eSJed Brown     ///
7459df49d7eSJed Brown     /// v.set_value(1.0);
746c68be7a2SJeremy L Thompson     /// op_mass.apply_add(&u, &mut v)?;
7479df49d7eSJed Brown     ///
7489df49d7eSJed Brown     /// // Check
749e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
7509df49d7eSJed Brown     /// assert!(
75180a9ef05SNatalie Beams     ///     (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON,
7529df49d7eSJed Brown     ///     "Incorrect interval length computed and added"
7539df49d7eSJed Brown     /// );
754c68be7a2SJeremy L Thompson     /// # Ok(())
755c68be7a2SJeremy L Thompson     /// # }
7569df49d7eSJed Brown     /// ```
7579df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
7589df49d7eSJed Brown         self.op_core.apply_add(input, output)
7599df49d7eSJed Brown     }
7609df49d7eSJed Brown 
7619df49d7eSJed Brown     /// Provide a field to a Operator for use by its QFunction
7629df49d7eSJed Brown     ///
7639df49d7eSJed Brown     /// * `fieldname` - Name of the field (to be matched with the name used by
7649df49d7eSJed Brown     ///                   the QFunction)
7659df49d7eSJed Brown     /// * `r`         - ElemRestriction
766356036faSJeremy L Thompson     /// * `b`         - Basis in which the field resides or `BasisOpt::None`
767356036faSJeremy L Thompson     /// * `v`         - Vector to be used by Operator or `VectorOpt::Active` if field
768356036faSJeremy L Thompson     ///                   is active or `VectorOpt::None` if using `Weight` with the
7699df49d7eSJed Brown     ///                   QFunction
7709df49d7eSJed Brown     ///
7719df49d7eSJed Brown     ///
7729df49d7eSJed Brown     /// ```
7739df49d7eSJed Brown     /// # use libceed::prelude::*;
7744d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
7759df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
776c68be7a2SJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
777c68be7a2SJeremy L Thompson     /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;
7789df49d7eSJed Brown     ///
7799df49d7eSJed Brown     /// // Operator field arguments
7809df49d7eSJed Brown     /// let ne = 3;
7819df49d7eSJed Brown     /// let q = 4;
7829df49d7eSJed Brown     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
7839df49d7eSJed Brown     /// for i in 0..ne {
7849df49d7eSJed Brown     ///     ind[2 * i + 0] = i as i32;
7859df49d7eSJed Brown     ///     ind[2 * i + 1] = (i + 1) as i32;
7869df49d7eSJed Brown     /// }
787c68be7a2SJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
7889df49d7eSJed Brown     ///
789c68be7a2SJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
7909df49d7eSJed Brown     ///
7919df49d7eSJed Brown     /// // Operator field
792c68be7a2SJeremy L Thompson     /// op = op.field("dx", &r, &b, VectorOpt::Active)?;
793c68be7a2SJeremy L Thompson     /// # Ok(())
794c68be7a2SJeremy L Thompson     /// # }
7959df49d7eSJed Brown     /// ```
7969df49d7eSJed Brown     #[allow(unused_mut)]
7979df49d7eSJed Brown     pub fn field<'b>(
7989df49d7eSJed Brown         mut self,
7999df49d7eSJed Brown         fieldname: &str,
8009df49d7eSJed Brown         r: impl Into<ElemRestrictionOpt<'b>>,
8019df49d7eSJed Brown         b: impl Into<BasisOpt<'b>>,
8029df49d7eSJed Brown         v: impl Into<VectorOpt<'b>>,
8039df49d7eSJed Brown     ) -> crate::Result<Self> {
8049df49d7eSJed Brown         let fieldname = CString::new(fieldname).expect("CString::new failed");
8059df49d7eSJed Brown         let fieldname = fieldname.as_ptr() as *const i8;
806656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
8079df49d7eSJed Brown             bind_ceed::CeedOperatorSetField(
8089df49d7eSJed Brown                 self.op_core.ptr,
8099df49d7eSJed Brown                 fieldname,
8109df49d7eSJed Brown                 r.into().to_raw(),
8119df49d7eSJed Brown                 b.into().to_raw(),
8129df49d7eSJed Brown                 v.into().to_raw(),
8139df49d7eSJed Brown             )
814656ef1e5SJeremy L Thompson         })?;
8159df49d7eSJed Brown         Ok(self)
8169df49d7eSJed Brown     }
8179df49d7eSJed Brown 
81808778c6fSJeremy L Thompson     /// Get a slice of Operator inputs
81908778c6fSJeremy L Thompson     ///
82008778c6fSJeremy L Thompson     /// ```
82108778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
8224d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
82308778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
82408778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
82508778c6fSJeremy L Thompson     ///
82608778c6fSJeremy L Thompson     /// // Operator field arguments
82708778c6fSJeremy L Thompson     /// let ne = 3;
82808778c6fSJeremy L Thompson     /// let q = 4 as usize;
82908778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
83008778c6fSJeremy L Thompson     /// for i in 0..ne {
83108778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
83208778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
83308778c6fSJeremy L Thompson     /// }
83408778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
83508778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
836d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
83708778c6fSJeremy L Thompson     ///
83808778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
83908778c6fSJeremy L Thompson     ///
84008778c6fSJeremy L Thompson     /// // Operator fields
84108778c6fSJeremy L Thompson     /// let op = ceed
84208778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
84308778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
84408778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
845356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
84608778c6fSJeremy L Thompson     ///
84708778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
84808778c6fSJeremy L Thompson     ///
84908778c6fSJeremy L Thompson     /// assert_eq!(inputs.len(), 2, "Incorrect inputs array");
85008778c6fSJeremy L Thompson     /// # Ok(())
85108778c6fSJeremy L Thompson     /// # }
85208778c6fSJeremy L Thompson     /// ```
853e03fef56SJeremy L Thompson     pub fn inputs(&self) -> crate::Result<Vec<crate::OperatorField>> {
85408778c6fSJeremy L Thompson         // Get array of raw C pointers for inputs
85508778c6fSJeremy L Thompson         let mut num_inputs = 0;
85608778c6fSJeremy L Thompson         let mut inputs_ptr = std::ptr::null_mut();
857656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
85808778c6fSJeremy L Thompson             bind_ceed::CeedOperatorGetFields(
85908778c6fSJeremy L Thompson                 self.op_core.ptr,
86008778c6fSJeremy L Thompson                 &mut num_inputs,
86108778c6fSJeremy L Thompson                 &mut inputs_ptr,
86208778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut bind_ceed::CeedInt,
86308778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField,
86408778c6fSJeremy L Thompson             )
865656ef1e5SJeremy L Thompson         })?;
86608778c6fSJeremy L Thompson         // Convert raw C pointers to fixed length slice
86708778c6fSJeremy L Thompson         let inputs_slice = unsafe {
86808778c6fSJeremy L Thompson             std::slice::from_raw_parts(
869e03fef56SJeremy L Thompson                 inputs_ptr as *mut bind_ceed::CeedOperatorField,
87008778c6fSJeremy L Thompson                 num_inputs as usize,
87108778c6fSJeremy L Thompson             )
87208778c6fSJeremy L Thompson         };
873e03fef56SJeremy L Thompson         // And finally build vec
874e03fef56SJeremy L Thompson         let ceed = {
875656ef1e5SJeremy L Thompson             let ceed_raw = self.op_core.ceed();
876e03fef56SJeremy L Thompson             let mut ptr = std::ptr::null_mut();
877e03fef56SJeremy L Thompson             unsafe {
878656ef1e5SJeremy L Thompson                 bind_ceed::CeedReferenceCopy(ceed_raw, &mut ptr); // refcount
879e03fef56SJeremy L Thompson             }
880e03fef56SJeremy L Thompson             crate::Ceed { ptr }
881e03fef56SJeremy L Thompson         };
882e03fef56SJeremy L Thompson         let inputs = (0..num_inputs as usize)
883*2b671a0aSJeremy L Thompson             .map(|i| unsafe { crate::OperatorField::from_raw(inputs_slice[i], ceed.clone()) })
884e03fef56SJeremy L Thompson             .collect::<crate::Result<Vec<_>>>()?;
885e03fef56SJeremy L Thompson         Ok(inputs)
88608778c6fSJeremy L Thompson     }
88708778c6fSJeremy L Thompson 
88808778c6fSJeremy L Thompson     /// Get a slice of Operator outputs
88908778c6fSJeremy L Thompson     ///
89008778c6fSJeremy L Thompson     /// ```
89108778c6fSJeremy L Thompson     /// # use libceed::prelude::*;
8924d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
89308778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
89408778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
89508778c6fSJeremy L Thompson     ///
89608778c6fSJeremy L Thompson     /// // Operator field arguments
89708778c6fSJeremy L Thompson     /// let ne = 3;
89808778c6fSJeremy L Thompson     /// let q = 4 as usize;
89908778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
90008778c6fSJeremy L Thompson     /// for i in 0..ne {
90108778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
90208778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
90308778c6fSJeremy L Thompson     /// }
90408778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
90508778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
906d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
90708778c6fSJeremy L Thompson     ///
90808778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
90908778c6fSJeremy L Thompson     ///
91008778c6fSJeremy L Thompson     /// // Operator fields
91108778c6fSJeremy L Thompson     /// let op = ceed
91208778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
91308778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
91408778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
915356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
91608778c6fSJeremy L Thompson     ///
91708778c6fSJeremy L Thompson     /// let outputs = op.outputs()?;
91808778c6fSJeremy L Thompson     ///
91908778c6fSJeremy L Thompson     /// assert_eq!(outputs.len(), 1, "Incorrect outputs array");
92008778c6fSJeremy L Thompson     /// # Ok(())
92108778c6fSJeremy L Thompson     /// # }
92208778c6fSJeremy L Thompson     /// ```
923e03fef56SJeremy L Thompson     pub fn outputs(&self) -> crate::Result<Vec<crate::OperatorField>> {
92408778c6fSJeremy L Thompson         // Get array of raw C pointers for outputs
92508778c6fSJeremy L Thompson         let mut num_outputs = 0;
92608778c6fSJeremy L Thompson         let mut outputs_ptr = std::ptr::null_mut();
927656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
92808778c6fSJeremy L Thompson             bind_ceed::CeedOperatorGetFields(
92908778c6fSJeremy L Thompson                 self.op_core.ptr,
93008778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut bind_ceed::CeedInt,
93108778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut *mut bind_ceed::CeedOperatorField,
93208778c6fSJeremy L Thompson                 &mut num_outputs,
93308778c6fSJeremy L Thompson                 &mut outputs_ptr,
93408778c6fSJeremy L Thompson             )
935656ef1e5SJeremy L Thompson         })?;
93608778c6fSJeremy L Thompson         // Convert raw C pointers to fixed length slice
93708778c6fSJeremy L Thompson         let outputs_slice = unsafe {
93808778c6fSJeremy L Thompson             std::slice::from_raw_parts(
939e03fef56SJeremy L Thompson                 outputs_ptr as *mut bind_ceed::CeedOperatorField,
94008778c6fSJeremy L Thompson                 num_outputs as usize,
94108778c6fSJeremy L Thompson             )
94208778c6fSJeremy L Thompson         };
943e03fef56SJeremy L Thompson         // And finally build vec
944e03fef56SJeremy L Thompson         let ceed = {
945656ef1e5SJeremy L Thompson             let ceed_raw = self.op_core.ceed();
946e03fef56SJeremy L Thompson             let mut ptr = std::ptr::null_mut();
947e03fef56SJeremy L Thompson             unsafe {
948656ef1e5SJeremy L Thompson                 bind_ceed::CeedReferenceCopy(ceed_raw, &mut ptr); // refcount
949e03fef56SJeremy L Thompson             }
950e03fef56SJeremy L Thompson             crate::Ceed { ptr }
951e03fef56SJeremy L Thompson         };
952e03fef56SJeremy L Thompson         let outputs = (0..num_outputs as usize)
953*2b671a0aSJeremy L Thompson             .map(|i| unsafe { crate::OperatorField::from_raw(outputs_slice[i], ceed.clone()) })
954e03fef56SJeremy L Thompson             .collect::<crate::Result<Vec<_>>>()?;
955e03fef56SJeremy L Thompson         Ok(outputs)
95608778c6fSJeremy L Thompson     }
95708778c6fSJeremy L Thompson 
9586f97ff0aSJeremy L Thompson     /// Check if Operator is setup correctly
9596f97ff0aSJeremy L Thompson     ///
9606f97ff0aSJeremy L Thompson     /// ```
9616f97ff0aSJeremy L Thompson     /// # use libceed::prelude::*;
9626f97ff0aSJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
9636f97ff0aSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
9646f97ff0aSJeremy L Thompson     /// let ne = 4;
9656f97ff0aSJeremy L Thompson     /// let p = 3;
9666f97ff0aSJeremy L Thompson     /// let q = 4;
9676f97ff0aSJeremy L Thompson     /// let ndofs = p * ne - ne + 1;
9686f97ff0aSJeremy L Thompson     ///
9696f97ff0aSJeremy L Thompson     /// // Restrictions
9706f97ff0aSJeremy L Thompson     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
9716f97ff0aSJeremy L Thompson     /// for i in 0..ne {
9726f97ff0aSJeremy L Thompson     ///     indx[2 * i + 0] = i as i32;
9736f97ff0aSJeremy L Thompson     ///     indx[2 * i + 1] = (i + 1) as i32;
9746f97ff0aSJeremy L Thompson     /// }
9756f97ff0aSJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
9766f97ff0aSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
9776f97ff0aSJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
9786f97ff0aSJeremy L Thompson     ///
9796f97ff0aSJeremy L Thompson     /// // Bases
9806f97ff0aSJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
9816f97ff0aSJeremy L Thompson     ///
9826f97ff0aSJeremy L Thompson     /// // Build quadrature data
9836f97ff0aSJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
9846f97ff0aSJeremy L Thompson     /// let op_build = ceed
9856f97ff0aSJeremy L Thompson     ///     .operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
9866f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
9876f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
988356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
9896f97ff0aSJeremy L Thompson     ///
9906f97ff0aSJeremy L Thompson     /// // Check
9916f97ff0aSJeremy L Thompson     /// assert!(op_build.check().is_ok(), "Operator setup incorrectly");
9926f97ff0aSJeremy L Thompson     /// # Ok(())
9936f97ff0aSJeremy L Thompson     /// # }
9946f97ff0aSJeremy L Thompson     /// ```
9956f97ff0aSJeremy L Thompson     pub fn check(self) -> crate::Result<Self> {
9966f97ff0aSJeremy L Thompson         self.op_core.check()?;
9976f97ff0aSJeremy L Thompson         Ok(self)
9986f97ff0aSJeremy L Thompson     }
9996f97ff0aSJeremy L Thompson 
10003f2759cfSJeremy L Thompson     /// Get the number of elements associated with an Operator
10013f2759cfSJeremy L Thompson     ///
10023f2759cfSJeremy L Thompson     ///
10033f2759cfSJeremy L Thompson     /// ```
10043f2759cfSJeremy L Thompson     /// # use libceed::prelude::*;
10054d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
10063f2759cfSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
10073f2759cfSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
10083f2759cfSJeremy L Thompson     /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;
10093f2759cfSJeremy L Thompson     ///
10103f2759cfSJeremy L Thompson     /// // Operator field arguments
10113f2759cfSJeremy L Thompson     /// let ne = 3;
10123f2759cfSJeremy L Thompson     /// let q = 4;
10133f2759cfSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
10143f2759cfSJeremy L Thompson     /// for i in 0..ne {
10153f2759cfSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
10163f2759cfSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
10173f2759cfSJeremy L Thompson     /// }
10183f2759cfSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
10193f2759cfSJeremy L Thompson     ///
10203f2759cfSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
10213f2759cfSJeremy L Thompson     ///
10223f2759cfSJeremy L Thompson     /// // Operator field
10233f2759cfSJeremy L Thompson     /// op = op.field("dx", &r, &b, VectorOpt::Active)?;
10243f2759cfSJeremy L Thompson     ///
10253f2759cfSJeremy L Thompson     /// // Check number of elements
10263f2759cfSJeremy L Thompson     /// assert_eq!(op.num_elements(), ne, "Incorrect number of elements");
10273f2759cfSJeremy L Thompson     /// # Ok(())
10283f2759cfSJeremy L Thompson     /// # }
10293f2759cfSJeremy L Thompson     /// ```
10303f2759cfSJeremy L Thompson     pub fn num_elements(&self) -> usize {
10313f2759cfSJeremy L Thompson         let mut nelem = 0;
10323f2759cfSJeremy L Thompson         unsafe { bind_ceed::CeedOperatorGetNumElements(self.op_core.ptr, &mut nelem) };
10333f2759cfSJeremy L Thompson         usize::try_from(nelem).unwrap()
10343f2759cfSJeremy L Thompson     }
10353f2759cfSJeremy L Thompson 
10363f2759cfSJeremy L Thompson     /// Get the number of quadrature points associated with each element of
10373f2759cfSJeremy L Thompson     ///   an Operator
10383f2759cfSJeremy L Thompson     ///
10393f2759cfSJeremy L Thompson     ///
10403f2759cfSJeremy L Thompson     /// ```
10413f2759cfSJeremy L Thompson     /// # use libceed::prelude::*;
10424d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
10433f2759cfSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
10443f2759cfSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
10453f2759cfSJeremy L Thompson     /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;
10463f2759cfSJeremy L Thompson     ///
10473f2759cfSJeremy L Thompson     /// // Operator field arguments
10483f2759cfSJeremy L Thompson     /// let ne = 3;
10493f2759cfSJeremy L Thompson     /// let q = 4;
10503f2759cfSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
10513f2759cfSJeremy L Thompson     /// for i in 0..ne {
10523f2759cfSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
10533f2759cfSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
10543f2759cfSJeremy L Thompson     /// }
10553f2759cfSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
10563f2759cfSJeremy L Thompson     ///
10573f2759cfSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
10583f2759cfSJeremy L Thompson     ///
10593f2759cfSJeremy L Thompson     /// // Operator field
10603f2759cfSJeremy L Thompson     /// op = op.field("dx", &r, &b, VectorOpt::Active)?;
10613f2759cfSJeremy L Thompson     ///
10623f2759cfSJeremy L Thompson     /// // Check number of quadrature points
10633f2759cfSJeremy L Thompson     /// assert_eq!(
10643f2759cfSJeremy L Thompson     ///     op.num_quadrature_points(),
10653f2759cfSJeremy L Thompson     ///     q,
10663f2759cfSJeremy L Thompson     ///     "Incorrect number of quadrature points"
10673f2759cfSJeremy L Thompson     /// );
10683f2759cfSJeremy L Thompson     /// # Ok(())
10693f2759cfSJeremy L Thompson     /// # }
10703f2759cfSJeremy L Thompson     /// ```
10713f2759cfSJeremy L Thompson     pub fn num_quadrature_points(&self) -> usize {
10723f2759cfSJeremy L Thompson         let mut Q = 0;
10733f2759cfSJeremy L Thompson         unsafe { bind_ceed::CeedOperatorGetNumQuadraturePoints(self.op_core.ptr, &mut Q) };
10743f2759cfSJeremy L Thompson         usize::try_from(Q).unwrap()
10753f2759cfSJeremy L Thompson     }
10763f2759cfSJeremy L Thompson 
10779df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
10789df49d7eSJed Brown     ///
10799df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
10809df49d7eSJed Brown     ///
10819df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
10829df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
10839df49d7eSJed Brown     ///
10849df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
10859df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
10869df49d7eSJed Brown     ///
10879df49d7eSJed Brown     /// ```
10889df49d7eSJed Brown     /// # use libceed::prelude::*;
10894d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
10909df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
10919df49d7eSJed Brown     /// let ne = 4;
10929df49d7eSJed Brown     /// let p = 3;
10939df49d7eSJed Brown     /// let q = 4;
10949df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
10959df49d7eSJed Brown     ///
10969df49d7eSJed Brown     /// // Vectors
1097c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1098c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
10999df49d7eSJed Brown     /// qdata.set_value(0.0);
1100c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
11019df49d7eSJed Brown     /// u.set_value(1.0);
1102c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
11039df49d7eSJed Brown     /// v.set_value(0.0);
11049df49d7eSJed Brown     ///
11059df49d7eSJed Brown     /// // Restrictions
11069df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
11079df49d7eSJed Brown     /// for i in 0..ne {
11089df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
11099df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
11109df49d7eSJed Brown     /// }
1111c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
11129df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
11139df49d7eSJed Brown     /// for i in 0..ne {
11149df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
11159df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
11169df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
11179df49d7eSJed Brown     /// }
1118c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?;
11199df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1120c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
11219df49d7eSJed Brown     ///
11229df49d7eSJed Brown     /// // Bases
1123c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1124c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
11259df49d7eSJed Brown     ///
11269df49d7eSJed Brown     /// // Build quadrature data
1127c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1128c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1129c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1130c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1131356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1132c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
11339df49d7eSJed Brown     ///
11349df49d7eSJed Brown     /// // Mass operator
1135c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
11369df49d7eSJed Brown     /// let op_mass = ceed
1137c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1138c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1139356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1140c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
11419df49d7eSJed Brown     ///
11429df49d7eSJed Brown     /// // Diagonal
1143c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ndofs)?;
11449df49d7eSJed Brown     /// diag.set_value(0.0);
1145c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_diagonal(&mut diag)?;
11469df49d7eSJed Brown     ///
11479df49d7eSJed Brown     /// // Manual diagonal computation
1148c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ndofs)?;
11499c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
11509df49d7eSJed Brown     /// for i in 0..ndofs {
11519df49d7eSJed Brown     ///     u.set_value(0.0);
11529df49d7eSJed Brown     ///     {
1153e78171edSJeremy L Thompson     ///         let mut u_array = u.view_mut()?;
11549df49d7eSJed Brown     ///         u_array[i] = 1.;
11559df49d7eSJed Brown     ///     }
11569df49d7eSJed Brown     ///
1157c68be7a2SJeremy L Thompson     ///     op_mass.apply(&u, &mut v)?;
11589df49d7eSJed Brown     ///
11599df49d7eSJed Brown     ///     {
11609c774eddSJeremy L Thompson     ///         let v_array = v.view()?;
1161e78171edSJeremy L Thompson     ///         let mut true_array = true_diag.view_mut()?;
11629df49d7eSJed Brown     ///         true_array[i] = v_array[i];
11639df49d7eSJed Brown     ///     }
11649df49d7eSJed Brown     /// }
11659df49d7eSJed Brown     ///
11669df49d7eSJed Brown     /// // Check
1167e78171edSJeremy L Thompson     /// diag.view()?
11689df49d7eSJed Brown     ///     .iter()
1169e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
11709df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
11719df49d7eSJed Brown     ///         assert!(
117280a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
11739df49d7eSJed Brown     ///             "Diagonal entry incorrect"
11749df49d7eSJed Brown     ///         );
11759df49d7eSJed Brown     ///     });
1176c68be7a2SJeremy L Thompson     /// # Ok(())
1177c68be7a2SJeremy L Thompson     /// # }
11789df49d7eSJed Brown     /// ```
11799df49d7eSJed Brown     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
11809df49d7eSJed Brown         self.op_core.linear_assemble_diagonal(assembled)
11819df49d7eSJed Brown     }
11829df49d7eSJed Brown 
11839df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
11849df49d7eSJed Brown     ///
11859df49d7eSJed Brown     /// This sums into a Vector with the diagonal of a linear Operator.
11869df49d7eSJed Brown     ///
11879df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
11889df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
11899df49d7eSJed Brown     ///
11909df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
11919df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
11929df49d7eSJed Brown     ///
11939df49d7eSJed Brown     ///
11949df49d7eSJed Brown     /// ```
11959df49d7eSJed Brown     /// # use libceed::prelude::*;
11964d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
11979df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
11989df49d7eSJed Brown     /// let ne = 4;
11999df49d7eSJed Brown     /// let p = 3;
12009df49d7eSJed Brown     /// let q = 4;
12019df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
12029df49d7eSJed Brown     ///
12039df49d7eSJed Brown     /// // Vectors
1204c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1205c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
12069df49d7eSJed Brown     /// qdata.set_value(0.0);
1207c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
12089df49d7eSJed Brown     /// u.set_value(1.0);
1209c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
12109df49d7eSJed Brown     /// v.set_value(0.0);
12119df49d7eSJed Brown     ///
12129df49d7eSJed Brown     /// // Restrictions
12139df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
12149df49d7eSJed Brown     /// for i in 0..ne {
12159df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
12169df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
12179df49d7eSJed Brown     /// }
1218c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
12199df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
12209df49d7eSJed Brown     /// for i in 0..ne {
12219df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
12229df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
12239df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
12249df49d7eSJed Brown     /// }
1225c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?;
12269df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1227c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
12289df49d7eSJed Brown     ///
12299df49d7eSJed Brown     /// // Bases
1230c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1231c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
12329df49d7eSJed Brown     ///
12339df49d7eSJed Brown     /// // Build quadrature data
1234c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1235c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1236c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1237c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1238356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1239c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
12409df49d7eSJed Brown     ///
12419df49d7eSJed Brown     /// // Mass operator
1242c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
12439df49d7eSJed Brown     /// let op_mass = ceed
1244c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1245c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1246356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1247c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
12489df49d7eSJed Brown     ///
12499df49d7eSJed Brown     /// // Diagonal
1250c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ndofs)?;
12519df49d7eSJed Brown     /// diag.set_value(1.0);
1252c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_add_diagonal(&mut diag)?;
12539df49d7eSJed Brown     ///
12549df49d7eSJed Brown     /// // Manual diagonal computation
1255c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ndofs)?;
12569c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
12579df49d7eSJed Brown     /// for i in 0..ndofs {
12589df49d7eSJed Brown     ///     u.set_value(0.0);
12599df49d7eSJed Brown     ///     {
1260e78171edSJeremy L Thompson     ///         let mut u_array = u.view_mut()?;
12619df49d7eSJed Brown     ///         u_array[i] = 1.;
12629df49d7eSJed Brown     ///     }
12639df49d7eSJed Brown     ///
1264c68be7a2SJeremy L Thompson     ///     op_mass.apply(&u, &mut v)?;
12659df49d7eSJed Brown     ///
12669df49d7eSJed Brown     ///     {
12679c774eddSJeremy L Thompson     ///         let v_array = v.view()?;
1268e78171edSJeremy L Thompson     ///         let mut true_array = true_diag.view_mut()?;
12699df49d7eSJed Brown     ///         true_array[i] = v_array[i] + 1.0;
12709df49d7eSJed Brown     ///     }
12719df49d7eSJed Brown     /// }
12729df49d7eSJed Brown     ///
12739df49d7eSJed Brown     /// // Check
1274e78171edSJeremy L Thompson     /// diag.view()?
12759df49d7eSJed Brown     ///     .iter()
1276e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
12779df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
12789df49d7eSJed Brown     ///         assert!(
127980a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
12809df49d7eSJed Brown     ///             "Diagonal entry incorrect"
12819df49d7eSJed Brown     ///         );
12829df49d7eSJed Brown     ///     });
1283c68be7a2SJeremy L Thompson     /// # Ok(())
1284c68be7a2SJeremy L Thompson     /// # }
12859df49d7eSJed Brown     /// ```
12869df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
12879df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
12889df49d7eSJed Brown     }
12899df49d7eSJed Brown 
12909df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
12919df49d7eSJed Brown     ///
12929df49d7eSJed Brown     /// This overwrites a Vector with the point block diagonal of a linear
12939df49d7eSJed Brown     /// Operator.
12949df49d7eSJed Brown     ///
12959df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
12969df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
12979df49d7eSJed Brown     ///
12989df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
12999df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
13009df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
13019df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
13029df49d7eSJed Brown     ///                   this vector are derived from the active vector for
13039df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
13049df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
13059df49d7eSJed Brown     ///
13069df49d7eSJed Brown     /// ```
13079df49d7eSJed Brown     /// # use libceed::prelude::*;
13084d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
13099df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
13109df49d7eSJed Brown     /// let ne = 4;
13119df49d7eSJed Brown     /// let p = 3;
13129df49d7eSJed Brown     /// let q = 4;
13139df49d7eSJed Brown     /// let ncomp = 2;
13149df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
13159df49d7eSJed Brown     ///
13169df49d7eSJed Brown     /// // Vectors
1317c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1318c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
13199df49d7eSJed Brown     /// qdata.set_value(0.0);
1320c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ncomp * ndofs)?;
13219df49d7eSJed Brown     /// u.set_value(1.0);
1322c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ncomp * ndofs)?;
13239df49d7eSJed Brown     /// v.set_value(0.0);
13249df49d7eSJed Brown     ///
13259df49d7eSJed Brown     /// // Restrictions
13269df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
13279df49d7eSJed Brown     /// for i in 0..ne {
13289df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
13299df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
13309df49d7eSJed Brown     /// }
1331c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
13329df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
13339df49d7eSJed Brown     /// for i in 0..ne {
13349df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
13359df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
13369df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
13379df49d7eSJed Brown     /// }
1338c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?;
13399df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1340c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
13419df49d7eSJed Brown     ///
13429df49d7eSJed Brown     /// // Bases
1343c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1344c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?;
13459df49d7eSJed Brown     ///
13469df49d7eSJed Brown     /// // Build quadrature data
1347c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1348c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1349c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1350c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1351356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1352c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
13539df49d7eSJed Brown     ///
13549df49d7eSJed Brown     /// // Mass operator
13559df49d7eSJed Brown     /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
13569df49d7eSJed Brown     ///     // Number of quadrature points
13579df49d7eSJed Brown     ///     let q = qdata.len();
13589df49d7eSJed Brown     ///
13599df49d7eSJed Brown     ///     // Iterate over quadrature points
13609df49d7eSJed Brown     ///     for i in 0..q {
13619df49d7eSJed Brown     ///         v[i + 0 * q] = u[i + 1 * q] * qdata[i];
13629df49d7eSJed Brown     ///         v[i + 1 * q] = u[i + 0 * q] * qdata[i];
13639df49d7eSJed Brown     ///     }
13649df49d7eSJed Brown     ///
13659df49d7eSJed Brown     ///     // Return clean error code
13669df49d7eSJed Brown     ///     0
13679df49d7eSJed Brown     /// };
13689df49d7eSJed Brown     ///
13699df49d7eSJed Brown     /// let qf_mass = ceed
1370c68be7a2SJeremy L Thompson     ///     .q_function_interior(1, Box::new(mass_2_comp))?
1371c68be7a2SJeremy L Thompson     ///     .input("u", 2, EvalMode::Interp)?
1372c68be7a2SJeremy L Thompson     ///     .input("qdata", 1, EvalMode::None)?
1373c68be7a2SJeremy L Thompson     ///     .output("v", 2, EvalMode::Interp)?;
13749df49d7eSJed Brown     ///
13759df49d7eSJed Brown     /// let op_mass = ceed
1376c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1377c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1378356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1379c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
13809df49d7eSJed Brown     ///
13819df49d7eSJed Brown     /// // Diagonal
1382c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?;
13839df49d7eSJed Brown     /// diag.set_value(0.0);
1384c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_point_block_diagonal(&mut diag)?;
13859df49d7eSJed Brown     ///
13869df49d7eSJed Brown     /// // Manual diagonal computation
1387c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?;
13889c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
13899df49d7eSJed Brown     /// for i in 0..ndofs {
13909df49d7eSJed Brown     ///     for j in 0..ncomp {
13919df49d7eSJed Brown     ///         u.set_value(0.0);
13929df49d7eSJed Brown     ///         {
1393e78171edSJeremy L Thompson     ///             let mut u_array = u.view_mut()?;
13949df49d7eSJed Brown     ///             u_array[i + j * ndofs] = 1.;
13959df49d7eSJed Brown     ///         }
13969df49d7eSJed Brown     ///
1397c68be7a2SJeremy L Thompson     ///         op_mass.apply(&u, &mut v)?;
13989df49d7eSJed Brown     ///
13999df49d7eSJed Brown     ///         {
14009c774eddSJeremy L Thompson     ///             let v_array = v.view()?;
1401e78171edSJeremy L Thompson     ///             let mut true_array = true_diag.view_mut()?;
14029df49d7eSJed Brown     ///             for k in 0..ncomp {
14039df49d7eSJed Brown     ///                 true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
14049df49d7eSJed Brown     ///             }
14059df49d7eSJed Brown     ///         }
14069df49d7eSJed Brown     ///     }
14079df49d7eSJed Brown     /// }
14089df49d7eSJed Brown     ///
14099df49d7eSJed Brown     /// // Check
1410e78171edSJeremy L Thompson     /// diag.view()?
14119df49d7eSJed Brown     ///     .iter()
1412e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
14139df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
14149df49d7eSJed Brown     ///         assert!(
141580a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
14169df49d7eSJed Brown     ///             "Diagonal entry incorrect"
14179df49d7eSJed Brown     ///         );
14189df49d7eSJed Brown     ///     });
1419c68be7a2SJeremy L Thompson     /// # Ok(())
1420c68be7a2SJeremy L Thompson     /// # }
14219df49d7eSJed Brown     /// ```
14229df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
14239df49d7eSJed Brown         &self,
14249df49d7eSJed Brown         assembled: &mut Vector,
14259df49d7eSJed Brown     ) -> crate::Result<i32> {
14269df49d7eSJed Brown         self.op_core.linear_assemble_point_block_diagonal(assembled)
14279df49d7eSJed Brown     }
14289df49d7eSJed Brown 
14299df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
14309df49d7eSJed Brown     ///
14319df49d7eSJed Brown     /// This sums into a Vector with the point block diagonal of a linear
14329df49d7eSJed Brown     /// Operator.
14339df49d7eSJed Brown     ///
14349df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
14359df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
14369df49d7eSJed Brown     ///
14379df49d7eSJed Brown     /// * `op`        -     Operator to assemble QFunction
14389df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
14399df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
14409df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
14419df49d7eSJed Brown     ///                   this vector are derived from the active vector for
14429df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
14439df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
14449df49d7eSJed Brown     ///
14459df49d7eSJed Brown     /// ```
14469df49d7eSJed Brown     /// # use libceed::prelude::*;
14474d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
14489df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
14499df49d7eSJed Brown     /// let ne = 4;
14509df49d7eSJed Brown     /// let p = 3;
14519df49d7eSJed Brown     /// let q = 4;
14529df49d7eSJed Brown     /// let ncomp = 2;
14539df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
14549df49d7eSJed Brown     ///
14559df49d7eSJed Brown     /// // Vectors
1456c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1457c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
14589df49d7eSJed Brown     /// qdata.set_value(0.0);
1459c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ncomp * ndofs)?;
14609df49d7eSJed Brown     /// u.set_value(1.0);
1461c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ncomp * ndofs)?;
14629df49d7eSJed Brown     /// v.set_value(0.0);
14639df49d7eSJed Brown     ///
14649df49d7eSJed Brown     /// // Restrictions
14659df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
14669df49d7eSJed Brown     /// for i in 0..ne {
14679df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
14689df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
14699df49d7eSJed Brown     /// }
1470c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
14719df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
14729df49d7eSJed Brown     /// for i in 0..ne {
14739df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
14749df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
14759df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
14769df49d7eSJed Brown     /// }
1477c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?;
14789df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1479c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
14809df49d7eSJed Brown     ///
14819df49d7eSJed Brown     /// // Bases
1482c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1483c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?;
14849df49d7eSJed Brown     ///
14859df49d7eSJed Brown     /// // Build quadrature data
1486c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1487c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1488c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1489c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1490356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1491c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
14929df49d7eSJed Brown     ///
14939df49d7eSJed Brown     /// // Mass operator
14949df49d7eSJed Brown     /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
14959df49d7eSJed Brown     ///     // Number of quadrature points
14969df49d7eSJed Brown     ///     let q = qdata.len();
14979df49d7eSJed Brown     ///
14989df49d7eSJed Brown     ///     // Iterate over quadrature points
14999df49d7eSJed Brown     ///     for i in 0..q {
15009df49d7eSJed Brown     ///         v[i + 0 * q] = u[i + 1 * q] * qdata[i];
15019df49d7eSJed Brown     ///         v[i + 1 * q] = u[i + 0 * q] * qdata[i];
15029df49d7eSJed Brown     ///     }
15039df49d7eSJed Brown     ///
15049df49d7eSJed Brown     ///     // Return clean error code
15059df49d7eSJed Brown     ///     0
15069df49d7eSJed Brown     /// };
15079df49d7eSJed Brown     ///
15089df49d7eSJed Brown     /// let qf_mass = ceed
1509c68be7a2SJeremy L Thompson     ///     .q_function_interior(1, Box::new(mass_2_comp))?
1510c68be7a2SJeremy L Thompson     ///     .input("u", 2, EvalMode::Interp)?
1511c68be7a2SJeremy L Thompson     ///     .input("qdata", 1, EvalMode::None)?
1512c68be7a2SJeremy L Thompson     ///     .output("v", 2, EvalMode::Interp)?;
15139df49d7eSJed Brown     ///
15149df49d7eSJed Brown     /// let op_mass = ceed
1515c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1516c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1517356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1518c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
15199df49d7eSJed Brown     ///
15209df49d7eSJed Brown     /// // Diagonal
1521c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?;
15229df49d7eSJed Brown     /// diag.set_value(1.0);
1523c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_add_point_block_diagonal(&mut diag)?;
15249df49d7eSJed Brown     ///
15259df49d7eSJed Brown     /// // Manual diagonal computation
1526c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?;
15279c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
15289df49d7eSJed Brown     /// for i in 0..ndofs {
15299df49d7eSJed Brown     ///     for j in 0..ncomp {
15309df49d7eSJed Brown     ///         u.set_value(0.0);
15319df49d7eSJed Brown     ///         {
1532e78171edSJeremy L Thompson     ///             let mut u_array = u.view_mut()?;
15339df49d7eSJed Brown     ///             u_array[i + j * ndofs] = 1.;
15349df49d7eSJed Brown     ///         }
15359df49d7eSJed Brown     ///
1536c68be7a2SJeremy L Thompson     ///         op_mass.apply(&u, &mut v)?;
15379df49d7eSJed Brown     ///
15389df49d7eSJed Brown     ///         {
15399c774eddSJeremy L Thompson     ///             let v_array = v.view()?;
1540e78171edSJeremy L Thompson     ///             let mut true_array = true_diag.view_mut()?;
15419df49d7eSJed Brown     ///             for k in 0..ncomp {
15429df49d7eSJed Brown     ///                 true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
15439df49d7eSJed Brown     ///             }
15449df49d7eSJed Brown     ///         }
15459df49d7eSJed Brown     ///     }
15469df49d7eSJed Brown     /// }
15479df49d7eSJed Brown     ///
15489df49d7eSJed Brown     /// // Check
1549e78171edSJeremy L Thompson     /// diag.view()?
15509df49d7eSJed Brown     ///     .iter()
1551e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
15529df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
15539df49d7eSJed Brown     ///         assert!(
155480a9ef05SNatalie Beams     ///             (*computed - 1.0 - *actual).abs() < 10.0 * libceed::EPSILON,
15559df49d7eSJed Brown     ///             "Diagonal entry incorrect"
15569df49d7eSJed Brown     ///         );
15579df49d7eSJed Brown     ///     });
1558c68be7a2SJeremy L Thompson     /// # Ok(())
1559c68be7a2SJeremy L Thompson     /// # }
15609df49d7eSJed Brown     /// ```
15619df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
15629df49d7eSJed Brown         &self,
15639df49d7eSJed Brown         assembled: &mut Vector,
15649df49d7eSJed Brown     ) -> crate::Result<i32> {
15659df49d7eSJed Brown         self.op_core
15669df49d7eSJed Brown             .linear_assemble_add_point_block_diagonal(assembled)
15679df49d7eSJed Brown     }
15689df49d7eSJed Brown 
15699df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
15709df49d7eSJed Brown     ///   given Operator, creating the prolongation basis from the fine and
15719df49d7eSJed Brown     ///   coarse grid interpolation
15729df49d7eSJed Brown     ///
15739df49d7eSJed Brown     /// * `p_mult_fine`  - Lvector multiplicity in parallel gather/scatter
15749df49d7eSJed Brown     /// * `rstr_coarse`  - Coarse grid restriction
15759df49d7eSJed Brown     /// * `basis_coarse` - Coarse grid active vector basis
15769df49d7eSJed Brown     ///
15779df49d7eSJed Brown     /// ```
15789df49d7eSJed Brown     /// # use libceed::prelude::*;
15794d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
15809df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
15819df49d7eSJed Brown     /// let ne = 15;
15829df49d7eSJed Brown     /// let p_coarse = 3;
15839df49d7eSJed Brown     /// let p_fine = 5;
15849df49d7eSJed Brown     /// let q = 6;
15859df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
15869df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
15879df49d7eSJed Brown     ///
15889df49d7eSJed Brown     /// // Vectors
15899df49d7eSJed Brown     /// let x_array = (0..ne + 1)
159080a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
159180a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1592c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1593c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
15949df49d7eSJed Brown     /// qdata.set_value(0.0);
1595c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
15969df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1597c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
15989df49d7eSJed Brown     /// u_fine.set_value(1.0);
1599c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
16009df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1601c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
16029df49d7eSJed Brown     /// v_fine.set_value(0.0);
1603c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
16049df49d7eSJed Brown     /// multiplicity.set_value(1.0);
16059df49d7eSJed Brown     ///
16069df49d7eSJed Brown     /// // Restrictions
16079df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1608c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
16099df49d7eSJed Brown     ///
16109df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
16119df49d7eSJed Brown     /// for i in 0..ne {
16129df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
16139df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
16149df49d7eSJed Brown     /// }
1615c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
16169df49d7eSJed Brown     ///
16179df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
16189df49d7eSJed Brown     /// for i in 0..ne {
16199df49d7eSJed Brown     ///     for j in 0..p_coarse {
16209df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
16219df49d7eSJed Brown     ///     }
16229df49d7eSJed Brown     /// }
1623c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
16249df49d7eSJed Brown     ///     ne,
16259df49d7eSJed Brown     ///     p_coarse,
16269df49d7eSJed Brown     ///     1,
16279df49d7eSJed Brown     ///     1,
16289df49d7eSJed Brown     ///     ndofs_coarse,
16299df49d7eSJed Brown     ///     MemType::Host,
16309df49d7eSJed Brown     ///     &indu_coarse,
1631c68be7a2SJeremy L Thompson     /// )?;
16329df49d7eSJed Brown     ///
16339df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
16349df49d7eSJed Brown     /// for i in 0..ne {
16359df49d7eSJed Brown     ///     for j in 0..p_fine {
16369df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
16379df49d7eSJed Brown     ///     }
16389df49d7eSJed Brown     /// }
1639c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
16409df49d7eSJed Brown     ///
16419df49d7eSJed Brown     /// // Bases
1642c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1643c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1644c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
16459df49d7eSJed Brown     ///
16469df49d7eSJed Brown     /// // Build quadrature data
1647c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1648c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1649c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1650c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1651356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1652c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
16539df49d7eSJed Brown     ///
16549df49d7eSJed Brown     /// // Mass operator
1655c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
16569df49d7eSJed Brown     /// let op_mass_fine = ceed
1657c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1658c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
1659356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1660c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
16619df49d7eSJed Brown     ///
16629df49d7eSJed Brown     /// // Multigrid setup
1663c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) =
1664c68be7a2SJeremy L Thompson     ///     op_mass_fine.create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)?;
16659df49d7eSJed Brown     ///
16669df49d7eSJed Brown     /// // Coarse problem
16679df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1668c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
16699df49d7eSJed Brown     ///
16709df49d7eSJed Brown     /// // Check
1671e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
16729df49d7eSJed Brown     /// assert!(
167380a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 50.0 * libceed::EPSILON,
16749df49d7eSJed Brown     ///     "Incorrect interval length computed"
16759df49d7eSJed Brown     /// );
16769df49d7eSJed Brown     ///
16779df49d7eSJed Brown     /// // Prolong
1678c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
16799df49d7eSJed Brown     ///
16809df49d7eSJed Brown     /// // Fine problem
1681c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
16829df49d7eSJed Brown     ///
16839df49d7eSJed Brown     /// // Check
1684e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
16859df49d7eSJed Brown     /// assert!(
1686392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
16879df49d7eSJed Brown     ///     "Incorrect interval length computed"
16889df49d7eSJed Brown     /// );
16899df49d7eSJed Brown     ///
16909df49d7eSJed Brown     /// // Restrict
1691c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
16929df49d7eSJed Brown     ///
16939df49d7eSJed Brown     /// // Check
1694e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
16959df49d7eSJed Brown     /// assert!(
1696392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
16979df49d7eSJed Brown     ///     "Incorrect interval length computed"
16989df49d7eSJed Brown     /// );
1699c68be7a2SJeremy L Thompson     /// # Ok(())
1700c68be7a2SJeremy L Thompson     /// # }
17019df49d7eSJed Brown     /// ```
1702594ef120SJeremy L Thompson     pub fn create_multigrid_level<'b>(
17039df49d7eSJed Brown         &self,
17049df49d7eSJed Brown         p_mult_fine: &Vector,
17059df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
17069df49d7eSJed Brown         basis_coarse: &Basis,
1707594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
17089df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
17099df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
17109df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
1711656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
17129df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreate(
17139df49d7eSJed Brown                 self.op_core.ptr,
17149df49d7eSJed Brown                 p_mult_fine.ptr,
17159df49d7eSJed Brown                 rstr_coarse.ptr,
17169df49d7eSJed Brown                 basis_coarse.ptr,
17179df49d7eSJed Brown                 &mut ptr_coarse,
17189df49d7eSJed Brown                 &mut ptr_prolong,
17199df49d7eSJed Brown                 &mut ptr_restrict,
17209df49d7eSJed Brown             )
1721656ef1e5SJeremy L Thompson         })?;
1722*2b671a0aSJeremy L Thompson         let op_coarse = unsafe { Operator::from_raw(ptr_coarse)? };
1723*2b671a0aSJeremy L Thompson         let op_prolong = unsafe { Operator::from_raw(ptr_prolong)? };
1724*2b671a0aSJeremy L Thompson         let op_restrict = unsafe { Operator::from_raw(ptr_restrict)? };
17259df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
17269df49d7eSJed Brown     }
17279df49d7eSJed Brown 
17289df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
17299df49d7eSJed Brown     ///   given Operator with a tensor basis for the active basis
17309df49d7eSJed Brown     ///
17319df49d7eSJed Brown     /// * `p_mult_fine`   - Lvector multiplicity in parallel gather/scatter
17329df49d7eSJed Brown     /// * `rstr_coarse`   - Coarse grid restriction
17339df49d7eSJed Brown     /// * `basis_coarse`  - Coarse grid active vector basis
17349df49d7eSJed Brown     /// * `interp_c_to_f` - Matrix for coarse to fine
17359df49d7eSJed Brown     ///
17369df49d7eSJed Brown     /// ```
17379df49d7eSJed Brown     /// # use libceed::prelude::*;
17384d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
17399df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
17409df49d7eSJed Brown     /// let ne = 15;
17419df49d7eSJed Brown     /// let p_coarse = 3;
17429df49d7eSJed Brown     /// let p_fine = 5;
17439df49d7eSJed Brown     /// let q = 6;
17449df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
17459df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
17469df49d7eSJed Brown     ///
17479df49d7eSJed Brown     /// // Vectors
17489df49d7eSJed Brown     /// let x_array = (0..ne + 1)
174980a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
175080a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1751c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1752c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
17539df49d7eSJed Brown     /// qdata.set_value(0.0);
1754c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
17559df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1756c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
17579df49d7eSJed Brown     /// u_fine.set_value(1.0);
1758c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
17599df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1760c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
17619df49d7eSJed Brown     /// v_fine.set_value(0.0);
1762c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
17639df49d7eSJed Brown     /// multiplicity.set_value(1.0);
17649df49d7eSJed Brown     ///
17659df49d7eSJed Brown     /// // Restrictions
17669df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1767c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
17689df49d7eSJed Brown     ///
17699df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
17709df49d7eSJed Brown     /// for i in 0..ne {
17719df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
17729df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
17739df49d7eSJed Brown     /// }
1774c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
17759df49d7eSJed Brown     ///
17769df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
17779df49d7eSJed Brown     /// for i in 0..ne {
17789df49d7eSJed Brown     ///     for j in 0..p_coarse {
17799df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
17809df49d7eSJed Brown     ///     }
17819df49d7eSJed Brown     /// }
1782c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
17839df49d7eSJed Brown     ///     ne,
17849df49d7eSJed Brown     ///     p_coarse,
17859df49d7eSJed Brown     ///     1,
17869df49d7eSJed Brown     ///     1,
17879df49d7eSJed Brown     ///     ndofs_coarse,
17889df49d7eSJed Brown     ///     MemType::Host,
17899df49d7eSJed Brown     ///     &indu_coarse,
1790c68be7a2SJeremy L Thompson     /// )?;
17919df49d7eSJed Brown     ///
17929df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
17939df49d7eSJed Brown     /// for i in 0..ne {
17949df49d7eSJed Brown     ///     for j in 0..p_fine {
17959df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
17969df49d7eSJed Brown     ///     }
17979df49d7eSJed Brown     /// }
1798c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
17999df49d7eSJed Brown     ///
18009df49d7eSJed Brown     /// // Bases
1801c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1802c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1803c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
18049df49d7eSJed Brown     ///
18059df49d7eSJed Brown     /// // Build quadrature data
1806c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1807c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1808c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1809c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1810356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1811c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
18129df49d7eSJed Brown     ///
18139df49d7eSJed Brown     /// // Mass operator
1814c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
18159df49d7eSJed Brown     /// let op_mass_fine = ceed
1816c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1817c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
1818356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1819c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
18209df49d7eSJed Brown     ///
18219df49d7eSJed Brown     /// // Multigrid setup
182280a9ef05SNatalie Beams     /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine];
18239df49d7eSJed Brown     /// {
1824c68be7a2SJeremy L Thompson     ///     let mut coarse = ceed.vector(p_coarse)?;
1825c68be7a2SJeremy L Thompson     ///     let mut fine = ceed.vector(p_fine)?;
1826c68be7a2SJeremy L Thompson     ///     let basis_c_to_f =
1827c68be7a2SJeremy L Thompson     ///         ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?;
18289df49d7eSJed Brown     ///     for i in 0..p_coarse {
18299df49d7eSJed Brown     ///         coarse.set_value(0.0);
18309df49d7eSJed Brown     ///         {
1831e78171edSJeremy L Thompson     ///             let mut array = coarse.view_mut()?;
18329df49d7eSJed Brown     ///             array[i] = 1.;
18339df49d7eSJed Brown     ///         }
1834c68be7a2SJeremy L Thompson     ///         basis_c_to_f.apply(
18359df49d7eSJed Brown     ///             1,
18369df49d7eSJed Brown     ///             TransposeMode::NoTranspose,
18379df49d7eSJed Brown     ///             EvalMode::Interp,
18389df49d7eSJed Brown     ///             &coarse,
18399df49d7eSJed Brown     ///             &mut fine,
1840c68be7a2SJeremy L Thompson     ///         )?;
1841e78171edSJeremy L Thompson     ///         let array = fine.view()?;
18429df49d7eSJed Brown     ///         for j in 0..p_fine {
18439df49d7eSJed Brown     ///             interp_c_to_f[j * p_coarse + i] = array[j];
18449df49d7eSJed Brown     ///         }
18459df49d7eSJed Brown     ///     }
18469df49d7eSJed Brown     /// }
1847c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_tensor_H1(
1848c68be7a2SJeremy L Thompson     ///     &multiplicity,
1849c68be7a2SJeremy L Thompson     ///     &ru_coarse,
1850c68be7a2SJeremy L Thompson     ///     &bu_coarse,
1851c68be7a2SJeremy L Thompson     ///     &interp_c_to_f,
1852c68be7a2SJeremy L Thompson     /// )?;
18539df49d7eSJed Brown     ///
18549df49d7eSJed Brown     /// // Coarse problem
18559df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1856c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
18579df49d7eSJed Brown     ///
18589df49d7eSJed Brown     /// // Check
1859e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
18609df49d7eSJed Brown     /// assert!(
186180a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
18629df49d7eSJed Brown     ///     "Incorrect interval length computed"
18639df49d7eSJed Brown     /// );
18649df49d7eSJed Brown     ///
18659df49d7eSJed Brown     /// // Prolong
1866c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
18679df49d7eSJed Brown     ///
18689df49d7eSJed Brown     /// // Fine problem
1869c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
18709df49d7eSJed Brown     ///
18719df49d7eSJed Brown     /// // Check
1872e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
18739df49d7eSJed Brown     /// assert!(
1874392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
18759df49d7eSJed Brown     ///     "Incorrect interval length computed"
18769df49d7eSJed Brown     /// );
18779df49d7eSJed Brown     ///
18789df49d7eSJed Brown     /// // Restrict
1879c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
18809df49d7eSJed Brown     ///
18819df49d7eSJed Brown     /// // Check
1882e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
18839df49d7eSJed Brown     /// assert!(
1884392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
18859df49d7eSJed Brown     ///     "Incorrect interval length computed"
18869df49d7eSJed Brown     /// );
1887c68be7a2SJeremy L Thompson     /// # Ok(())
1888c68be7a2SJeremy L Thompson     /// # }
18899df49d7eSJed Brown     /// ```
1890594ef120SJeremy L Thompson     pub fn create_multigrid_level_tensor_H1<'b>(
18919df49d7eSJed Brown         &self,
18929df49d7eSJed Brown         p_mult_fine: &Vector,
18939df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
18949df49d7eSJed Brown         basis_coarse: &Basis,
189580a9ef05SNatalie Beams         interpCtoF: &Vec<Scalar>,
1896594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
18979df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
18989df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
18999df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
1900656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
19019df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreateTensorH1(
19029df49d7eSJed Brown                 self.op_core.ptr,
19039df49d7eSJed Brown                 p_mult_fine.ptr,
19049df49d7eSJed Brown                 rstr_coarse.ptr,
19059df49d7eSJed Brown                 basis_coarse.ptr,
19069df49d7eSJed Brown                 interpCtoF.as_ptr(),
19079df49d7eSJed Brown                 &mut ptr_coarse,
19089df49d7eSJed Brown                 &mut ptr_prolong,
19099df49d7eSJed Brown                 &mut ptr_restrict,
19109df49d7eSJed Brown             )
1911656ef1e5SJeremy L Thompson         })?;
1912*2b671a0aSJeremy L Thompson         let op_coarse = unsafe { Operator::from_raw(ptr_coarse)? };
1913*2b671a0aSJeremy L Thompson         let op_prolong = unsafe { Operator::from_raw(ptr_prolong)? };
1914*2b671a0aSJeremy L Thompson         let op_restrict = unsafe { Operator::from_raw(ptr_restrict)? };
19159df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
19169df49d7eSJed Brown     }
19179df49d7eSJed Brown 
19189df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
19199df49d7eSJed Brown     ///   given Operator with a non-tensor basis for the active basis
19209df49d7eSJed Brown     ///
19219df49d7eSJed Brown     /// * `p_mult_fine`   - Lvector multiplicity in parallel gather/scatter
19229df49d7eSJed Brown     /// * `rstr_coarse`   - Coarse grid restriction
19239df49d7eSJed Brown     /// * `basis_coarse`  - Coarse grid active vector basis
19249df49d7eSJed Brown     /// * `interp_c_to_f` - Matrix for coarse to fine
19259df49d7eSJed Brown     ///
19269df49d7eSJed Brown     /// ```
19279df49d7eSJed Brown     /// # use libceed::prelude::*;
19284d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
19299df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
19309df49d7eSJed Brown     /// let ne = 15;
19319df49d7eSJed Brown     /// let p_coarse = 3;
19329df49d7eSJed Brown     /// let p_fine = 5;
19339df49d7eSJed Brown     /// let q = 6;
19349df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
19359df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
19369df49d7eSJed Brown     ///
19379df49d7eSJed Brown     /// // Vectors
19389df49d7eSJed Brown     /// let x_array = (0..ne + 1)
193980a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
194080a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1941c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1942c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
19439df49d7eSJed Brown     /// qdata.set_value(0.0);
1944c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
19459df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1946c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
19479df49d7eSJed Brown     /// u_fine.set_value(1.0);
1948c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
19499df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1950c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
19519df49d7eSJed Brown     /// v_fine.set_value(0.0);
1952c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
19539df49d7eSJed Brown     /// multiplicity.set_value(1.0);
19549df49d7eSJed Brown     ///
19559df49d7eSJed Brown     /// // Restrictions
19569df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1957c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
19589df49d7eSJed Brown     ///
19599df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
19609df49d7eSJed Brown     /// for i in 0..ne {
19619df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
19629df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
19639df49d7eSJed Brown     /// }
1964c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
19659df49d7eSJed Brown     ///
19669df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
19679df49d7eSJed Brown     /// for i in 0..ne {
19689df49d7eSJed Brown     ///     for j in 0..p_coarse {
19699df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
19709df49d7eSJed Brown     ///     }
19719df49d7eSJed Brown     /// }
1972c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
19739df49d7eSJed Brown     ///     ne,
19749df49d7eSJed Brown     ///     p_coarse,
19759df49d7eSJed Brown     ///     1,
19769df49d7eSJed Brown     ///     1,
19779df49d7eSJed Brown     ///     ndofs_coarse,
19789df49d7eSJed Brown     ///     MemType::Host,
19799df49d7eSJed Brown     ///     &indu_coarse,
1980c68be7a2SJeremy L Thompson     /// )?;
19819df49d7eSJed Brown     ///
19829df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
19839df49d7eSJed Brown     /// for i in 0..ne {
19849df49d7eSJed Brown     ///     for j in 0..p_fine {
19859df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
19869df49d7eSJed Brown     ///     }
19879df49d7eSJed Brown     /// }
1988c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
19899df49d7eSJed Brown     ///
19909df49d7eSJed Brown     /// // Bases
1991c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1992c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1993c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
19949df49d7eSJed Brown     ///
19959df49d7eSJed Brown     /// // Build quadrature data
1996c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1997c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1998c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1999c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2000356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2001c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
20029df49d7eSJed Brown     ///
20039df49d7eSJed Brown     /// // Mass operator
2004c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
20059df49d7eSJed Brown     /// let op_mass_fine = ceed
2006c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2007c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
2008356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
2009c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
20109df49d7eSJed Brown     ///
20119df49d7eSJed Brown     /// // Multigrid setup
201280a9ef05SNatalie Beams     /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine];
20139df49d7eSJed Brown     /// {
2014c68be7a2SJeremy L Thompson     ///     let mut coarse = ceed.vector(p_coarse)?;
2015c68be7a2SJeremy L Thompson     ///     let mut fine = ceed.vector(p_fine)?;
2016c68be7a2SJeremy L Thompson     ///     let basis_c_to_f =
2017c68be7a2SJeremy L Thompson     ///         ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?;
20189df49d7eSJed Brown     ///     for i in 0..p_coarse {
20199df49d7eSJed Brown     ///         coarse.set_value(0.0);
20209df49d7eSJed Brown     ///         {
2021e78171edSJeremy L Thompson     ///             let mut array = coarse.view_mut()?;
20229df49d7eSJed Brown     ///             array[i] = 1.;
20239df49d7eSJed Brown     ///         }
2024c68be7a2SJeremy L Thompson     ///         basis_c_to_f.apply(
20259df49d7eSJed Brown     ///             1,
20269df49d7eSJed Brown     ///             TransposeMode::NoTranspose,
20279df49d7eSJed Brown     ///             EvalMode::Interp,
20289df49d7eSJed Brown     ///             &coarse,
20299df49d7eSJed Brown     ///             &mut fine,
2030c68be7a2SJeremy L Thompson     ///         )?;
2031e78171edSJeremy L Thompson     ///         let array = fine.view()?;
20329df49d7eSJed Brown     ///         for j in 0..p_fine {
20339df49d7eSJed Brown     ///             interp_c_to_f[j * p_coarse + i] = array[j];
20349df49d7eSJed Brown     ///         }
20359df49d7eSJed Brown     ///     }
20369df49d7eSJed Brown     /// }
2037c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_H1(
2038c68be7a2SJeremy L Thompson     ///     &multiplicity,
2039c68be7a2SJeremy L Thompson     ///     &ru_coarse,
2040c68be7a2SJeremy L Thompson     ///     &bu_coarse,
2041c68be7a2SJeremy L Thompson     ///     &interp_c_to_f,
2042c68be7a2SJeremy L Thompson     /// )?;
20439df49d7eSJed Brown     ///
20449df49d7eSJed Brown     /// // Coarse problem
20459df49d7eSJed Brown     /// u_coarse.set_value(1.0);
2046c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
20479df49d7eSJed Brown     ///
20489df49d7eSJed Brown     /// // Check
2049e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
20509df49d7eSJed Brown     /// assert!(
205180a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
20529df49d7eSJed Brown     ///     "Incorrect interval length computed"
20539df49d7eSJed Brown     /// );
20549df49d7eSJed Brown     ///
20559df49d7eSJed Brown     /// // Prolong
2056c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
20579df49d7eSJed Brown     ///
20589df49d7eSJed Brown     /// // Fine problem
2059c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
20609df49d7eSJed Brown     ///
20619df49d7eSJed Brown     /// // Check
2062e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
20639df49d7eSJed Brown     /// assert!(
2064392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
20659df49d7eSJed Brown     ///     "Incorrect interval length computed"
20669df49d7eSJed Brown     /// );
20679df49d7eSJed Brown     ///
20689df49d7eSJed Brown     /// // Restrict
2069c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
20709df49d7eSJed Brown     ///
20719df49d7eSJed Brown     /// // Check
2072e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
20739df49d7eSJed Brown     /// assert!(
2074392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
20759df49d7eSJed Brown     ///     "Incorrect interval length computed"
20769df49d7eSJed Brown     /// );
2077c68be7a2SJeremy L Thompson     /// # Ok(())
2078c68be7a2SJeremy L Thompson     /// # }
20799df49d7eSJed Brown     /// ```
2080594ef120SJeremy L Thompson     pub fn create_multigrid_level_H1<'b>(
20819df49d7eSJed Brown         &self,
20829df49d7eSJed Brown         p_mult_fine: &Vector,
20839df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
20849df49d7eSJed Brown         basis_coarse: &Basis,
208580a9ef05SNatalie Beams         interpCtoF: &[Scalar],
2086594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
20879df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
20889df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
20899df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
2090656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
20919df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreateH1(
20929df49d7eSJed Brown                 self.op_core.ptr,
20939df49d7eSJed Brown                 p_mult_fine.ptr,
20949df49d7eSJed Brown                 rstr_coarse.ptr,
20959df49d7eSJed Brown                 basis_coarse.ptr,
20969df49d7eSJed Brown                 interpCtoF.as_ptr(),
20979df49d7eSJed Brown                 &mut ptr_coarse,
20989df49d7eSJed Brown                 &mut ptr_prolong,
20999df49d7eSJed Brown                 &mut ptr_restrict,
21009df49d7eSJed Brown             )
2101656ef1e5SJeremy L Thompson         })?;
2102*2b671a0aSJeremy L Thompson         let op_coarse = unsafe { Operator::from_raw(ptr_coarse)? };
2103*2b671a0aSJeremy L Thompson         let op_prolong = unsafe { Operator::from_raw(ptr_prolong)? };
2104*2b671a0aSJeremy L Thompson         let op_restrict = unsafe { Operator::from_raw(ptr_restrict)? };
21059df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
21069df49d7eSJed Brown     }
21079df49d7eSJed Brown }
21089df49d7eSJed Brown 
21099df49d7eSJed Brown // -----------------------------------------------------------------------------
21109df49d7eSJed Brown // Composite Operator
21119df49d7eSJed Brown // -----------------------------------------------------------------------------
21129df49d7eSJed Brown impl<'a> CompositeOperator<'a> {
21139df49d7eSJed Brown     // Constructor
2114594ef120SJeremy L Thompson     pub fn create(ceed: &crate::Ceed) -> crate::Result<Self> {
21159df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
2116656ef1e5SJeremy L Thompson         ceed.check_error(unsafe { bind_ceed::CeedCompositeOperatorCreate(ceed.ptr, &mut ptr) })?;
21179df49d7eSJed Brown         Ok(Self {
21181142270cSJeremy L Thompson             op_core: OperatorCore {
21191142270cSJeremy L Thompson                 ptr,
21201142270cSJeremy L Thompson                 _lifeline: PhantomData,
21211142270cSJeremy L Thompson             },
21229df49d7eSJed Brown         })
21239df49d7eSJed Brown     }
21249df49d7eSJed Brown 
2125ea6b5821SJeremy L Thompson     /// Set name for CompositeOperator printing
2126ea6b5821SJeremy L Thompson     ///
2127ea6b5821SJeremy L Thompson     /// * 'name' - Name to set
2128ea6b5821SJeremy L Thompson     ///
2129ea6b5821SJeremy L Thompson     /// ```
2130ea6b5821SJeremy L Thompson     /// # use libceed::prelude::*;
2131ea6b5821SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
2132ea6b5821SJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
2133ea6b5821SJeremy L Thompson     ///
2134ea6b5821SJeremy L Thompson     /// // Sub operator field arguments
2135ea6b5821SJeremy L Thompson     /// let ne = 3;
2136ea6b5821SJeremy L Thompson     /// let q = 4 as usize;
2137ea6b5821SJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
2138ea6b5821SJeremy L Thompson     /// for i in 0..ne {
2139ea6b5821SJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
2140ea6b5821SJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
2141ea6b5821SJeremy L Thompson     /// }
2142ea6b5821SJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
2143ea6b5821SJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2144d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
2145ea6b5821SJeremy L Thompson     ///
2146ea6b5821SJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2147ea6b5821SJeremy L Thompson     ///
2148ea6b5821SJeremy L Thompson     /// let qdata_mass = ceed.vector(q * ne)?;
2149ea6b5821SJeremy L Thompson     /// let qdata_diff = ceed.vector(q * ne)?;
2150ea6b5821SJeremy L Thompson     ///
2151ea6b5821SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
2152ea6b5821SJeremy L Thompson     /// let op_mass = ceed
2153ea6b5821SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2154ea6b5821SJeremy L Thompson     ///     .name("Mass term")?
2155ea6b5821SJeremy L Thompson     ///     .field("u", &r, &b, VectorOpt::Active)?
2156356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2157ea6b5821SJeremy L Thompson     ///     .field("v", &r, &b, VectorOpt::Active)?;
2158ea6b5821SJeremy L Thompson     ///
2159ea6b5821SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
2160ea6b5821SJeremy L Thompson     /// let op_diff = ceed
2161ea6b5821SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2162ea6b5821SJeremy L Thompson     ///     .name("Poisson term")?
2163ea6b5821SJeremy L Thompson     ///     .field("du", &r, &b, VectorOpt::Active)?
2164356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2165ea6b5821SJeremy L Thompson     ///     .field("dv", &r, &b, VectorOpt::Active)?;
2166ea6b5821SJeremy L Thompson     ///
2167ea6b5821SJeremy L Thompson     /// let op = ceed
2168ea6b5821SJeremy L Thompson     ///     .composite_operator()?
2169ea6b5821SJeremy L Thompson     ///     .name("Screened Poisson")?
2170ea6b5821SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2171ea6b5821SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
2172ea6b5821SJeremy L Thompson     /// # Ok(())
2173ea6b5821SJeremy L Thompson     /// # }
2174ea6b5821SJeremy L Thompson     /// ```
2175ea6b5821SJeremy L Thompson     #[allow(unused_mut)]
2176ea6b5821SJeremy L Thompson     pub fn name(mut self, name: &str) -> crate::Result<Self> {
2177ea6b5821SJeremy L Thompson         self.op_core.name(name)?;
2178ea6b5821SJeremy L Thompson         Ok(self)
2179ea6b5821SJeremy L Thompson     }
2180ea6b5821SJeremy L Thompson 
21819df49d7eSJed Brown     /// Apply Operator to a vector
21829df49d7eSJed Brown     ///
2183ea6b5821SJeremy L Thompson     /// * `input`  - Inpuht Vector
21849df49d7eSJed Brown     /// * `output` - Output Vector
21859df49d7eSJed Brown     ///
21869df49d7eSJed Brown     /// ```
21879df49d7eSJed Brown     /// # use libceed::prelude::*;
21884d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
21899df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
21909df49d7eSJed Brown     /// let ne = 4;
21919df49d7eSJed Brown     /// let p = 3;
21929df49d7eSJed Brown     /// let q = 4;
21939df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
21949df49d7eSJed Brown     ///
21959df49d7eSJed Brown     /// // Vectors
2196c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
2197c68be7a2SJeremy L Thompson     /// let mut qdata_mass = ceed.vector(ne * q)?;
21989df49d7eSJed Brown     /// qdata_mass.set_value(0.0);
2199c68be7a2SJeremy L Thompson     /// let mut qdata_diff = ceed.vector(ne * q)?;
22009df49d7eSJed Brown     /// qdata_diff.set_value(0.0);
2201c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
22029df49d7eSJed Brown     /// u.set_value(1.0);
2203c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
22049df49d7eSJed Brown     /// v.set_value(0.0);
22059df49d7eSJed Brown     ///
22069df49d7eSJed Brown     /// // Restrictions
22079df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
22089df49d7eSJed Brown     /// for i in 0..ne {
22099df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
22109df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
22119df49d7eSJed Brown     /// }
2212c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
22139df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
22149df49d7eSJed Brown     /// for i in 0..ne {
22159df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
22169df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
22179df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
22189df49d7eSJed Brown     /// }
2219c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
22209df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2221c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
22229df49d7eSJed Brown     ///
22239df49d7eSJed Brown     /// // Bases
2224c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2225c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
22269df49d7eSJed Brown     ///
22279df49d7eSJed Brown     /// // Build quadrature data
2228c68be7a2SJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
2229c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
2230c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2231c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2232356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2233c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_mass)?;
22349df49d7eSJed Brown     ///
2235c68be7a2SJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
2236c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
2237c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2238c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2239356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2240c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_diff)?;
22419df49d7eSJed Brown     ///
22429df49d7eSJed Brown     /// // Application operator
2243c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
22449df49d7eSJed Brown     /// let op_mass = ceed
2245c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2246c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
2247356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2248c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
22499df49d7eSJed Brown     ///
2250c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
22519df49d7eSJed Brown     /// let op_diff = ceed
2252c68be7a2SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2253c68be7a2SJeremy L Thompson     ///     .field("du", &ru, &bu, VectorOpt::Active)?
2254356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2255c68be7a2SJeremy L Thompson     ///     .field("dv", &ru, &bu, VectorOpt::Active)?;
22569df49d7eSJed Brown     ///
22579df49d7eSJed Brown     /// let op_composite = ceed
2258c68be7a2SJeremy L Thompson     ///     .composite_operator()?
2259c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2260c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
22619df49d7eSJed Brown     ///
22629df49d7eSJed Brown     /// v.set_value(0.0);
2263c68be7a2SJeremy L Thompson     /// op_composite.apply(&u, &mut v)?;
22649df49d7eSJed Brown     ///
22659df49d7eSJed Brown     /// // Check
2266e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
22679df49d7eSJed Brown     /// assert!(
226880a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
22699df49d7eSJed Brown     ///     "Incorrect interval length computed"
22709df49d7eSJed Brown     /// );
2271c68be7a2SJeremy L Thompson     /// # Ok(())
2272c68be7a2SJeremy L Thompson     /// # }
22739df49d7eSJed Brown     /// ```
22749df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
22759df49d7eSJed Brown         self.op_core.apply(input, output)
22769df49d7eSJed Brown     }
22779df49d7eSJed Brown 
22789df49d7eSJed Brown     /// Apply Operator to a vector and add result to output vector
22799df49d7eSJed Brown     ///
22809df49d7eSJed Brown     /// * `input`  - Input Vector
22819df49d7eSJed Brown     /// * `output` - Output Vector
22829df49d7eSJed Brown     ///
22839df49d7eSJed Brown     /// ```
22849df49d7eSJed Brown     /// # use libceed::prelude::*;
22854d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
22869df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
22879df49d7eSJed Brown     /// let ne = 4;
22889df49d7eSJed Brown     /// let p = 3;
22899df49d7eSJed Brown     /// let q = 4;
22909df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
22919df49d7eSJed Brown     ///
22929df49d7eSJed Brown     /// // Vectors
2293c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
2294c68be7a2SJeremy L Thompson     /// let mut qdata_mass = ceed.vector(ne * q)?;
22959df49d7eSJed Brown     /// qdata_mass.set_value(0.0);
2296c68be7a2SJeremy L Thompson     /// let mut qdata_diff = ceed.vector(ne * q)?;
22979df49d7eSJed Brown     /// qdata_diff.set_value(0.0);
2298c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
22999df49d7eSJed Brown     /// u.set_value(1.0);
2300c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
23019df49d7eSJed Brown     /// v.set_value(0.0);
23029df49d7eSJed Brown     ///
23039df49d7eSJed Brown     /// // Restrictions
23049df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
23059df49d7eSJed Brown     /// for i in 0..ne {
23069df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
23079df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
23089df49d7eSJed Brown     /// }
2309c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
23109df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
23119df49d7eSJed Brown     /// for i in 0..ne {
23129df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
23139df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
23149df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
23159df49d7eSJed Brown     /// }
2316c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
23179df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2318c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
23199df49d7eSJed Brown     ///
23209df49d7eSJed Brown     /// // Bases
2321c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2322c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
23239df49d7eSJed Brown     ///
23249df49d7eSJed Brown     /// // Build quadrature data
2325c68be7a2SJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
2326c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
2327c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2328c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2329356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2330c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_mass)?;
23319df49d7eSJed Brown     ///
2332c68be7a2SJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
2333c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
2334c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2335c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2336356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2337c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_diff)?;
23389df49d7eSJed Brown     ///
23399df49d7eSJed Brown     /// // Application operator
2340c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
23419df49d7eSJed Brown     /// let op_mass = ceed
2342c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2343c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
2344356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2345c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
23469df49d7eSJed Brown     ///
2347c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
23489df49d7eSJed Brown     /// let op_diff = ceed
2349c68be7a2SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2350c68be7a2SJeremy L Thompson     ///     .field("du", &ru, &bu, VectorOpt::Active)?
2351356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2352c68be7a2SJeremy L Thompson     ///     .field("dv", &ru, &bu, VectorOpt::Active)?;
23539df49d7eSJed Brown     ///
23549df49d7eSJed Brown     /// let op_composite = ceed
2355c68be7a2SJeremy L Thompson     ///     .composite_operator()?
2356c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2357c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
23589df49d7eSJed Brown     ///
23599df49d7eSJed Brown     /// v.set_value(1.0);
2360c68be7a2SJeremy L Thompson     /// op_composite.apply_add(&u, &mut v)?;
23619df49d7eSJed Brown     ///
23629df49d7eSJed Brown     /// // Check
2363e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
23649df49d7eSJed Brown     /// assert!(
236580a9ef05SNatalie Beams     ///     (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON,
23669df49d7eSJed Brown     ///     "Incorrect interval length computed"
23679df49d7eSJed Brown     /// );
2368c68be7a2SJeremy L Thompson     /// # Ok(())
2369c68be7a2SJeremy L Thompson     /// # }
23709df49d7eSJed Brown     /// ```
23719df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
23729df49d7eSJed Brown         self.op_core.apply_add(input, output)
23739df49d7eSJed Brown     }
23749df49d7eSJed Brown 
23759df49d7eSJed Brown     /// Add a sub-Operator to a Composite Operator
23769df49d7eSJed Brown     ///
23779df49d7eSJed Brown     /// * `subop` - Sub-Operator
23789df49d7eSJed Brown     ///
23799df49d7eSJed Brown     /// ```
23809df49d7eSJed Brown     /// # use libceed::prelude::*;
23814d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
23829df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
2383c68be7a2SJeremy L Thompson     /// let mut op = ceed.composite_operator()?;
23849df49d7eSJed Brown     ///
2385c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
2386c68be7a2SJeremy L Thompson     /// let op_mass = ceed.operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?;
2387c68be7a2SJeremy L Thompson     /// op = op.sub_operator(&op_mass)?;
23889df49d7eSJed Brown     ///
2389c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
2390c68be7a2SJeremy L Thompson     /// let op_diff = ceed.operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?;
2391c68be7a2SJeremy L Thompson     /// op = op.sub_operator(&op_diff)?;
2392c68be7a2SJeremy L Thompson     /// # Ok(())
2393c68be7a2SJeremy L Thompson     /// # }
23949df49d7eSJed Brown     /// ```
23959df49d7eSJed Brown     #[allow(unused_mut)]
23969df49d7eSJed Brown     pub fn sub_operator(mut self, subop: &Operator) -> crate::Result<Self> {
2397656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
2398656ef1e5SJeremy L Thompson             bind_ceed::CeedCompositeOperatorAddSub(self.op_core.ptr, subop.op_core.ptr)
2399656ef1e5SJeremy L Thompson         })?;
24009df49d7eSJed Brown         Ok(self)
24019df49d7eSJed Brown     }
24029df49d7eSJed Brown 
24036f97ff0aSJeremy L Thompson     /// Check if CompositeOperator is setup correctly
24046f97ff0aSJeremy L Thompson     ///
24056f97ff0aSJeremy L Thompson     /// ```
24066f97ff0aSJeremy L Thompson     /// # use libceed::prelude::*;
24076f97ff0aSJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
24086f97ff0aSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
24096f97ff0aSJeremy L Thompson     /// let ne = 4;
24106f97ff0aSJeremy L Thompson     /// let p = 3;
24116f97ff0aSJeremy L Thompson     /// let q = 4;
24126f97ff0aSJeremy L Thompson     /// let ndofs = p * ne - ne + 1;
24136f97ff0aSJeremy L Thompson     ///
24146f97ff0aSJeremy L Thompson     /// // Restrictions
24156f97ff0aSJeremy L Thompson     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
24166f97ff0aSJeremy L Thompson     /// for i in 0..ne {
24176f97ff0aSJeremy L Thompson     ///     indx[2 * i + 0] = i as i32;
24186f97ff0aSJeremy L Thompson     ///     indx[2 * i + 1] = (i + 1) as i32;
24196f97ff0aSJeremy L Thompson     /// }
24206f97ff0aSJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
24216f97ff0aSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
24226f97ff0aSJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
24236f97ff0aSJeremy L Thompson     ///
24246f97ff0aSJeremy L Thompson     /// // Bases
24256f97ff0aSJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
24266f97ff0aSJeremy L Thompson     ///
24276f97ff0aSJeremy L Thompson     /// // Build quadrature data
24286f97ff0aSJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
24296f97ff0aSJeremy L Thompson     /// let op_build_mass = ceed
24306f97ff0aSJeremy L Thompson     ///     .operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
24316f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
24326f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2433356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
24346f97ff0aSJeremy L Thompson     ///
24356f97ff0aSJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
24366f97ff0aSJeremy L Thompson     /// let op_build_diff = ceed
24376f97ff0aSJeremy L Thompson     ///     .operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
24386f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
24396f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2440356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
24416f97ff0aSJeremy L Thompson     ///
24426f97ff0aSJeremy L Thompson     /// let op_build = ceed
24436f97ff0aSJeremy L Thompson     ///     .composite_operator()?
24446f97ff0aSJeremy L Thompson     ///     .sub_operator(&op_build_mass)?
24456f97ff0aSJeremy L Thompson     ///     .sub_operator(&op_build_diff)?;
24466f97ff0aSJeremy L Thompson     ///
24476f97ff0aSJeremy L Thompson     /// // Check
24486f97ff0aSJeremy L Thompson     /// assert!(op_build.check().is_ok(), "Operator setup incorrectly");
24496f97ff0aSJeremy L Thompson     /// # Ok(())
24506f97ff0aSJeremy L Thompson     /// # }
24516f97ff0aSJeremy L Thompson     /// ```
24526f97ff0aSJeremy L Thompson     pub fn check(self) -> crate::Result<Self> {
24536f97ff0aSJeremy L Thompson         self.op_core.check()?;
24546f97ff0aSJeremy L Thompson         Ok(self)
24556f97ff0aSJeremy L Thompson     }
24566f97ff0aSJeremy L Thompson 
24579df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
24589df49d7eSJed Brown     ///
24599df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
24609df49d7eSJed Brown     ///
24619df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24629df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24639df49d7eSJed Brown     ///
24649df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24659df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
2466b748b478SJeremy L Thompson     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
24679df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
24689df49d7eSJed Brown     }
24699df49d7eSJed Brown 
24709df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
24719df49d7eSJed Brown     ///
24729df49d7eSJed Brown     /// This overwrites a Vector with the point block diagonal of a linear
24739df49d7eSJed Brown     ///   Operator.
24749df49d7eSJed Brown     ///
24759df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24769df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24779df49d7eSJed Brown     ///
24789df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24799df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
24809df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
24819df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
24829df49d7eSJed Brown     }
24839df49d7eSJed Brown 
24849df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
24859df49d7eSJed Brown     ///
24869df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
24879df49d7eSJed Brown     ///
24889df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24899df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24909df49d7eSJed Brown     ///
24919df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24929df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
24939df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
24949df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
24959df49d7eSJed Brown     ///                   this vector are derived from the active vector for
24969df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
24979df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
24989df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
24999df49d7eSJed Brown         &self,
25009df49d7eSJed Brown         assembled: &mut Vector,
25019df49d7eSJed Brown     ) -> crate::Result<i32> {
25029df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
25039df49d7eSJed Brown     }
25049df49d7eSJed Brown 
25059df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
25069df49d7eSJed Brown     ///
25079df49d7eSJed Brown     /// This sums into a Vector with the diagonal of a linear Operator.
25089df49d7eSJed Brown     ///
25099df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
25109df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
25119df49d7eSJed Brown     ///
25129df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
25139df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
25149df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
25159df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
25169df49d7eSJed Brown     ///                   this vector are derived from the active vector for
25179df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
25189df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
25199df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
25209df49d7eSJed Brown         &self,
25219df49d7eSJed Brown         assembled: &mut Vector,
25229df49d7eSJed Brown     ) -> crate::Result<i32> {
25239df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
25249df49d7eSJed Brown     }
25259df49d7eSJed Brown }
25269df49d7eSJed Brown 
25279df49d7eSJed Brown // -----------------------------------------------------------------------------
2528