xref: /libCEED/rust/libceed/src/operator.rs (revision ed094490f53e580908aa80e9fe815a6fd76d7526)
1d275d636SJeremy L Thompson // Copyright (c) 2017-2025, 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 
12eb07d68fSJeremy L Thompson use crate::{
13eb07d68fSJeremy L Thompson     basis::{Basis, BasisOpt},
14eb07d68fSJeremy L Thompson     elem_restriction::{ElemRestriction, ElemRestrictionOpt},
15eb07d68fSJeremy L Thompson     prelude::*,
16eb07d68fSJeremy L Thompson     qfunction::QFunctionOpt,
17eb07d68fSJeremy L Thompson     vector::{Vector, VectorOpt},
18eb07d68fSJeremy L Thompson };
199df49d7eSJed Brown 
209df49d7eSJed Brown // -----------------------------------------------------------------------------
217ed177dbSJed Brown // Operator Field context wrapper
2208778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
2308778c6fSJeremy L Thompson #[derive(Debug)]
2408778c6fSJeremy L Thompson pub struct OperatorField<'a> {
2508778c6fSJeremy L Thompson     pub(crate) ptr: bind_ceed::CeedOperatorField,
26e03fef56SJeremy L Thompson     pub(crate) vector: crate::Vector<'a>,
27e03fef56SJeremy L Thompson     pub(crate) elem_restriction: crate::ElemRestriction<'a>,
28e03fef56SJeremy L Thompson     pub(crate) basis: crate::Basis<'a>,
2908778c6fSJeremy L Thompson     _lifeline: PhantomData<&'a ()>,
3008778c6fSJeremy L Thompson }
3108778c6fSJeremy L Thompson 
3208778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
3308778c6fSJeremy L Thompson // Implementations
3408778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
3508778c6fSJeremy L Thompson impl<'a> OperatorField<'a> {
362b671a0aSJeremy L Thompson     pub(crate) unsafe fn from_raw(
37e03fef56SJeremy L Thompson         ptr: bind_ceed::CeedOperatorField,
38e03fef56SJeremy L Thompson         ceed: crate::Ceed,
39e03fef56SJeremy L Thompson     ) -> crate::Result<Self> {
40e03fef56SJeremy L Thompson         let vector = {
41e03fef56SJeremy L Thompson             let mut vector_ptr = std::ptr::null_mut();
422b671a0aSJeremy L Thompson             ceed.check_error(bind_ceed::CeedOperatorFieldGetVector(ptr, &mut vector_ptr))?;
43e03fef56SJeremy L Thompson             crate::Vector::from_raw(vector_ptr)?
44e03fef56SJeremy L Thompson         };
45e03fef56SJeremy L Thompson         let elem_restriction = {
46e03fef56SJeremy L Thompson             let mut elem_restriction_ptr = std::ptr::null_mut();
472b671a0aSJeremy L Thompson             ceed.check_error(bind_ceed::CeedOperatorFieldGetElemRestriction(
482b671a0aSJeremy L Thompson                 ptr,
492b671a0aSJeremy L Thompson                 &mut elem_restriction_ptr,
502b671a0aSJeremy L Thompson             ))?;
51e03fef56SJeremy L Thompson             crate::ElemRestriction::from_raw(elem_restriction_ptr)?
52e03fef56SJeremy L Thompson         };
53e03fef56SJeremy L Thompson         let basis = {
54e03fef56SJeremy L Thompson             let mut basis_ptr = std::ptr::null_mut();
552b671a0aSJeremy L Thompson             ceed.check_error(bind_ceed::CeedOperatorFieldGetBasis(ptr, &mut basis_ptr))?;
56e03fef56SJeremy L Thompson             crate::Basis::from_raw(basis_ptr)?
57e03fef56SJeremy L Thompson         };
58e03fef56SJeremy L Thompson         Ok(Self {
59e03fef56SJeremy L Thompson             ptr,
60e03fef56SJeremy L Thompson             vector,
61e03fef56SJeremy L Thompson             elem_restriction,
62e03fef56SJeremy L Thompson             basis,
63e03fef56SJeremy L Thompson             _lifeline: PhantomData,
64e03fef56SJeremy L Thompson         })
65e03fef56SJeremy L Thompson     }
66e03fef56SJeremy L Thompson 
6708778c6fSJeremy L Thompson     /// Get the name of an OperatorField
6808778c6fSJeremy L Thompson     ///
6908778c6fSJeremy L Thompson     /// ```
70eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
714d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
7208778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
7308778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
7408778c6fSJeremy L Thompson     ///
7508778c6fSJeremy L Thompson     /// // Operator field arguments
7608778c6fSJeremy L Thompson     /// let ne = 3;
77bf55b007SJeremy L Thompson     /// let q = 4_usize;
7808778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
7908778c6fSJeremy L Thompson     /// for i in 0..ne {
8008778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
8108778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
8208778c6fSJeremy L Thompson     /// }
8308778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
8408778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
85d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
8608778c6fSJeremy L Thompson     ///
8708778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
8808778c6fSJeremy L Thompson     ///
8908778c6fSJeremy L Thompson     /// // Operator fields
9008778c6fSJeremy L Thompson     /// let op = ceed
9108778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
9208778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
9308778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
94356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
9508778c6fSJeremy L Thompson     ///
9608778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
9708778c6fSJeremy L Thompson     ///
9808778c6fSJeremy L Thompson     /// assert_eq!(inputs[0].name(), "dx", "Incorrect input name");
9908778c6fSJeremy L Thompson     /// assert_eq!(inputs[1].name(), "weights", "Incorrect input name");
10008778c6fSJeremy L Thompson     /// # Ok(())
10108778c6fSJeremy L Thompson     /// # }
10208778c6fSJeremy L Thompson     /// ```
10308778c6fSJeremy L Thompson     pub fn name(&self) -> &str {
10408778c6fSJeremy L Thompson         let mut name_ptr: *mut std::os::raw::c_char = std::ptr::null_mut();
10508778c6fSJeremy L Thompson         unsafe {
1066f8994e9SJeremy L Thompson             bind_ceed::CeedOperatorFieldGetName(
1076f8994e9SJeremy L Thompson                 self.ptr,
1086f8994e9SJeremy L Thompson                 &mut name_ptr as *const _ as *mut *const _,
1096f8994e9SJeremy L Thompson             );
11008778c6fSJeremy L Thompson         }
11108778c6fSJeremy L Thompson         unsafe { CStr::from_ptr(name_ptr) }.to_str().unwrap()
11208778c6fSJeremy L Thompson     }
11308778c6fSJeremy L Thompson 
11408778c6fSJeremy L Thompson     /// Get the ElemRestriction of an OperatorField
11508778c6fSJeremy L Thompson     ///
11608778c6fSJeremy L Thompson     /// ```
117eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
1184d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
11908778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
12008778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
12108778c6fSJeremy L Thompson     ///
12208778c6fSJeremy L Thompson     /// // Operator field arguments
12308778c6fSJeremy L Thompson     /// let ne = 3;
124bf55b007SJeremy L Thompson     /// let q = 4_usize;
12508778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
12608778c6fSJeremy L Thompson     /// for i in 0..ne {
12708778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
12808778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
12908778c6fSJeremy L Thompson     /// }
13008778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
13108778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
132d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
13308778c6fSJeremy L Thompson     ///
13408778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
13508778c6fSJeremy L Thompson     ///
13608778c6fSJeremy L Thompson     /// // Operator fields
13708778c6fSJeremy L Thompson     /// let op = ceed
13808778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
13908778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
14008778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
141356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
14208778c6fSJeremy L Thompson     ///
14308778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
14408778c6fSJeremy L Thompson     ///
14508778c6fSJeremy L Thompson     /// assert!(
14608778c6fSJeremy L Thompson     ///     inputs[0].elem_restriction().is_some(),
14708778c6fSJeremy L Thompson     ///     "Incorrect field ElemRestriction"
14808778c6fSJeremy L Thompson     /// );
149567c3c29SJeremy L Thompson     /// if let ElemRestrictionOpt::Some(r) = inputs[0].elem_restriction() {
150567c3c29SJeremy L Thompson     ///     assert_eq!(
151567c3c29SJeremy L Thompson     ///         r.num_elements(),
152567c3c29SJeremy L Thompson     ///         ne,
153567c3c29SJeremy L Thompson     ///         "Incorrect field ElemRestriction number of elements"
154567c3c29SJeremy L Thompson     ///     );
155567c3c29SJeremy L Thompson     /// }
156567c3c29SJeremy L Thompson     ///
15708778c6fSJeremy L Thompson     /// assert!(
15808778c6fSJeremy L Thompson     ///     inputs[1].elem_restriction().is_none(),
15908778c6fSJeremy L Thompson     ///     "Incorrect field ElemRestriction"
16008778c6fSJeremy L Thompson     /// );
161e03fef56SJeremy L Thompson     ///
162e03fef56SJeremy L Thompson     /// let outputs = op.outputs()?;
163e03fef56SJeremy L Thompson     ///
164e03fef56SJeremy L Thompson     /// assert!(
165e03fef56SJeremy L Thompson     ///     outputs[0].elem_restriction().is_some(),
166e03fef56SJeremy L Thompson     ///     "Incorrect field ElemRestriction"
167e03fef56SJeremy L Thompson     /// );
168567c3c29SJeremy L Thompson     /// if let ElemRestrictionOpt::Some(r) = outputs[0].elem_restriction() {
169567c3c29SJeremy L Thompson     ///     assert_eq!(
170567c3c29SJeremy L Thompson     ///         r.num_elements(),
171567c3c29SJeremy L Thompson     ///         ne,
172567c3c29SJeremy L Thompson     ///         "Incorrect field ElemRestriction number of elements"
173567c3c29SJeremy L Thompson     ///     );
174567c3c29SJeremy L Thompson     /// }
17508778c6fSJeremy L Thompson     /// # Ok(())
17608778c6fSJeremy L Thompson     /// # }
17708778c6fSJeremy L Thompson     /// ```
17808778c6fSJeremy L Thompson     pub fn elem_restriction(&self) -> ElemRestrictionOpt {
179e03fef56SJeremy L Thompson         if self.elem_restriction.ptr == unsafe { bind_ceed::CEED_ELEMRESTRICTION_NONE } {
18008778c6fSJeremy L Thompson             ElemRestrictionOpt::None
18108778c6fSJeremy L Thompson         } else {
182e03fef56SJeremy L Thompson             ElemRestrictionOpt::Some(&self.elem_restriction)
18308778c6fSJeremy L Thompson         }
18408778c6fSJeremy L Thompson     }
18508778c6fSJeremy L Thompson 
18608778c6fSJeremy L Thompson     /// Get the Basis of an OperatorField
18708778c6fSJeremy L Thompson     ///
18808778c6fSJeremy L Thompson     /// ```
189eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
1904d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
19108778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
19208778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
19308778c6fSJeremy L Thompson     ///
19408778c6fSJeremy L Thompson     /// // Operator field arguments
19508778c6fSJeremy L Thompson     /// let ne = 3;
196bf55b007SJeremy L Thompson     /// let q = 4_usize;
19708778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
19808778c6fSJeremy L Thompson     /// for i in 0..ne {
19908778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
20008778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
20108778c6fSJeremy L Thompson     /// }
20208778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
20308778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
204d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
20508778c6fSJeremy L Thompson     ///
20608778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
20708778c6fSJeremy L Thompson     ///
20808778c6fSJeremy L Thompson     /// // Operator fields
20908778c6fSJeremy L Thompson     /// let op = ceed
21008778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
21108778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
21208778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
213356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
21408778c6fSJeremy L Thompson     ///
21508778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
21608778c6fSJeremy L Thompson     ///
21708778c6fSJeremy L Thompson     /// assert!(inputs[0].basis().is_some(), "Incorrect field Basis");
218567c3c29SJeremy L Thompson     /// if let BasisOpt::Some(b) = inputs[0].basis() {
219567c3c29SJeremy L Thompson     ///     assert_eq!(
220567c3c29SJeremy L Thompson     ///         b.num_quadrature_points(),
221567c3c29SJeremy L Thompson     ///         q,
222567c3c29SJeremy L Thompson     ///         "Incorrect field Basis number of quadrature points"
223567c3c29SJeremy L Thompson     ///     );
224567c3c29SJeremy L Thompson     /// }
22508778c6fSJeremy L Thompson     /// assert!(inputs[1].basis().is_some(), "Incorrect field Basis");
226567c3c29SJeremy L Thompson     /// if let BasisOpt::Some(b) = inputs[1].basis() {
227567c3c29SJeremy L Thompson     ///     assert_eq!(
228567c3c29SJeremy L Thompson     ///         b.num_quadrature_points(),
229567c3c29SJeremy L Thompson     ///         q,
230567c3c29SJeremy L Thompson     ///         "Incorrect field Basis number of quadrature points"
231567c3c29SJeremy L Thompson     ///     );
232567c3c29SJeremy L Thompson     /// }
23308778c6fSJeremy L Thompson     ///
23408778c6fSJeremy L Thompson     /// let outputs = op.outputs()?;
23508778c6fSJeremy L Thompson     ///
236356036faSJeremy L Thompson     /// assert!(outputs[0].basis().is_none(), "Incorrect field Basis");
23708778c6fSJeremy L Thompson     /// # Ok(())
23808778c6fSJeremy L Thompson     /// # }
23908778c6fSJeremy L Thompson     /// ```
24008778c6fSJeremy L Thompson     pub fn basis(&self) -> BasisOpt {
241e03fef56SJeremy L Thompson         if self.basis.ptr == unsafe { bind_ceed::CEED_BASIS_NONE } {
242356036faSJeremy L Thompson             BasisOpt::None
24308778c6fSJeremy L Thompson         } else {
244e03fef56SJeremy L Thompson             BasisOpt::Some(&self.basis)
24508778c6fSJeremy L Thompson         }
24608778c6fSJeremy L Thompson     }
24708778c6fSJeremy L Thompson 
24808778c6fSJeremy L Thompson     /// Get the Vector of an OperatorField
24908778c6fSJeremy L Thompson     ///
25008778c6fSJeremy L Thompson     /// ```
251eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
2524d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
25308778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
25408778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
25508778c6fSJeremy L Thompson     ///
25608778c6fSJeremy L Thompson     /// // Operator field arguments
25708778c6fSJeremy L Thompson     /// let ne = 3;
258bf55b007SJeremy L Thompson     /// let q = 4_usize;
25908778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
26008778c6fSJeremy L Thompson     /// for i in 0..ne {
26108778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
26208778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
26308778c6fSJeremy L Thompson     /// }
26408778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
26508778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
266d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
26708778c6fSJeremy L Thompson     ///
26808778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
26908778c6fSJeremy L Thompson     ///
27008778c6fSJeremy L Thompson     /// // Operator fields
27108778c6fSJeremy L Thompson     /// let op = ceed
27208778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
27308778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
27408778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
275356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
27608778c6fSJeremy L Thompson     ///
27708778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
27808778c6fSJeremy L Thompson     ///
27908778c6fSJeremy L Thompson     /// assert!(inputs[0].vector().is_active(), "Incorrect field Vector");
28008778c6fSJeremy L Thompson     /// assert!(inputs[1].vector().is_none(), "Incorrect field Vector");
281e03fef56SJeremy L Thompson     ///
282e03fef56SJeremy L Thompson     /// let outputs = op.outputs()?;
283e03fef56SJeremy L Thompson     ///
284e03fef56SJeremy L Thompson     /// assert!(outputs[0].vector().is_active(), "Incorrect field Vector");
28508778c6fSJeremy L Thompson     /// # Ok(())
28608778c6fSJeremy L Thompson     /// # }
28708778c6fSJeremy L Thompson     /// ```
28808778c6fSJeremy L Thompson     pub fn vector(&self) -> VectorOpt {
289e03fef56SJeremy L Thompson         if self.vector.ptr == unsafe { bind_ceed::CEED_VECTOR_ACTIVE } {
29008778c6fSJeremy L Thompson             VectorOpt::Active
291e03fef56SJeremy L Thompson         } else if self.vector.ptr == unsafe { bind_ceed::CEED_VECTOR_NONE } {
29208778c6fSJeremy L Thompson             VectorOpt::None
29308778c6fSJeremy L Thompson         } else {
294e03fef56SJeremy L Thompson             VectorOpt::Some(&self.vector)
29508778c6fSJeremy L Thompson         }
29608778c6fSJeremy L Thompson     }
29708778c6fSJeremy L Thompson }
29808778c6fSJeremy L Thompson 
29908778c6fSJeremy L Thompson // -----------------------------------------------------------------------------
3007ed177dbSJed Brown // Operator context wrapper
3019df49d7eSJed Brown // -----------------------------------------------------------------------------
302c68be7a2SJeremy L Thompson #[derive(Debug)]
3039df49d7eSJed Brown pub(crate) struct OperatorCore<'a> {
3049df49d7eSJed Brown     ptr: bind_ceed::CeedOperator,
3051142270cSJeremy L Thompson     _lifeline: PhantomData<&'a ()>,
3069df49d7eSJed Brown }
3079df49d7eSJed Brown 
308c68be7a2SJeremy L Thompson #[derive(Debug)]
3099df49d7eSJed Brown pub struct Operator<'a> {
3109df49d7eSJed Brown     op_core: OperatorCore<'a>,
3119df49d7eSJed Brown }
3129df49d7eSJed Brown 
313c68be7a2SJeremy L Thompson #[derive(Debug)]
3149df49d7eSJed Brown pub struct CompositeOperator<'a> {
3159df49d7eSJed Brown     op_core: OperatorCore<'a>,
3169df49d7eSJed Brown }
3179df49d7eSJed Brown 
3189df49d7eSJed Brown // -----------------------------------------------------------------------------
3199df49d7eSJed Brown // Destructor
3209df49d7eSJed Brown // -----------------------------------------------------------------------------
3219df49d7eSJed Brown impl<'a> Drop for OperatorCore<'a> {
3229df49d7eSJed Brown     fn drop(&mut self) {
3239df49d7eSJed Brown         unsafe {
3249df49d7eSJed Brown             bind_ceed::CeedOperatorDestroy(&mut self.ptr);
3259df49d7eSJed Brown         }
3269df49d7eSJed Brown     }
3279df49d7eSJed Brown }
3289df49d7eSJed Brown 
3299df49d7eSJed Brown // -----------------------------------------------------------------------------
3309df49d7eSJed Brown // Display
3319df49d7eSJed Brown // -----------------------------------------------------------------------------
3329df49d7eSJed Brown impl<'a> fmt::Display for OperatorCore<'a> {
3339df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3349df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
3359df49d7eSJed Brown         let mut sizeloc = crate::MAX_BUFFER_LENGTH;
3369df49d7eSJed Brown         let cstring = unsafe {
3379df49d7eSJed Brown             let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc);
3389df49d7eSJed Brown             bind_ceed::CeedOperatorView(self.ptr, file);
3399df49d7eSJed Brown             bind_ceed::fclose(file);
3409df49d7eSJed Brown             CString::from_raw(ptr)
3419df49d7eSJed Brown         };
3429df49d7eSJed Brown         cstring.to_string_lossy().fmt(f)
3439df49d7eSJed Brown     }
3449df49d7eSJed Brown }
3459df49d7eSJed Brown 
3469df49d7eSJed Brown /// View an Operator
3479df49d7eSJed Brown ///
3489df49d7eSJed Brown /// ```
349eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
3504d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
3519df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
352c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
3539df49d7eSJed Brown ///
3549df49d7eSJed Brown /// // Operator field arguments
3559df49d7eSJed Brown /// let ne = 3;
356bf55b007SJeremy L Thompson /// let q = 4_usize;
3579df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne];
3589df49d7eSJed Brown /// for i in 0..ne {
3599df49d7eSJed Brown ///     ind[2 * i + 0] = i as i32;
3609df49d7eSJed Brown ///     ind[2 * i + 1] = (i + 1) as i32;
3619df49d7eSJed Brown /// }
362c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
3639df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32];
364d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
3659df49d7eSJed Brown ///
366c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
3679df49d7eSJed Brown ///
3689df49d7eSJed Brown /// // Operator fields
3699df49d7eSJed Brown /// let op = ceed
370c68be7a2SJeremy L Thompson ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
371ea6b5821SJeremy L Thompson ///     .name("mass")?
372c68be7a2SJeremy L Thompson ///     .field("dx", &r, &b, VectorOpt::Active)?
373c68be7a2SJeremy L Thompson ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
374356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
3759df49d7eSJed Brown ///
3769df49d7eSJed Brown /// println!("{}", op);
377c68be7a2SJeremy L Thompson /// # Ok(())
378c68be7a2SJeremy L Thompson /// # }
3799df49d7eSJed Brown /// ```
3809df49d7eSJed Brown impl<'a> fmt::Display for Operator<'a> {
3819df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3829df49d7eSJed Brown         self.op_core.fmt(f)
3839df49d7eSJed Brown     }
3849df49d7eSJed Brown }
3859df49d7eSJed Brown 
3869df49d7eSJed Brown /// View a composite Operator
3879df49d7eSJed Brown ///
3889df49d7eSJed Brown /// ```
389eb07d68fSJeremy L Thompson /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
3904d27c890SJeremy L Thompson /// # fn main() -> libceed::Result<()> {
3919df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
3929df49d7eSJed Brown ///
3939df49d7eSJed Brown /// // Sub operator field arguments
3949df49d7eSJed Brown /// let ne = 3;
395bf55b007SJeremy L Thompson /// let q = 4_usize;
3969df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne];
3979df49d7eSJed Brown /// for i in 0..ne {
3989df49d7eSJed Brown ///     ind[2 * i + 0] = i as i32;
3999df49d7eSJed Brown ///     ind[2 * i + 1] = (i + 1) as i32;
4009df49d7eSJed Brown /// }
401c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
4029df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32];
403d9267b76SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
4049df49d7eSJed Brown ///
405c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
4069df49d7eSJed Brown ///
407c68be7a2SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?;
408c68be7a2SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?;
4099df49d7eSJed Brown ///
410c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
4119df49d7eSJed Brown /// let op_mass = ceed
412c68be7a2SJeremy L Thompson ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
413ea6b5821SJeremy L Thompson ///     .name("Mass term")?
414c68be7a2SJeremy L Thompson ///     .field("u", &r, &b, VectorOpt::Active)?
415356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
416c68be7a2SJeremy L Thompson ///     .field("v", &r, &b, VectorOpt::Active)?;
4179df49d7eSJed Brown ///
418c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
4199df49d7eSJed Brown /// let op_diff = ceed
420c68be7a2SJeremy L Thompson ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
421ea6b5821SJeremy L Thompson ///     .name("Poisson term")?
422c68be7a2SJeremy L Thompson ///     .field("du", &r, &b, VectorOpt::Active)?
423356036faSJeremy L Thompson ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
424c68be7a2SJeremy L Thompson ///     .field("dv", &r, &b, VectorOpt::Active)?;
4259df49d7eSJed Brown ///
4269df49d7eSJed Brown /// let op = ceed
427c68be7a2SJeremy L Thompson ///     .composite_operator()?
428ea6b5821SJeremy L Thompson ///     .name("Screened Poisson")?
429c68be7a2SJeremy L Thompson ///     .sub_operator(&op_mass)?
430c68be7a2SJeremy L Thompson ///     .sub_operator(&op_diff)?;
4319df49d7eSJed Brown ///
4329df49d7eSJed Brown /// println!("{}", op);
433c68be7a2SJeremy L Thompson /// # Ok(())
434c68be7a2SJeremy L Thompson /// # }
4359df49d7eSJed Brown /// ```
4369df49d7eSJed Brown impl<'a> fmt::Display for CompositeOperator<'a> {
4379df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4389df49d7eSJed Brown         self.op_core.fmt(f)
4399df49d7eSJed Brown     }
4409df49d7eSJed Brown }
4419df49d7eSJed Brown 
4429df49d7eSJed Brown // -----------------------------------------------------------------------------
4439df49d7eSJed Brown // Core functionality
4449df49d7eSJed Brown // -----------------------------------------------------------------------------
4459df49d7eSJed Brown impl<'a> OperatorCore<'a> {
44611544396SJeremy L Thompson     // Raw Ceed for error handling
44711544396SJeremy L Thompson     #[doc(hidden)]
44811544396SJeremy L Thompson     fn ceed(&self) -> bind_ceed::Ceed {
44911544396SJeremy L Thompson         unsafe { bind_ceed::CeedOperatorReturnCeed(self.ptr) }
45011544396SJeremy L Thompson     }
45111544396SJeremy L Thompson 
4521142270cSJeremy L Thompson     // Error handling
4531142270cSJeremy L Thompson     #[doc(hidden)]
4541142270cSJeremy L Thompson     fn check_error(&self, ierr: i32) -> crate::Result<i32> {
45511544396SJeremy L Thompson         crate::check_error(|| self.ceed(), ierr)
4561142270cSJeremy L Thompson     }
4571142270cSJeremy L Thompson 
4589df49d7eSJed Brown     // Common implementations
4596f97ff0aSJeremy L Thompson     pub fn check(&self) -> crate::Result<i32> {
460656ef1e5SJeremy L Thompson         self.check_error(unsafe { bind_ceed::CeedOperatorCheckReady(self.ptr) })
4616f97ff0aSJeremy L Thompson     }
4626f97ff0aSJeremy L Thompson 
463ea6b5821SJeremy L Thompson     pub fn name(&self, name: &str) -> crate::Result<i32> {
464ea6b5821SJeremy L Thompson         let name_c = CString::new(name).expect("CString::new failed");
465656ef1e5SJeremy L Thompson         self.check_error(unsafe { bind_ceed::CeedOperatorSetName(self.ptr, name_c.as_ptr()) })
466ea6b5821SJeremy L Thompson     }
467ea6b5821SJeremy L Thompson 
4689df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
469656ef1e5SJeremy L Thompson         self.check_error(unsafe {
4709df49d7eSJed Brown             bind_ceed::CeedOperatorApply(
4719df49d7eSJed Brown                 self.ptr,
4729df49d7eSJed Brown                 input.ptr,
4739df49d7eSJed Brown                 output.ptr,
4749df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4759df49d7eSJed Brown             )
476656ef1e5SJeremy L Thompson         })
4779df49d7eSJed Brown     }
4789df49d7eSJed Brown 
4799df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
480656ef1e5SJeremy L Thompson         self.check_error(unsafe {
4819df49d7eSJed Brown             bind_ceed::CeedOperatorApplyAdd(
4829df49d7eSJed Brown                 self.ptr,
4839df49d7eSJed Brown                 input.ptr,
4849df49d7eSJed Brown                 output.ptr,
4859df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4869df49d7eSJed Brown             )
487656ef1e5SJeremy L Thompson         })
4889df49d7eSJed Brown     }
4899df49d7eSJed Brown 
4909df49d7eSJed Brown     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
491656ef1e5SJeremy L Thompson         self.check_error(unsafe {
4929df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleDiagonal(
4939df49d7eSJed Brown                 self.ptr,
4949df49d7eSJed Brown                 assembled.ptr,
4959df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
4969df49d7eSJed Brown             )
497656ef1e5SJeremy L Thompson         })
4989df49d7eSJed Brown     }
4999df49d7eSJed Brown 
5009df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
501656ef1e5SJeremy L Thompson         self.check_error(unsafe {
5029df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleAddDiagonal(
5039df49d7eSJed Brown                 self.ptr,
5049df49d7eSJed Brown                 assembled.ptr,
5059df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
5069df49d7eSJed Brown             )
507656ef1e5SJeremy L Thompson         })
5089df49d7eSJed Brown     }
5099df49d7eSJed Brown 
5109df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
5119df49d7eSJed Brown         &self,
5129df49d7eSJed Brown         assembled: &mut Vector,
5139df49d7eSJed Brown     ) -> crate::Result<i32> {
514656ef1e5SJeremy L Thompson         self.check_error(unsafe {
5159df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssemblePointBlockDiagonal(
5169df49d7eSJed Brown                 self.ptr,
5179df49d7eSJed Brown                 assembled.ptr,
5189df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
5199df49d7eSJed Brown             )
520656ef1e5SJeremy L Thompson         })
5219df49d7eSJed Brown     }
5229df49d7eSJed Brown 
5239df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
5249df49d7eSJed Brown         &self,
5259df49d7eSJed Brown         assembled: &mut Vector,
5269df49d7eSJed Brown     ) -> crate::Result<i32> {
527656ef1e5SJeremy L Thompson         self.check_error(unsafe {
5289df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleAddPointBlockDiagonal(
5299df49d7eSJed Brown                 self.ptr,
5309df49d7eSJed Brown                 assembled.ptr,
5319df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
5329df49d7eSJed Brown             )
533656ef1e5SJeremy L Thompson         })
5349df49d7eSJed Brown     }
5359df49d7eSJed Brown }
5369df49d7eSJed Brown 
5379df49d7eSJed Brown // -----------------------------------------------------------------------------
5389df49d7eSJed Brown // Operator
5399df49d7eSJed Brown // -----------------------------------------------------------------------------
5409df49d7eSJed Brown impl<'a> Operator<'a> {
5419df49d7eSJed Brown     // Constructor
5429df49d7eSJed Brown     pub fn create<'b>(
543594ef120SJeremy L Thompson         ceed: &crate::Ceed,
5449df49d7eSJed Brown         qf: impl Into<QFunctionOpt<'b>>,
5459df49d7eSJed Brown         dqf: impl Into<QFunctionOpt<'b>>,
5469df49d7eSJed Brown         dqfT: impl Into<QFunctionOpt<'b>>,
5479df49d7eSJed Brown     ) -> crate::Result<Self> {
5489df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
549656ef1e5SJeremy L Thompson         ceed.check_error(unsafe {
5509df49d7eSJed Brown             bind_ceed::CeedOperatorCreate(
5519df49d7eSJed Brown                 ceed.ptr,
5529df49d7eSJed Brown                 qf.into().to_raw(),
5539df49d7eSJed Brown                 dqf.into().to_raw(),
5549df49d7eSJed Brown                 dqfT.into().to_raw(),
5559df49d7eSJed Brown                 &mut ptr,
5569df49d7eSJed Brown             )
557656ef1e5SJeremy L Thompson         })?;
5589df49d7eSJed Brown         Ok(Self {
5591142270cSJeremy L Thompson             op_core: OperatorCore {
5601142270cSJeremy L Thompson                 ptr,
5611142270cSJeremy L Thompson                 _lifeline: PhantomData,
5621142270cSJeremy L Thompson             },
5639df49d7eSJed Brown         })
5649df49d7eSJed Brown     }
5659df49d7eSJed Brown 
5662b671a0aSJeremy L Thompson     unsafe fn from_raw(ptr: bind_ceed::CeedOperator) -> crate::Result<Self> {
5679df49d7eSJed Brown         Ok(Self {
5681142270cSJeremy L Thompson             op_core: OperatorCore {
5691142270cSJeremy L Thompson                 ptr,
5701142270cSJeremy L Thompson                 _lifeline: PhantomData,
5711142270cSJeremy L Thompson             },
5729df49d7eSJed Brown         })
5739df49d7eSJed Brown     }
5749df49d7eSJed Brown 
575ea6b5821SJeremy L Thompson     /// Set name for Operator printing
576ea6b5821SJeremy L Thompson     ///
577ea6b5821SJeremy L Thompson     /// * 'name' - Name to set
578ea6b5821SJeremy L Thompson     ///
579ea6b5821SJeremy L Thompson     /// ```
580eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
581ea6b5821SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
582ea6b5821SJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
583ea6b5821SJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
584ea6b5821SJeremy L Thompson     ///
585ea6b5821SJeremy L Thompson     /// // Operator field arguments
586ea6b5821SJeremy L Thompson     /// let ne = 3;
587bf55b007SJeremy L Thompson     /// let q = 4_usize;
588ea6b5821SJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
589ea6b5821SJeremy L Thompson     /// for i in 0..ne {
590ea6b5821SJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
591ea6b5821SJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
592ea6b5821SJeremy L Thompson     /// }
593ea6b5821SJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
594ea6b5821SJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
595d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
596ea6b5821SJeremy L Thompson     ///
597ea6b5821SJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
598ea6b5821SJeremy L Thompson     ///
599ea6b5821SJeremy L Thompson     /// // Operator fields
600ea6b5821SJeremy L Thompson     /// let op = ceed
601ea6b5821SJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
602ea6b5821SJeremy L Thompson     ///     .name("mass")?
603ea6b5821SJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
604ea6b5821SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
605356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
606ea6b5821SJeremy L Thompson     /// # Ok(())
607ea6b5821SJeremy L Thompson     /// # }
608ea6b5821SJeremy L Thompson     /// ```
609ea6b5821SJeremy L Thompson     #[allow(unused_mut)]
610ea6b5821SJeremy L Thompson     pub fn name(mut self, name: &str) -> crate::Result<Self> {
611ea6b5821SJeremy L Thompson         self.op_core.name(name)?;
612ea6b5821SJeremy L Thompson         Ok(self)
613ea6b5821SJeremy L Thompson     }
614ea6b5821SJeremy L Thompson 
6159df49d7eSJed Brown     /// Apply Operator to a vector
6169df49d7eSJed Brown     ///
6179df49d7eSJed Brown     /// * `input`  - Input Vector
6189df49d7eSJed Brown     /// * `output` - Output Vector
6199df49d7eSJed Brown     ///
6209df49d7eSJed Brown     /// ```
621eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, Scalar, VectorOpt};
6224d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
6239df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
6249df49d7eSJed Brown     /// let ne = 4;
6259df49d7eSJed Brown     /// let p = 3;
6269df49d7eSJed Brown     /// let q = 4;
6279df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
6289df49d7eSJed Brown     ///
6299df49d7eSJed Brown     /// // Vectors
630c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
631c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
6329df49d7eSJed Brown     /// qdata.set_value(0.0);
633c68be7a2SJeremy L Thompson     /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?;
634c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
6359df49d7eSJed Brown     /// v.set_value(0.0);
6369df49d7eSJed Brown     ///
6379df49d7eSJed Brown     /// // Restrictions
6389df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
6399df49d7eSJed Brown     /// for i in 0..ne {
6409df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
6419df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
6429df49d7eSJed Brown     /// }
643c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
6449df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
6459df49d7eSJed Brown     /// for i in 0..ne {
6469df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
6479df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
6489df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
6499df49d7eSJed Brown     /// }
650c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
6519df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
652c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
6539df49d7eSJed Brown     ///
6549df49d7eSJed Brown     /// // Bases
655c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
656c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
6579df49d7eSJed Brown     ///
6589df49d7eSJed Brown     /// // Build quadrature data
659c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
660c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
661c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
662c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
663356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
664c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
6659df49d7eSJed Brown     ///
6669df49d7eSJed Brown     /// // Mass operator
667c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
6689df49d7eSJed Brown     /// let op_mass = ceed
669c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
670c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
671356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
672c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
6739df49d7eSJed Brown     ///
6749df49d7eSJed Brown     /// v.set_value(0.0);
675c68be7a2SJeremy L Thompson     /// op_mass.apply(&u, &mut v)?;
6769df49d7eSJed Brown     ///
6779df49d7eSJed Brown     /// // Check
678e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
6794b61a5a0SRezgar Shakeri     /// let error: Scalar = (sum - 2.0).abs();
6809df49d7eSJed Brown     /// assert!(
6814b61a5a0SRezgar Shakeri     ///     error < 50.0 * libceed::EPSILON,
6824b61a5a0SRezgar Shakeri     ///     "Incorrect interval length computed. Expected: 2.0, Found: {}, Error: {:.12e}",
6834b61a5a0SRezgar Shakeri     ///     sum,
6844b61a5a0SRezgar Shakeri     ///     error
6859df49d7eSJed Brown     /// );
686c68be7a2SJeremy L Thompson     /// # Ok(())
687c68be7a2SJeremy L Thompson     /// # }
6889df49d7eSJed Brown     /// ```
6899df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
6909df49d7eSJed Brown         self.op_core.apply(input, output)
6919df49d7eSJed Brown     }
6929df49d7eSJed Brown 
6939df49d7eSJed Brown     /// Apply Operator to a vector and add result to output vector
6949df49d7eSJed Brown     ///
6959df49d7eSJed Brown     /// * `input`  - Input Vector
6969df49d7eSJed Brown     /// * `output` - Output Vector
6979df49d7eSJed Brown     ///
6989df49d7eSJed Brown     /// ```
699eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, Scalar, VectorOpt};
7004d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
7019df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
7029df49d7eSJed Brown     /// let ne = 4;
7039df49d7eSJed Brown     /// let p = 3;
7049df49d7eSJed Brown     /// let q = 4;
7059df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
7069df49d7eSJed Brown     ///
7079df49d7eSJed Brown     /// // Vectors
708c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
709c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
7109df49d7eSJed Brown     /// qdata.set_value(0.0);
711c68be7a2SJeremy L Thompson     /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?;
712c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
7139df49d7eSJed Brown     ///
7149df49d7eSJed Brown     /// // Restrictions
7159df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
7169df49d7eSJed Brown     /// for i in 0..ne {
7179df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
7189df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
7199df49d7eSJed Brown     /// }
720c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
7219df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
7229df49d7eSJed Brown     /// for i in 0..ne {
7239df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
7249df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
7259df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
7269df49d7eSJed Brown     /// }
727c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
7289df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
729c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
7309df49d7eSJed Brown     ///
7319df49d7eSJed Brown     /// // Bases
732c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
733c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
7349df49d7eSJed Brown     ///
7359df49d7eSJed Brown     /// // Build quadrature data
736c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
737c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
738c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
739c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
740356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
741c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
7429df49d7eSJed Brown     ///
7439df49d7eSJed Brown     /// // Mass operator
744c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
7459df49d7eSJed Brown     /// let op_mass = ceed
746c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
747c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
748356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
749c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
7509df49d7eSJed Brown     ///
7519df49d7eSJed Brown     /// v.set_value(1.0);
752c68be7a2SJeremy L Thompson     /// op_mass.apply_add(&u, &mut v)?;
7539df49d7eSJed Brown     ///
7549df49d7eSJed Brown     /// // Check
755e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
7569df49d7eSJed Brown     /// assert!(
75780a9ef05SNatalie Beams     ///     (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON,
7589df49d7eSJed Brown     ///     "Incorrect interval length computed and added"
7599df49d7eSJed Brown     /// );
760c68be7a2SJeremy L Thompson     /// # Ok(())
761c68be7a2SJeremy L Thompson     /// # }
7629df49d7eSJed Brown     /// ```
7639df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
7649df49d7eSJed Brown         self.op_core.apply_add(input, output)
7659df49d7eSJed Brown     }
7669df49d7eSJed Brown 
7679df49d7eSJed Brown     /// Provide a field to a Operator for use by its QFunction
7689df49d7eSJed Brown     ///
7699df49d7eSJed Brown     /// * `fieldname` - Name of the field (to be matched with the name used by
7709df49d7eSJed Brown     ///                   the QFunction)
7719df49d7eSJed Brown     /// * `r`         - ElemRestriction
772356036faSJeremy L Thompson     /// * `b`         - Basis in which the field resides or `BasisOpt::None`
773356036faSJeremy L Thompson     /// * `v`         - Vector to be used by Operator or `VectorOpt::Active` if field
774356036faSJeremy L Thompson     ///                   is active or `VectorOpt::None` if using `Weight` with the
7759df49d7eSJed Brown     ///                   QFunction
7769df49d7eSJed Brown     ///
7779df49d7eSJed Brown     ///
7789df49d7eSJed Brown     /// ```
779eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, MemType, QFunctionOpt, QuadMode, VectorOpt};
7804d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
7819df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
782c68be7a2SJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
783c68be7a2SJeremy L Thompson     /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;
7849df49d7eSJed Brown     ///
7859df49d7eSJed Brown     /// // Operator field arguments
7869df49d7eSJed Brown     /// let ne = 3;
7879df49d7eSJed Brown     /// let q = 4;
7889df49d7eSJed Brown     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
7899df49d7eSJed Brown     /// for i in 0..ne {
7909df49d7eSJed Brown     ///     ind[2 * i + 0] = i as i32;
7919df49d7eSJed Brown     ///     ind[2 * i + 1] = (i + 1) as i32;
7929df49d7eSJed Brown     /// }
793c68be7a2SJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
7949df49d7eSJed Brown     ///
795c68be7a2SJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
7969df49d7eSJed Brown     ///
7979df49d7eSJed Brown     /// // Operator field
798c68be7a2SJeremy L Thompson     /// op = op.field("dx", &r, &b, VectorOpt::Active)?;
799c68be7a2SJeremy L Thompson     /// # Ok(())
800c68be7a2SJeremy L Thompson     /// # }
8019df49d7eSJed Brown     /// ```
8029df49d7eSJed Brown     #[allow(unused_mut)]
8039df49d7eSJed Brown     pub fn field<'b>(
8049df49d7eSJed Brown         mut self,
8059df49d7eSJed Brown         fieldname: &str,
8069df49d7eSJed Brown         r: impl Into<ElemRestrictionOpt<'b>>,
8079df49d7eSJed Brown         b: impl Into<BasisOpt<'b>>,
8089df49d7eSJed Brown         v: impl Into<VectorOpt<'b>>,
8099df49d7eSJed Brown     ) -> crate::Result<Self> {
8109df49d7eSJed Brown         let fieldname = CString::new(fieldname).expect("CString::new failed");
811bf55b007SJeremy L Thompson         let fieldname = fieldname.as_ptr();
812656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
8139df49d7eSJed Brown             bind_ceed::CeedOperatorSetField(
8149df49d7eSJed Brown                 self.op_core.ptr,
8159df49d7eSJed Brown                 fieldname,
8169df49d7eSJed Brown                 r.into().to_raw(),
8179df49d7eSJed Brown                 b.into().to_raw(),
8189df49d7eSJed Brown                 v.into().to_raw(),
8199df49d7eSJed Brown             )
820656ef1e5SJeremy L Thompson         })?;
8219df49d7eSJed Brown         Ok(self)
8229df49d7eSJed Brown     }
8239df49d7eSJed Brown 
82408778c6fSJeremy L Thompson     /// Get a slice of Operator inputs
82508778c6fSJeremy L Thompson     ///
82608778c6fSJeremy L Thompson     /// ```
827eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, Scalar, VectorOpt};
8284d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
82908778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
83008778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
83108778c6fSJeremy L Thompson     ///
83208778c6fSJeremy L Thompson     /// // Operator field arguments
83308778c6fSJeremy L Thompson     /// let ne = 3;
834bf55b007SJeremy L Thompson     /// let q = 4_usize;
83508778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
83608778c6fSJeremy L Thompson     /// for i in 0..ne {
83708778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
83808778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
83908778c6fSJeremy L Thompson     /// }
84008778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
84108778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
842d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
84308778c6fSJeremy L Thompson     ///
84408778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
84508778c6fSJeremy L Thompson     ///
84608778c6fSJeremy L Thompson     /// // Operator fields
84708778c6fSJeremy L Thompson     /// let op = ceed
84808778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
84908778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
85008778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
851356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
85208778c6fSJeremy L Thompson     ///
85308778c6fSJeremy L Thompson     /// let inputs = op.inputs()?;
85408778c6fSJeremy L Thompson     ///
85508778c6fSJeremy L Thompson     /// assert_eq!(inputs.len(), 2, "Incorrect inputs array");
85608778c6fSJeremy L Thompson     /// # Ok(())
85708778c6fSJeremy L Thompson     /// # }
85808778c6fSJeremy L Thompson     /// ```
859e03fef56SJeremy L Thompson     pub fn inputs(&self) -> crate::Result<Vec<crate::OperatorField>> {
86008778c6fSJeremy L Thompson         // Get array of raw C pointers for inputs
86108778c6fSJeremy L Thompson         let mut num_inputs = 0;
86208778c6fSJeremy L Thompson         let mut inputs_ptr = std::ptr::null_mut();
863656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
86408778c6fSJeremy L Thompson             bind_ceed::CeedOperatorGetFields(
86508778c6fSJeremy L Thompson                 self.op_core.ptr,
86608778c6fSJeremy L Thompson                 &mut num_inputs,
86708778c6fSJeremy L Thompson                 &mut inputs_ptr,
86808778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut bind_ceed::CeedInt,
869bf55b007SJeremy L Thompson                 std::ptr::null_mut(),
87008778c6fSJeremy L Thompson             )
871656ef1e5SJeremy L Thompson         })?;
87208778c6fSJeremy L Thompson         // Convert raw C pointers to fixed length slice
87308778c6fSJeremy L Thompson         let inputs_slice = unsafe {
87408778c6fSJeremy L Thompson             std::slice::from_raw_parts(
875e03fef56SJeremy L Thompson                 inputs_ptr as *mut bind_ceed::CeedOperatorField,
87608778c6fSJeremy L Thompson                 num_inputs as usize,
87708778c6fSJeremy L Thompson             )
87808778c6fSJeremy L Thompson         };
879e03fef56SJeremy L Thompson         // And finally build vec
880e03fef56SJeremy L Thompson         let ceed = {
881656ef1e5SJeremy L Thompson             let ceed_raw = self.op_core.ceed();
882e03fef56SJeremy L Thompson             let mut ptr = std::ptr::null_mut();
883e03fef56SJeremy L Thompson             unsafe {
884656ef1e5SJeremy L Thompson                 bind_ceed::CeedReferenceCopy(ceed_raw, &mut ptr); // refcount
885e03fef56SJeremy L Thompson             }
886e03fef56SJeremy L Thompson             crate::Ceed { ptr }
887e03fef56SJeremy L Thompson         };
888e03fef56SJeremy L Thompson         let inputs = (0..num_inputs as usize)
8892b671a0aSJeremy L Thompson             .map(|i| unsafe { crate::OperatorField::from_raw(inputs_slice[i], ceed.clone()) })
890e03fef56SJeremy L Thompson             .collect::<crate::Result<Vec<_>>>()?;
891e03fef56SJeremy L Thompson         Ok(inputs)
89208778c6fSJeremy L Thompson     }
89308778c6fSJeremy L Thompson 
89408778c6fSJeremy L Thompson     /// Get a slice of Operator outputs
89508778c6fSJeremy L Thompson     ///
89608778c6fSJeremy L Thompson     /// ```
897eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
8984d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
89908778c6fSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
90008778c6fSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
90108778c6fSJeremy L Thompson     ///
90208778c6fSJeremy L Thompson     /// // Operator field arguments
90308778c6fSJeremy L Thompson     /// let ne = 3;
904bf55b007SJeremy L Thompson     /// let q = 4_usize;
90508778c6fSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
90608778c6fSJeremy L Thompson     /// for i in 0..ne {
90708778c6fSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
90808778c6fSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
90908778c6fSJeremy L Thompson     /// }
91008778c6fSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
91108778c6fSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
912d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
91308778c6fSJeremy L Thompson     ///
91408778c6fSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
91508778c6fSJeremy L Thompson     ///
91608778c6fSJeremy L Thompson     /// // Operator fields
91708778c6fSJeremy L Thompson     /// let op = ceed
91808778c6fSJeremy L Thompson     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
91908778c6fSJeremy L Thompson     ///     .field("dx", &r, &b, VectorOpt::Active)?
92008778c6fSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
921356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
92208778c6fSJeremy L Thompson     ///
92308778c6fSJeremy L Thompson     /// let outputs = op.outputs()?;
92408778c6fSJeremy L Thompson     ///
92508778c6fSJeremy L Thompson     /// assert_eq!(outputs.len(), 1, "Incorrect outputs array");
92608778c6fSJeremy L Thompson     /// # Ok(())
92708778c6fSJeremy L Thompson     /// # }
92808778c6fSJeremy L Thompson     /// ```
929e03fef56SJeremy L Thompson     pub fn outputs(&self) -> crate::Result<Vec<crate::OperatorField>> {
93008778c6fSJeremy L Thompson         // Get array of raw C pointers for outputs
93108778c6fSJeremy L Thompson         let mut num_outputs = 0;
93208778c6fSJeremy L Thompson         let mut outputs_ptr = std::ptr::null_mut();
933656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
93408778c6fSJeremy L Thompson             bind_ceed::CeedOperatorGetFields(
93508778c6fSJeremy L Thompson                 self.op_core.ptr,
93608778c6fSJeremy L Thompson                 std::ptr::null_mut() as *mut bind_ceed::CeedInt,
937bf55b007SJeremy L Thompson                 std::ptr::null_mut(),
93808778c6fSJeremy L Thompson                 &mut num_outputs,
93908778c6fSJeremy L Thompson                 &mut outputs_ptr,
94008778c6fSJeremy L Thompson             )
941656ef1e5SJeremy L Thompson         })?;
94208778c6fSJeremy L Thompson         // Convert raw C pointers to fixed length slice
94308778c6fSJeremy L Thompson         let outputs_slice = unsafe {
94408778c6fSJeremy L Thompson             std::slice::from_raw_parts(
945e03fef56SJeremy L Thompson                 outputs_ptr as *mut bind_ceed::CeedOperatorField,
94608778c6fSJeremy L Thompson                 num_outputs as usize,
94708778c6fSJeremy L Thompson             )
94808778c6fSJeremy L Thompson         };
949e03fef56SJeremy L Thompson         // And finally build vec
950e03fef56SJeremy L Thompson         let ceed = {
951656ef1e5SJeremy L Thompson             let ceed_raw = self.op_core.ceed();
952e03fef56SJeremy L Thompson             let mut ptr = std::ptr::null_mut();
953e03fef56SJeremy L Thompson             unsafe {
954656ef1e5SJeremy L Thompson                 bind_ceed::CeedReferenceCopy(ceed_raw, &mut ptr); // refcount
955e03fef56SJeremy L Thompson             }
956e03fef56SJeremy L Thompson             crate::Ceed { ptr }
957e03fef56SJeremy L Thompson         };
958e03fef56SJeremy L Thompson         let outputs = (0..num_outputs as usize)
9592b671a0aSJeremy L Thompson             .map(|i| unsafe { crate::OperatorField::from_raw(outputs_slice[i], ceed.clone()) })
960e03fef56SJeremy L Thompson             .collect::<crate::Result<Vec<_>>>()?;
961e03fef56SJeremy L Thompson         Ok(outputs)
96208778c6fSJeremy L Thompson     }
96308778c6fSJeremy L Thompson 
9646f97ff0aSJeremy L Thompson     /// Check if Operator is setup correctly
9656f97ff0aSJeremy L Thompson     ///
9666f97ff0aSJeremy L Thompson     /// ```
967eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
9686f97ff0aSJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
9696f97ff0aSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
9706f97ff0aSJeremy L Thompson     /// let ne = 4;
9716f97ff0aSJeremy L Thompson     /// let p = 3;
9726f97ff0aSJeremy L Thompson     /// let q = 4;
9736f97ff0aSJeremy L Thompson     /// let ndofs = p * ne - ne + 1;
9746f97ff0aSJeremy L Thompson     ///
9756f97ff0aSJeremy L Thompson     /// // Restrictions
9766f97ff0aSJeremy L Thompson     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
9776f97ff0aSJeremy L Thompson     /// for i in 0..ne {
9786f97ff0aSJeremy L Thompson     ///     indx[2 * i + 0] = i as i32;
9796f97ff0aSJeremy L Thompson     ///     indx[2 * i + 1] = (i + 1) as i32;
9806f97ff0aSJeremy L Thompson     /// }
9816f97ff0aSJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
9826f97ff0aSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
9836f97ff0aSJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
9846f97ff0aSJeremy L Thompson     ///
9856f97ff0aSJeremy L Thompson     /// // Bases
9866f97ff0aSJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
9876f97ff0aSJeremy L Thompson     ///
9886f97ff0aSJeremy L Thompson     /// // Build quadrature data
9896f97ff0aSJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
9906f97ff0aSJeremy L Thompson     /// let op_build = ceed
9916f97ff0aSJeremy L Thompson     ///     .operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
9926f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
9936f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
994356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
9956f97ff0aSJeremy L Thompson     ///
9966f97ff0aSJeremy L Thompson     /// // Check
9976f97ff0aSJeremy L Thompson     /// assert!(op_build.check().is_ok(), "Operator setup incorrectly");
9986f97ff0aSJeremy L Thompson     /// # Ok(())
9996f97ff0aSJeremy L Thompson     /// # }
10006f97ff0aSJeremy L Thompson     /// ```
10016f97ff0aSJeremy L Thompson     pub fn check(self) -> crate::Result<Self> {
10026f97ff0aSJeremy L Thompson         self.op_core.check()?;
10036f97ff0aSJeremy L Thompson         Ok(self)
10046f97ff0aSJeremy L Thompson     }
10056f97ff0aSJeremy L Thompson 
10063f2759cfSJeremy L Thompson     /// Get the number of elements associated with an Operator
10073f2759cfSJeremy L Thompson     ///
10083f2759cfSJeremy L Thompson     ///
10093f2759cfSJeremy L Thompson     /// ```
1010eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, MemType, QFunctionOpt, QuadMode, VectorOpt};
10114d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
10123f2759cfSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
10133f2759cfSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
10143f2759cfSJeremy L Thompson     /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;
10153f2759cfSJeremy L Thompson     ///
10163f2759cfSJeremy L Thompson     /// // Operator field arguments
10173f2759cfSJeremy L Thompson     /// let ne = 3;
10183f2759cfSJeremy L Thompson     /// let q = 4;
10193f2759cfSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
10203f2759cfSJeremy L Thompson     /// for i in 0..ne {
10213f2759cfSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
10223f2759cfSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
10233f2759cfSJeremy L Thompson     /// }
10243f2759cfSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
10253f2759cfSJeremy L Thompson     ///
10263f2759cfSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
10273f2759cfSJeremy L Thompson     ///
10283f2759cfSJeremy L Thompson     /// // Operator field
10293f2759cfSJeremy L Thompson     /// op = op.field("dx", &r, &b, VectorOpt::Active)?;
10303f2759cfSJeremy L Thompson     ///
10313f2759cfSJeremy L Thompson     /// // Check number of elements
10323f2759cfSJeremy L Thompson     /// assert_eq!(op.num_elements(), ne, "Incorrect number of elements");
10333f2759cfSJeremy L Thompson     /// # Ok(())
10343f2759cfSJeremy L Thompson     /// # }
10353f2759cfSJeremy L Thompson     /// ```
10363f2759cfSJeremy L Thompson     pub fn num_elements(&self) -> usize {
10373f2759cfSJeremy L Thompson         let mut nelem = 0;
10383f2759cfSJeremy L Thompson         unsafe { bind_ceed::CeedOperatorGetNumElements(self.op_core.ptr, &mut nelem) };
10393f2759cfSJeremy L Thompson         usize::try_from(nelem).unwrap()
10403f2759cfSJeremy L Thompson     }
10413f2759cfSJeremy L Thompson 
10423f2759cfSJeremy L Thompson     /// Get the number of quadrature points associated with each element of
10433f2759cfSJeremy L Thompson     ///   an Operator
10443f2759cfSJeremy L Thompson     ///
10453f2759cfSJeremy L Thompson     ///
10463f2759cfSJeremy L Thompson     /// ```
1047eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, MemType, QFunctionOpt, QuadMode, VectorOpt};
10484d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
10493f2759cfSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
10503f2759cfSJeremy L Thompson     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
10513f2759cfSJeremy L Thompson     /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;
10523f2759cfSJeremy L Thompson     ///
10533f2759cfSJeremy L Thompson     /// // Operator field arguments
10543f2759cfSJeremy L Thompson     /// let ne = 3;
10553f2759cfSJeremy L Thompson     /// let q = 4;
10563f2759cfSJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
10573f2759cfSJeremy L Thompson     /// for i in 0..ne {
10583f2759cfSJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
10593f2759cfSJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
10603f2759cfSJeremy L Thompson     /// }
10613f2759cfSJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
10623f2759cfSJeremy L Thompson     ///
10633f2759cfSJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
10643f2759cfSJeremy L Thompson     ///
10653f2759cfSJeremy L Thompson     /// // Operator field
10663f2759cfSJeremy L Thompson     /// op = op.field("dx", &r, &b, VectorOpt::Active)?;
10673f2759cfSJeremy L Thompson     ///
10683f2759cfSJeremy L Thompson     /// // Check number of quadrature points
10693f2759cfSJeremy L Thompson     /// assert_eq!(
10703f2759cfSJeremy L Thompson     ///     op.num_quadrature_points(),
10713f2759cfSJeremy L Thompson     ///     q,
10723f2759cfSJeremy L Thompson     ///     "Incorrect number of quadrature points"
10733f2759cfSJeremy L Thompson     /// );
10743f2759cfSJeremy L Thompson     /// # Ok(())
10753f2759cfSJeremy L Thompson     /// # }
10763f2759cfSJeremy L Thompson     /// ```
10773f2759cfSJeremy L Thompson     pub fn num_quadrature_points(&self) -> usize {
10783f2759cfSJeremy L Thompson         let mut Q = 0;
10793f2759cfSJeremy L Thompson         unsafe { bind_ceed::CeedOperatorGetNumQuadraturePoints(self.op_core.ptr, &mut Q) };
10803f2759cfSJeremy L Thompson         usize::try_from(Q).unwrap()
10813f2759cfSJeremy L Thompson     }
10823f2759cfSJeremy L Thompson 
10839df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
10849df49d7eSJed Brown     ///
10859df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
10869df49d7eSJed Brown     ///
10879df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
10889df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
10899df49d7eSJed Brown     ///
10909df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
10919df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
10929df49d7eSJed Brown     ///
10939df49d7eSJed Brown     /// ```
1094eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
10954d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
10969df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
10979df49d7eSJed Brown     /// let ne = 4;
10989df49d7eSJed Brown     /// let p = 3;
10999df49d7eSJed Brown     /// let q = 4;
11009df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
11019df49d7eSJed Brown     ///
11029df49d7eSJed Brown     /// // Vectors
1103c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1104c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
11059df49d7eSJed Brown     /// qdata.set_value(0.0);
1106c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
11079df49d7eSJed Brown     /// u.set_value(1.0);
1108c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
11099df49d7eSJed Brown     /// v.set_value(0.0);
11109df49d7eSJed Brown     ///
11119df49d7eSJed Brown     /// // Restrictions
11129df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
11139df49d7eSJed Brown     /// for i in 0..ne {
11149df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
11159df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
11169df49d7eSJed Brown     /// }
1117c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
11189df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
11199df49d7eSJed Brown     /// for i in 0..ne {
11209df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
11219df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
11229df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
11239df49d7eSJed Brown     /// }
1124c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?;
11259df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1126c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
11279df49d7eSJed Brown     ///
11289df49d7eSJed Brown     /// // Bases
1129c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1130c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
11319df49d7eSJed Brown     ///
11329df49d7eSJed Brown     /// // Build quadrature data
1133c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1134c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1135c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1136c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1137356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1138c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
11399df49d7eSJed Brown     ///
11409df49d7eSJed Brown     /// // Mass operator
1141c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
11429df49d7eSJed Brown     /// let op_mass = ceed
1143c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1144c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1145356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1146c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
11479df49d7eSJed Brown     ///
11489df49d7eSJed Brown     /// // Diagonal
1149c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ndofs)?;
11509df49d7eSJed Brown     /// diag.set_value(0.0);
1151c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_diagonal(&mut diag)?;
11529df49d7eSJed Brown     ///
11539df49d7eSJed Brown     /// // Manual diagonal computation
1154c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ndofs)?;
11559c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
11569df49d7eSJed Brown     /// for i in 0..ndofs {
11579df49d7eSJed Brown     ///     u.set_value(0.0);
11589df49d7eSJed Brown     ///     {
1159e78171edSJeremy L Thompson     ///         let mut u_array = u.view_mut()?;
11609df49d7eSJed Brown     ///         u_array[i] = 1.;
11619df49d7eSJed Brown     ///     }
11629df49d7eSJed Brown     ///
1163c68be7a2SJeremy L Thompson     ///     op_mass.apply(&u, &mut v)?;
11649df49d7eSJed Brown     ///
11659df49d7eSJed Brown     ///     {
11669c774eddSJeremy L Thompson     ///         let v_array = v.view()?;
1167e78171edSJeremy L Thompson     ///         let mut true_array = true_diag.view_mut()?;
11689df49d7eSJed Brown     ///         true_array[i] = v_array[i];
11699df49d7eSJed Brown     ///     }
11709df49d7eSJed Brown     /// }
11719df49d7eSJed Brown     ///
11729df49d7eSJed Brown     /// // Check
1173e78171edSJeremy L Thompson     /// diag.view()?
11749df49d7eSJed Brown     ///     .iter()
1175e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
11769df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
11779df49d7eSJed Brown     ///         assert!(
117880a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
11799df49d7eSJed Brown     ///             "Diagonal entry incorrect"
11809df49d7eSJed Brown     ///         );
11819df49d7eSJed Brown     ///     });
1182c68be7a2SJeremy L Thompson     /// # Ok(())
1183c68be7a2SJeremy L Thompson     /// # }
11849df49d7eSJed Brown     /// ```
11859df49d7eSJed Brown     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
11869df49d7eSJed Brown         self.op_core.linear_assemble_diagonal(assembled)
11879df49d7eSJed Brown     }
11889df49d7eSJed Brown 
11899df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
11909df49d7eSJed Brown     ///
11919df49d7eSJed Brown     /// This sums into a Vector with the diagonal of a linear Operator.
11929df49d7eSJed Brown     ///
11939df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
11949df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
11959df49d7eSJed Brown     ///
11969df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
11979df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
11989df49d7eSJed Brown     ///
11999df49d7eSJed Brown     ///
12009df49d7eSJed Brown     /// ```
1201eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, Scalar, VectorOpt};
12024d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
12039df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
12049df49d7eSJed Brown     /// let ne = 4;
12059df49d7eSJed Brown     /// let p = 3;
12069df49d7eSJed Brown     /// let q = 4;
12079df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
12089df49d7eSJed Brown     ///
12099df49d7eSJed Brown     /// // Vectors
1210c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1211c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
12129df49d7eSJed Brown     /// qdata.set_value(0.0);
1213c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
12149df49d7eSJed Brown     /// u.set_value(1.0);
1215c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
12169df49d7eSJed Brown     /// v.set_value(0.0);
12179df49d7eSJed Brown     ///
12189df49d7eSJed Brown     /// // Restrictions
12199df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
12209df49d7eSJed Brown     /// for i in 0..ne {
12219df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
12229df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
12239df49d7eSJed Brown     /// }
1224c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
12259df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
12269df49d7eSJed Brown     /// for i in 0..ne {
12279df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
12289df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
12299df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
12309df49d7eSJed Brown     /// }
1231c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?;
12329df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1233c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
12349df49d7eSJed Brown     ///
12359df49d7eSJed Brown     /// // Bases
1236c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1237c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
12389df49d7eSJed Brown     ///
12399df49d7eSJed Brown     /// // Build quadrature data
1240c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1241c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1242c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1243c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1244356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1245c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
12469df49d7eSJed Brown     ///
12479df49d7eSJed Brown     /// // Mass operator
1248c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
12499df49d7eSJed Brown     /// let op_mass = ceed
1250c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1251c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1252356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1253c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
12549df49d7eSJed Brown     ///
12559df49d7eSJed Brown     /// // Diagonal
1256c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ndofs)?;
12579df49d7eSJed Brown     /// diag.set_value(1.0);
1258c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_add_diagonal(&mut diag)?;
12599df49d7eSJed Brown     ///
12609df49d7eSJed Brown     /// // Manual diagonal computation
1261c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ndofs)?;
12629c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
12639df49d7eSJed Brown     /// for i in 0..ndofs {
12649df49d7eSJed Brown     ///     u.set_value(0.0);
12659df49d7eSJed Brown     ///     {
1266e78171edSJeremy L Thompson     ///         let mut u_array = u.view_mut()?;
12679df49d7eSJed Brown     ///         u_array[i] = 1.;
12689df49d7eSJed Brown     ///     }
12699df49d7eSJed Brown     ///
1270c68be7a2SJeremy L Thompson     ///     op_mass.apply(&u, &mut v)?;
12719df49d7eSJed Brown     ///
12729df49d7eSJed Brown     ///     {
12739c774eddSJeremy L Thompson     ///         let v_array = v.view()?;
1274e78171edSJeremy L Thompson     ///         let mut true_array = true_diag.view_mut()?;
12759df49d7eSJed Brown     ///         true_array[i] = v_array[i] + 1.0;
12769df49d7eSJed Brown     ///     }
12779df49d7eSJed Brown     /// }
12789df49d7eSJed Brown     ///
12799df49d7eSJed Brown     /// // Check
1280e78171edSJeremy L Thompson     /// diag.view()?
12819df49d7eSJed Brown     ///     .iter()
1282e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
12839df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
12849df49d7eSJed Brown     ///         assert!(
128580a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
12869df49d7eSJed Brown     ///             "Diagonal entry incorrect"
12879df49d7eSJed Brown     ///         );
12889df49d7eSJed Brown     ///     });
1289c68be7a2SJeremy L Thompson     /// # Ok(())
1290c68be7a2SJeremy L Thompson     /// # }
12919df49d7eSJed Brown     /// ```
12929df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
12939df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
12949df49d7eSJed Brown     }
12959df49d7eSJed Brown 
12969df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
12979df49d7eSJed Brown     ///
12989df49d7eSJed Brown     /// This overwrites a Vector with the point block diagonal of a linear
12999df49d7eSJed Brown     /// Operator.
13009df49d7eSJed Brown     ///
13019df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
13029df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
13039df49d7eSJed Brown     ///
13049df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
13059df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
13069df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
13079df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
13089df49d7eSJed Brown     ///                   this vector are derived from the active vector for
13099df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
13109df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
13119df49d7eSJed Brown     ///
13129df49d7eSJed Brown     /// ```
1313eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, EvalMode, MemType, QFunctionInputs, QFunctionOpt, QFunctionOutputs, QuadMode, VectorOpt};
13144d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
13159df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
13169df49d7eSJed Brown     /// let ne = 4;
13179df49d7eSJed Brown     /// let p = 3;
13189df49d7eSJed Brown     /// let q = 4;
13199df49d7eSJed Brown     /// let ncomp = 2;
13209df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
13219df49d7eSJed Brown     ///
13229df49d7eSJed Brown     /// // Vectors
1323c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1324c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
13259df49d7eSJed Brown     /// qdata.set_value(0.0);
1326c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ncomp * ndofs)?;
13279df49d7eSJed Brown     /// u.set_value(1.0);
1328c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ncomp * ndofs)?;
13299df49d7eSJed Brown     /// v.set_value(0.0);
13309df49d7eSJed Brown     ///
13319df49d7eSJed Brown     /// // Restrictions
13329df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
13339df49d7eSJed Brown     /// for i in 0..ne {
13349df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
13359df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
13369df49d7eSJed Brown     /// }
1337c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
13389df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
13399df49d7eSJed Brown     /// for i in 0..ne {
13409df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
13419df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
13429df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
13439df49d7eSJed Brown     /// }
1344c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?;
13459df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1346c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
13479df49d7eSJed Brown     ///
13489df49d7eSJed Brown     /// // Bases
1349c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1350c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?;
13519df49d7eSJed Brown     ///
13529df49d7eSJed Brown     /// // Build quadrature data
1353c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1354c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1355c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1356c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1357356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1358c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
13599df49d7eSJed Brown     ///
13609df49d7eSJed Brown     /// // Mass operator
13619df49d7eSJed Brown     /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
13629df49d7eSJed Brown     ///     // Number of quadrature points
13639df49d7eSJed Brown     ///     let q = qdata.len();
13649df49d7eSJed Brown     ///
13659df49d7eSJed Brown     ///     // Iterate over quadrature points
13669df49d7eSJed Brown     ///     for i in 0..q {
13679df49d7eSJed Brown     ///         v[i + 0 * q] = u[i + 1 * q] * qdata[i];
13689df49d7eSJed Brown     ///         v[i + 1 * q] = u[i + 0 * q] * qdata[i];
13699df49d7eSJed Brown     ///     }
13709df49d7eSJed Brown     ///
13719df49d7eSJed Brown     ///     // Return clean error code
13729df49d7eSJed Brown     ///     0
13739df49d7eSJed Brown     /// };
13749df49d7eSJed Brown     ///
13759df49d7eSJed Brown     /// let qf_mass = ceed
1376c68be7a2SJeremy L Thompson     ///     .q_function_interior(1, Box::new(mass_2_comp))?
1377c68be7a2SJeremy L Thompson     ///     .input("u", 2, EvalMode::Interp)?
1378c68be7a2SJeremy L Thompson     ///     .input("qdata", 1, EvalMode::None)?
1379c68be7a2SJeremy L Thompson     ///     .output("v", 2, EvalMode::Interp)?;
13809df49d7eSJed Brown     ///
13819df49d7eSJed Brown     /// let op_mass = ceed
1382c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1383c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1384356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1385c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
13869df49d7eSJed Brown     ///
13879df49d7eSJed Brown     /// // Diagonal
1388c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?;
13899df49d7eSJed Brown     /// diag.set_value(0.0);
1390c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_point_block_diagonal(&mut diag)?;
13919df49d7eSJed Brown     ///
13929df49d7eSJed Brown     /// // Manual diagonal computation
1393c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?;
13949c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
13959df49d7eSJed Brown     /// for i in 0..ndofs {
13969df49d7eSJed Brown     ///     for j in 0..ncomp {
13979df49d7eSJed Brown     ///         u.set_value(0.0);
13989df49d7eSJed Brown     ///         {
1399e78171edSJeremy L Thompson     ///             let mut u_array = u.view_mut()?;
14009df49d7eSJed Brown     ///             u_array[i + j * ndofs] = 1.;
14019df49d7eSJed Brown     ///         }
14029df49d7eSJed Brown     ///
1403c68be7a2SJeremy L Thompson     ///         op_mass.apply(&u, &mut v)?;
14049df49d7eSJed Brown     ///
14059df49d7eSJed Brown     ///         {
14069c774eddSJeremy L Thompson     ///             let v_array = v.view()?;
1407e78171edSJeremy L Thompson     ///             let mut true_array = true_diag.view_mut()?;
14089df49d7eSJed Brown     ///             for k in 0..ncomp {
14099df49d7eSJed Brown     ///                 true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
14109df49d7eSJed Brown     ///             }
14119df49d7eSJed Brown     ///         }
14129df49d7eSJed Brown     ///     }
14139df49d7eSJed Brown     /// }
14149df49d7eSJed Brown     ///
14159df49d7eSJed Brown     /// // Check
1416e78171edSJeremy L Thompson     /// diag.view()?
14179df49d7eSJed Brown     ///     .iter()
1418e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
14199df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
14209df49d7eSJed Brown     ///         assert!(
142180a9ef05SNatalie Beams     ///             (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
14229df49d7eSJed Brown     ///             "Diagonal entry incorrect"
14239df49d7eSJed Brown     ///         );
14249df49d7eSJed Brown     ///     });
1425c68be7a2SJeremy L Thompson     /// # Ok(())
1426c68be7a2SJeremy L Thompson     /// # }
14279df49d7eSJed Brown     /// ```
14289df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
14299df49d7eSJed Brown         &self,
14309df49d7eSJed Brown         assembled: &mut Vector,
14319df49d7eSJed Brown     ) -> crate::Result<i32> {
14329df49d7eSJed Brown         self.op_core.linear_assemble_point_block_diagonal(assembled)
14339df49d7eSJed Brown     }
14349df49d7eSJed Brown 
14359df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
14369df49d7eSJed Brown     ///
14379df49d7eSJed Brown     /// This sums into a Vector with the point block diagonal of a linear
14389df49d7eSJed Brown     /// Operator.
14399df49d7eSJed Brown     ///
14409df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
14419df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
14429df49d7eSJed Brown     ///
14439df49d7eSJed Brown     /// * `op`        -     Operator to assemble QFunction
14449df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
14459df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
14469df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
14479df49d7eSJed Brown     ///                   this vector are derived from the active vector for
14489df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
14499df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
14509df49d7eSJed Brown     ///
14519df49d7eSJed Brown     /// ```
1452eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, EvalMode, MemType, QFunctionInputs, QFunctionOpt, QFunctionOutputs, QuadMode, Scalar, VectorOpt};
14534d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
14549df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
14559df49d7eSJed Brown     /// let ne = 4;
14569df49d7eSJed Brown     /// let p = 3;
14579df49d7eSJed Brown     /// let q = 4;
14589df49d7eSJed Brown     /// let ncomp = 2;
14599df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
14609df49d7eSJed Brown     ///
14619df49d7eSJed Brown     /// // Vectors
1462c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
1463c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
14649df49d7eSJed Brown     /// qdata.set_value(0.0);
1465c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ncomp * ndofs)?;
14669df49d7eSJed Brown     /// u.set_value(1.0);
1467c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ncomp * ndofs)?;
14689df49d7eSJed Brown     /// v.set_value(0.0);
14699df49d7eSJed Brown     ///
14709df49d7eSJed Brown     /// // Restrictions
14719df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
14729df49d7eSJed Brown     /// for i in 0..ne {
14739df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
14749df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
14759df49d7eSJed Brown     /// }
1476c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
14779df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
14789df49d7eSJed Brown     /// for i in 0..ne {
14799df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
14809df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
14819df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
14829df49d7eSJed Brown     /// }
1483c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?;
14849df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1485c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
14869df49d7eSJed Brown     ///
14879df49d7eSJed Brown     /// // Bases
1488c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1489c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?;
14909df49d7eSJed Brown     ///
14919df49d7eSJed Brown     /// // Build quadrature data
1492c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1493c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1494c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1495c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1496356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1497c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
14989df49d7eSJed Brown     ///
14999df49d7eSJed Brown     /// // Mass operator
15009df49d7eSJed Brown     /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
15019df49d7eSJed Brown     ///     // Number of quadrature points
15029df49d7eSJed Brown     ///     let q = qdata.len();
15039df49d7eSJed Brown     ///
15049df49d7eSJed Brown     ///     // Iterate over quadrature points
15059df49d7eSJed Brown     ///     for i in 0..q {
15069df49d7eSJed Brown     ///         v[i + 0 * q] = u[i + 1 * q] * qdata[i];
15079df49d7eSJed Brown     ///         v[i + 1 * q] = u[i + 0 * q] * qdata[i];
15089df49d7eSJed Brown     ///     }
15099df49d7eSJed Brown     ///
15109df49d7eSJed Brown     ///     // Return clean error code
15119df49d7eSJed Brown     ///     0
15129df49d7eSJed Brown     /// };
15139df49d7eSJed Brown     ///
15149df49d7eSJed Brown     /// let qf_mass = ceed
1515c68be7a2SJeremy L Thompson     ///     .q_function_interior(1, Box::new(mass_2_comp))?
1516c68be7a2SJeremy L Thompson     ///     .input("u", 2, EvalMode::Interp)?
1517c68be7a2SJeremy L Thompson     ///     .input("qdata", 1, EvalMode::None)?
1518c68be7a2SJeremy L Thompson     ///     .output("v", 2, EvalMode::Interp)?;
15199df49d7eSJed Brown     ///
15209df49d7eSJed Brown     /// let op_mass = ceed
1521c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1522c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
1523356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1524c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
15259df49d7eSJed Brown     ///
15269df49d7eSJed Brown     /// // Diagonal
1527c68be7a2SJeremy L Thompson     /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?;
15289df49d7eSJed Brown     /// diag.set_value(1.0);
1529c68be7a2SJeremy L Thompson     /// op_mass.linear_assemble_add_point_block_diagonal(&mut diag)?;
15309df49d7eSJed Brown     ///
15319df49d7eSJed Brown     /// // Manual diagonal computation
1532c68be7a2SJeremy L Thompson     /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?;
15339c774eddSJeremy L Thompson     /// true_diag.set_value(0.0)?;
15349df49d7eSJed Brown     /// for i in 0..ndofs {
15359df49d7eSJed Brown     ///     for j in 0..ncomp {
15369df49d7eSJed Brown     ///         u.set_value(0.0);
15379df49d7eSJed Brown     ///         {
1538e78171edSJeremy L Thompson     ///             let mut u_array = u.view_mut()?;
15399df49d7eSJed Brown     ///             u_array[i + j * ndofs] = 1.;
15409df49d7eSJed Brown     ///         }
15419df49d7eSJed Brown     ///
1542c68be7a2SJeremy L Thompson     ///         op_mass.apply(&u, &mut v)?;
15439df49d7eSJed Brown     ///
15449df49d7eSJed Brown     ///         {
15459c774eddSJeremy L Thompson     ///             let v_array = v.view()?;
1546e78171edSJeremy L Thompson     ///             let mut true_array = true_diag.view_mut()?;
15479df49d7eSJed Brown     ///             for k in 0..ncomp {
15489df49d7eSJed Brown     ///                 true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
15499df49d7eSJed Brown     ///             }
15509df49d7eSJed Brown     ///         }
15519df49d7eSJed Brown     ///     }
15529df49d7eSJed Brown     /// }
15539df49d7eSJed Brown     ///
15549df49d7eSJed Brown     /// // Check
1555e78171edSJeremy L Thompson     /// diag.view()?
15569df49d7eSJed Brown     ///     .iter()
1557e78171edSJeremy L Thompson     ///     .zip(true_diag.view()?.iter())
15589df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
15599df49d7eSJed Brown     ///         assert!(
156080a9ef05SNatalie Beams     ///             (*computed - 1.0 - *actual).abs() < 10.0 * libceed::EPSILON,
15619df49d7eSJed Brown     ///             "Diagonal entry incorrect"
15629df49d7eSJed Brown     ///         );
15639df49d7eSJed Brown     ///     });
1564c68be7a2SJeremy L Thompson     /// # Ok(())
1565c68be7a2SJeremy L Thompson     /// # }
15669df49d7eSJed Brown     /// ```
15679df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
15689df49d7eSJed Brown         &self,
15699df49d7eSJed Brown         assembled: &mut Vector,
15709df49d7eSJed Brown     ) -> crate::Result<i32> {
15719df49d7eSJed Brown         self.op_core
15729df49d7eSJed Brown             .linear_assemble_add_point_block_diagonal(assembled)
15739df49d7eSJed Brown     }
15749df49d7eSJed Brown 
15759df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
15769df49d7eSJed Brown     ///   given Operator, creating the prolongation basis from the fine and
15779df49d7eSJed Brown     ///   coarse grid interpolation
15789df49d7eSJed Brown     ///
15799df49d7eSJed Brown     /// * `p_mult_fine`  - Lvector multiplicity in parallel gather/scatter
15809df49d7eSJed Brown     /// * `rstr_coarse`  - Coarse grid restriction
15819df49d7eSJed Brown     /// * `basis_coarse` - Coarse grid active vector basis
15829df49d7eSJed Brown     ///
15839df49d7eSJed Brown     /// ```
1584eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, Scalar, VectorOpt};
15854d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
15869df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
15879df49d7eSJed Brown     /// let ne = 15;
15889df49d7eSJed Brown     /// let p_coarse = 3;
15899df49d7eSJed Brown     /// let p_fine = 5;
15909df49d7eSJed Brown     /// let q = 6;
15919df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
15929df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
15939df49d7eSJed Brown     ///
15949df49d7eSJed Brown     /// // Vectors
15959df49d7eSJed Brown     /// let x_array = (0..ne + 1)
159680a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
159780a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1598c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1599c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
16009df49d7eSJed Brown     /// qdata.set_value(0.0);
1601c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
16029df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1603c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
16049df49d7eSJed Brown     /// u_fine.set_value(1.0);
1605c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
16069df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1607c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
16089df49d7eSJed Brown     /// v_fine.set_value(0.0);
1609c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
16109df49d7eSJed Brown     /// multiplicity.set_value(1.0);
16119df49d7eSJed Brown     ///
16129df49d7eSJed Brown     /// // Restrictions
16139df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1614c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
16159df49d7eSJed Brown     ///
16169df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
16179df49d7eSJed Brown     /// for i in 0..ne {
16189df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
16199df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
16209df49d7eSJed Brown     /// }
1621c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
16229df49d7eSJed Brown     ///
16239df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
16249df49d7eSJed Brown     /// for i in 0..ne {
16259df49d7eSJed Brown     ///     for j in 0..p_coarse {
16269df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
16279df49d7eSJed Brown     ///     }
16289df49d7eSJed Brown     /// }
1629c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
16309df49d7eSJed Brown     ///     ne,
16319df49d7eSJed Brown     ///     p_coarse,
16329df49d7eSJed Brown     ///     1,
16339df49d7eSJed Brown     ///     1,
16349df49d7eSJed Brown     ///     ndofs_coarse,
16359df49d7eSJed Brown     ///     MemType::Host,
16369df49d7eSJed Brown     ///     &indu_coarse,
1637c68be7a2SJeremy L Thompson     /// )?;
16389df49d7eSJed Brown     ///
16399df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
16409df49d7eSJed Brown     /// for i in 0..ne {
16419df49d7eSJed Brown     ///     for j in 0..p_fine {
16429df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
16439df49d7eSJed Brown     ///     }
16449df49d7eSJed Brown     /// }
1645c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
16469df49d7eSJed Brown     ///
16479df49d7eSJed Brown     /// // Bases
1648c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1649c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1650c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
16519df49d7eSJed Brown     ///
16529df49d7eSJed Brown     /// // Build quadrature data
1653c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1654c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1655c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1656c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1657356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1658c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
16599df49d7eSJed Brown     ///
16609df49d7eSJed Brown     /// // Mass operator
1661c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
16629df49d7eSJed Brown     /// let op_mass_fine = ceed
1663c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1664c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
1665356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1666c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
16679df49d7eSJed Brown     ///
16689df49d7eSJed Brown     /// // Multigrid setup
1669c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) =
1670c68be7a2SJeremy L Thompson     ///     op_mass_fine.create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)?;
16719df49d7eSJed Brown     ///
16729df49d7eSJed Brown     /// // Coarse problem
16739df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1674c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
16759df49d7eSJed Brown     ///
16769df49d7eSJed Brown     /// // Check
1677e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
16789df49d7eSJed Brown     /// assert!(
167980a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 50.0 * libceed::EPSILON,
16809df49d7eSJed Brown     ///     "Incorrect interval length computed"
16819df49d7eSJed Brown     /// );
16829df49d7eSJed Brown     ///
16839df49d7eSJed Brown     /// // Prolong
1684c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
16859df49d7eSJed Brown     ///
16869df49d7eSJed Brown     /// // Fine problem
1687c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
16889df49d7eSJed Brown     ///
16899df49d7eSJed Brown     /// // Check
1690e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
16919df49d7eSJed Brown     /// assert!(
1692392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
16939df49d7eSJed Brown     ///     "Incorrect interval length computed"
16949df49d7eSJed Brown     /// );
16959df49d7eSJed Brown     ///
16969df49d7eSJed Brown     /// // Restrict
1697c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
16989df49d7eSJed Brown     ///
16999df49d7eSJed Brown     /// // Check
1700e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
17019df49d7eSJed Brown     /// assert!(
1702392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
17039df49d7eSJed Brown     ///     "Incorrect interval length computed"
17049df49d7eSJed Brown     /// );
1705c68be7a2SJeremy L Thompson     /// # Ok(())
1706c68be7a2SJeremy L Thompson     /// # }
17079df49d7eSJed Brown     /// ```
1708594ef120SJeremy L Thompson     pub fn create_multigrid_level<'b>(
17099df49d7eSJed Brown         &self,
17109df49d7eSJed Brown         p_mult_fine: &Vector,
17119df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
17129df49d7eSJed Brown         basis_coarse: &Basis,
1713594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
17149df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
17159df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
17169df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
1717656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
17189df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreate(
17199df49d7eSJed Brown                 self.op_core.ptr,
17209df49d7eSJed Brown                 p_mult_fine.ptr,
17219df49d7eSJed Brown                 rstr_coarse.ptr,
17229df49d7eSJed Brown                 basis_coarse.ptr,
17239df49d7eSJed Brown                 &mut ptr_coarse,
17249df49d7eSJed Brown                 &mut ptr_prolong,
17259df49d7eSJed Brown                 &mut ptr_restrict,
17269df49d7eSJed Brown             )
1727656ef1e5SJeremy L Thompson         })?;
17282b671a0aSJeremy L Thompson         let op_coarse = unsafe { Operator::from_raw(ptr_coarse)? };
17292b671a0aSJeremy L Thompson         let op_prolong = unsafe { Operator::from_raw(ptr_prolong)? };
17302b671a0aSJeremy L Thompson         let op_restrict = unsafe { Operator::from_raw(ptr_restrict)? };
17319df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
17329df49d7eSJed Brown     }
17339df49d7eSJed Brown 
17349df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
17359df49d7eSJed Brown     ///   given Operator with a tensor basis for the active basis
17369df49d7eSJed Brown     ///
17379df49d7eSJed Brown     /// * `p_mult_fine`   - Lvector multiplicity in parallel gather/scatter
17389df49d7eSJed Brown     /// * `rstr_coarse`   - Coarse grid restriction
17399df49d7eSJed Brown     /// * `basis_coarse`  - Coarse grid active vector basis
17409df49d7eSJed Brown     /// * `interp_c_to_f` - Matrix for coarse to fine
17419df49d7eSJed Brown     ///
17429df49d7eSJed Brown     /// ```
1743eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, EvalMode, MemType, QFunctionOpt, QuadMode, Scalar, TransposeMode, VectorOpt};
17444d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
17459df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
17469df49d7eSJed Brown     /// let ne = 15;
17479df49d7eSJed Brown     /// let p_coarse = 3;
17489df49d7eSJed Brown     /// let p_fine = 5;
17499df49d7eSJed Brown     /// let q = 6;
17509df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
17519df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
17529df49d7eSJed Brown     ///
17539df49d7eSJed Brown     /// // Vectors
17549df49d7eSJed Brown     /// let x_array = (0..ne + 1)
175580a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
175680a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1757c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1758c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
17599df49d7eSJed Brown     /// qdata.set_value(0.0);
1760c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
17619df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1762c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
17639df49d7eSJed Brown     /// u_fine.set_value(1.0);
1764c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
17659df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1766c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
17679df49d7eSJed Brown     /// v_fine.set_value(0.0);
1768c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
17699df49d7eSJed Brown     /// multiplicity.set_value(1.0);
17709df49d7eSJed Brown     ///
17719df49d7eSJed Brown     /// // Restrictions
17729df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1773c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
17749df49d7eSJed Brown     ///
17759df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
17769df49d7eSJed Brown     /// for i in 0..ne {
17779df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
17789df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
17799df49d7eSJed Brown     /// }
1780c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
17819df49d7eSJed Brown     ///
17829df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
17839df49d7eSJed Brown     /// for i in 0..ne {
17849df49d7eSJed Brown     ///     for j in 0..p_coarse {
17859df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
17869df49d7eSJed Brown     ///     }
17879df49d7eSJed Brown     /// }
1788c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
17899df49d7eSJed Brown     ///     ne,
17909df49d7eSJed Brown     ///     p_coarse,
17919df49d7eSJed Brown     ///     1,
17929df49d7eSJed Brown     ///     1,
17939df49d7eSJed Brown     ///     ndofs_coarse,
17949df49d7eSJed Brown     ///     MemType::Host,
17959df49d7eSJed Brown     ///     &indu_coarse,
1796c68be7a2SJeremy L Thompson     /// )?;
17979df49d7eSJed Brown     ///
17989df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
17999df49d7eSJed Brown     /// for i in 0..ne {
18009df49d7eSJed Brown     ///     for j in 0..p_fine {
18019df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
18029df49d7eSJed Brown     ///     }
18039df49d7eSJed Brown     /// }
1804c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
18059df49d7eSJed Brown     ///
18069df49d7eSJed Brown     /// // Bases
1807c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1808c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1809c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
18109df49d7eSJed Brown     ///
18119df49d7eSJed Brown     /// // Build quadrature data
1812c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
1813c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
1814c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
1815c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
1816356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
1817c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
18189df49d7eSJed Brown     ///
18199df49d7eSJed Brown     /// // Mass operator
1820c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
18219df49d7eSJed Brown     /// let op_mass_fine = ceed
1822c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
1823c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
1824356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
1825c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
18269df49d7eSJed Brown     ///
18279df49d7eSJed Brown     /// // Multigrid setup
182880a9ef05SNatalie Beams     /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine];
18299df49d7eSJed Brown     /// {
1830c68be7a2SJeremy L Thompson     ///     let mut coarse = ceed.vector(p_coarse)?;
1831c68be7a2SJeremy L Thompson     ///     let mut fine = ceed.vector(p_fine)?;
1832c68be7a2SJeremy L Thompson     ///     let basis_c_to_f =
1833c68be7a2SJeremy L Thompson     ///         ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?;
18349df49d7eSJed Brown     ///     for i in 0..p_coarse {
18359df49d7eSJed Brown     ///         coarse.set_value(0.0);
18369df49d7eSJed Brown     ///         {
1837e78171edSJeremy L Thompson     ///             let mut array = coarse.view_mut()?;
18389df49d7eSJed Brown     ///             array[i] = 1.;
18399df49d7eSJed Brown     ///         }
1840c68be7a2SJeremy L Thompson     ///         basis_c_to_f.apply(
18419df49d7eSJed Brown     ///             1,
18429df49d7eSJed Brown     ///             TransposeMode::NoTranspose,
18439df49d7eSJed Brown     ///             EvalMode::Interp,
18449df49d7eSJed Brown     ///             &coarse,
18459df49d7eSJed Brown     ///             &mut fine,
1846c68be7a2SJeremy L Thompson     ///         )?;
1847e78171edSJeremy L Thompson     ///         let array = fine.view()?;
18489df49d7eSJed Brown     ///         for j in 0..p_fine {
18499df49d7eSJed Brown     ///             interp_c_to_f[j * p_coarse + i] = array[j];
18509df49d7eSJed Brown     ///         }
18519df49d7eSJed Brown     ///     }
18529df49d7eSJed Brown     /// }
1853c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_tensor_H1(
1854c68be7a2SJeremy L Thompson     ///     &multiplicity,
1855c68be7a2SJeremy L Thompson     ///     &ru_coarse,
1856c68be7a2SJeremy L Thompson     ///     &bu_coarse,
1857c68be7a2SJeremy L Thompson     ///     &interp_c_to_f,
1858c68be7a2SJeremy L Thompson     /// )?;
18599df49d7eSJed Brown     ///
18609df49d7eSJed Brown     /// // Coarse problem
18619df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1862c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
18639df49d7eSJed Brown     ///
18649df49d7eSJed Brown     /// // Check
1865e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
18669df49d7eSJed Brown     /// assert!(
186780a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
18689df49d7eSJed Brown     ///     "Incorrect interval length computed"
18699df49d7eSJed Brown     /// );
18709df49d7eSJed Brown     ///
18719df49d7eSJed Brown     /// // Prolong
1872c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
18739df49d7eSJed Brown     ///
18749df49d7eSJed Brown     /// // Fine problem
1875c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
18769df49d7eSJed Brown     ///
18779df49d7eSJed Brown     /// // Check
1878e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
18799df49d7eSJed Brown     /// assert!(
1880392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
18819df49d7eSJed Brown     ///     "Incorrect interval length computed"
18829df49d7eSJed Brown     /// );
18839df49d7eSJed Brown     ///
18849df49d7eSJed Brown     /// // Restrict
1885c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
18869df49d7eSJed Brown     ///
18879df49d7eSJed Brown     /// // Check
1888e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
18899df49d7eSJed Brown     /// assert!(
1890392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
18919df49d7eSJed Brown     ///     "Incorrect interval length computed"
18929df49d7eSJed Brown     /// );
1893c68be7a2SJeremy L Thompson     /// # Ok(())
1894c68be7a2SJeremy L Thompson     /// # }
18959df49d7eSJed Brown     /// ```
1896594ef120SJeremy L Thompson     pub fn create_multigrid_level_tensor_H1<'b>(
18979df49d7eSJed Brown         &self,
18989df49d7eSJed Brown         p_mult_fine: &Vector,
18999df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
19009df49d7eSJed Brown         basis_coarse: &Basis,
19019ab2bffdSJeremy L Thompson         interpCtoF: &[crate::Scalar],
1902594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
19039df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
19049df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
19059df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
1906656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
19079df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreateTensorH1(
19089df49d7eSJed Brown                 self.op_core.ptr,
19099df49d7eSJed Brown                 p_mult_fine.ptr,
19109df49d7eSJed Brown                 rstr_coarse.ptr,
19119df49d7eSJed Brown                 basis_coarse.ptr,
19129df49d7eSJed Brown                 interpCtoF.as_ptr(),
19139df49d7eSJed Brown                 &mut ptr_coarse,
19149df49d7eSJed Brown                 &mut ptr_prolong,
19159df49d7eSJed Brown                 &mut ptr_restrict,
19169df49d7eSJed Brown             )
1917656ef1e5SJeremy L Thompson         })?;
19182b671a0aSJeremy L Thompson         let op_coarse = unsafe { Operator::from_raw(ptr_coarse)? };
19192b671a0aSJeremy L Thompson         let op_prolong = unsafe { Operator::from_raw(ptr_prolong)? };
19202b671a0aSJeremy L Thompson         let op_restrict = unsafe { Operator::from_raw(ptr_restrict)? };
19219df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
19229df49d7eSJed Brown     }
19239df49d7eSJed Brown 
19249df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
19259df49d7eSJed Brown     ///   given Operator with a non-tensor basis for the active basis
19269df49d7eSJed Brown     ///
19279df49d7eSJed Brown     /// * `p_mult_fine`   - Lvector multiplicity in parallel gather/scatter
19289df49d7eSJed Brown     /// * `rstr_coarse`   - Coarse grid restriction
19299df49d7eSJed Brown     /// * `basis_coarse`  - Coarse grid active vector basis
19309df49d7eSJed Brown     /// * `interp_c_to_f` - Matrix for coarse to fine
19319df49d7eSJed Brown     ///
19329df49d7eSJed Brown     /// ```
1933eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, EvalMode, MemType, QFunctionOpt, QuadMode, Scalar, TransposeMode, VectorOpt};
19344d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
19359df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
19369df49d7eSJed Brown     /// let ne = 15;
19379df49d7eSJed Brown     /// let p_coarse = 3;
19389df49d7eSJed Brown     /// let p_fine = 5;
19399df49d7eSJed Brown     /// let q = 6;
19409df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
19419df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
19429df49d7eSJed Brown     ///
19439df49d7eSJed Brown     /// // Vectors
19449df49d7eSJed Brown     /// let x_array = (0..ne + 1)
194580a9ef05SNatalie Beams     ///     .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0)
194680a9ef05SNatalie Beams     ///     .collect::<Vec<Scalar>>();
1947c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&x_array)?;
1948c68be7a2SJeremy L Thompson     /// let mut qdata = ceed.vector(ne * q)?;
19499df49d7eSJed Brown     /// qdata.set_value(0.0);
1950c68be7a2SJeremy L Thompson     /// let mut u_coarse = ceed.vector(ndofs_coarse)?;
19519df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1952c68be7a2SJeremy L Thompson     /// let mut u_fine = ceed.vector(ndofs_fine)?;
19539df49d7eSJed Brown     /// u_fine.set_value(1.0);
1954c68be7a2SJeremy L Thompson     /// let mut v_coarse = ceed.vector(ndofs_coarse)?;
19559df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1956c68be7a2SJeremy L Thompson     /// let mut v_fine = ceed.vector(ndofs_fine)?;
19579df49d7eSJed Brown     /// v_fine.set_value(0.0);
1958c68be7a2SJeremy L Thompson     /// let mut multiplicity = ceed.vector(ndofs_fine)?;
19599df49d7eSJed Brown     /// multiplicity.set_value(1.0);
19609df49d7eSJed Brown     ///
19619df49d7eSJed Brown     /// // Restrictions
19629df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1963c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
19649df49d7eSJed Brown     ///
19659df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
19669df49d7eSJed Brown     /// for i in 0..ne {
19679df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
19689df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
19699df49d7eSJed Brown     /// }
1970c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
19719df49d7eSJed Brown     ///
19729df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
19739df49d7eSJed Brown     /// for i in 0..ne {
19749df49d7eSJed Brown     ///     for j in 0..p_coarse {
19759df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
19769df49d7eSJed Brown     ///     }
19779df49d7eSJed Brown     /// }
1978c68be7a2SJeremy L Thompson     /// let ru_coarse = ceed.elem_restriction(
19799df49d7eSJed Brown     ///     ne,
19809df49d7eSJed Brown     ///     p_coarse,
19819df49d7eSJed Brown     ///     1,
19829df49d7eSJed Brown     ///     1,
19839df49d7eSJed Brown     ///     ndofs_coarse,
19849df49d7eSJed Brown     ///     MemType::Host,
19859df49d7eSJed Brown     ///     &indu_coarse,
1986c68be7a2SJeremy L Thompson     /// )?;
19879df49d7eSJed Brown     ///
19889df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
19899df49d7eSJed Brown     /// for i in 0..ne {
19909df49d7eSJed Brown     ///     for j in 0..p_fine {
19919df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
19929df49d7eSJed Brown     ///     }
19939df49d7eSJed Brown     /// }
1994c68be7a2SJeremy L Thompson     /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?;
19959df49d7eSJed Brown     ///
19969df49d7eSJed Brown     /// // Bases
1997c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
1998c68be7a2SJeremy L Thompson     /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?;
1999c68be7a2SJeremy L Thompson     /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?;
20009df49d7eSJed Brown     ///
20019df49d7eSJed Brown     /// // Build quadrature data
2002c68be7a2SJeremy L Thompson     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
2003c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
2004c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2005c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2006356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2007c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata)?;
20089df49d7eSJed Brown     ///
20099df49d7eSJed Brown     /// // Mass operator
2010c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
20119df49d7eSJed Brown     /// let op_mass_fine = ceed
2012c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2013c68be7a2SJeremy L Thompson     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)?
2014356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata)?
2015c68be7a2SJeremy L Thompson     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?;
20169df49d7eSJed Brown     ///
20179df49d7eSJed Brown     /// // Multigrid setup
201880a9ef05SNatalie Beams     /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine];
20199df49d7eSJed Brown     /// {
2020c68be7a2SJeremy L Thompson     ///     let mut coarse = ceed.vector(p_coarse)?;
2021c68be7a2SJeremy L Thompson     ///     let mut fine = ceed.vector(p_fine)?;
2022c68be7a2SJeremy L Thompson     ///     let basis_c_to_f =
2023c68be7a2SJeremy L Thompson     ///         ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?;
20249df49d7eSJed Brown     ///     for i in 0..p_coarse {
20259df49d7eSJed Brown     ///         coarse.set_value(0.0);
20269df49d7eSJed Brown     ///         {
2027e78171edSJeremy L Thompson     ///             let mut array = coarse.view_mut()?;
20289df49d7eSJed Brown     ///             array[i] = 1.;
20299df49d7eSJed Brown     ///         }
2030c68be7a2SJeremy L Thompson     ///         basis_c_to_f.apply(
20319df49d7eSJed Brown     ///             1,
20329df49d7eSJed Brown     ///             TransposeMode::NoTranspose,
20339df49d7eSJed Brown     ///             EvalMode::Interp,
20349df49d7eSJed Brown     ///             &coarse,
20359df49d7eSJed Brown     ///             &mut fine,
2036c68be7a2SJeremy L Thompson     ///         )?;
2037e78171edSJeremy L Thompson     ///         let array = fine.view()?;
20389df49d7eSJed Brown     ///         for j in 0..p_fine {
20399df49d7eSJed Brown     ///             interp_c_to_f[j * p_coarse + i] = array[j];
20409df49d7eSJed Brown     ///         }
20419df49d7eSJed Brown     ///     }
20429df49d7eSJed Brown     /// }
2043c68be7a2SJeremy L Thompson     /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_H1(
2044c68be7a2SJeremy L Thompson     ///     &multiplicity,
2045c68be7a2SJeremy L Thompson     ///     &ru_coarse,
2046c68be7a2SJeremy L Thompson     ///     &bu_coarse,
2047c68be7a2SJeremy L Thompson     ///     &interp_c_to_f,
2048c68be7a2SJeremy L Thompson     /// )?;
20499df49d7eSJed Brown     ///
20509df49d7eSJed Brown     /// // Coarse problem
20519df49d7eSJed Brown     /// u_coarse.set_value(1.0);
2052c68be7a2SJeremy L Thompson     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?;
20539df49d7eSJed Brown     ///
20549df49d7eSJed Brown     /// // Check
2055e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
20569df49d7eSJed Brown     /// assert!(
205780a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
20589df49d7eSJed Brown     ///     "Incorrect interval length computed"
20599df49d7eSJed Brown     /// );
20609df49d7eSJed Brown     ///
20619df49d7eSJed Brown     /// // Prolong
2062c68be7a2SJeremy L Thompson     /// op_prolong.apply(&u_coarse, &mut u_fine)?;
20639df49d7eSJed Brown     ///
20649df49d7eSJed Brown     /// // Fine problem
2065c68be7a2SJeremy L Thompson     /// op_mass_fine.apply(&u_fine, &mut v_fine)?;
20669df49d7eSJed Brown     ///
20679df49d7eSJed Brown     /// // Check
2068e78171edSJeremy L Thompson     /// let sum: Scalar = v_fine.view()?.iter().sum();
20699df49d7eSJed Brown     /// assert!(
2070392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
20719df49d7eSJed Brown     ///     "Incorrect interval length computed"
20729df49d7eSJed Brown     /// );
20739df49d7eSJed Brown     ///
20749df49d7eSJed Brown     /// // Restrict
2075c68be7a2SJeremy L Thompson     /// op_restrict.apply(&v_fine, &mut v_coarse)?;
20769df49d7eSJed Brown     ///
20779df49d7eSJed Brown     /// // Check
2078e78171edSJeremy L Thompson     /// let sum: Scalar = v_coarse.view()?.iter().sum();
20799df49d7eSJed Brown     /// assert!(
2080392d940cSJeremy L Thompson     ///     (sum - 2.0).abs() < 200.0 * libceed::EPSILON,
20819df49d7eSJed Brown     ///     "Incorrect interval length computed"
20829df49d7eSJed Brown     /// );
2083c68be7a2SJeremy L Thompson     /// # Ok(())
2084c68be7a2SJeremy L Thompson     /// # }
20859df49d7eSJed Brown     /// ```
2086594ef120SJeremy L Thompson     pub fn create_multigrid_level_H1<'b>(
20879df49d7eSJed Brown         &self,
20889df49d7eSJed Brown         p_mult_fine: &Vector,
20899df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
20909df49d7eSJed Brown         basis_coarse: &Basis,
2091eb07d68fSJeremy L Thompson         interpCtoF: &[crate::Scalar],
2092594ef120SJeremy L Thompson     ) -> crate::Result<(Operator<'b>, Operator<'b>, Operator<'b>)> {
20939df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
20949df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
20959df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
2096656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
20979df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreateH1(
20989df49d7eSJed Brown                 self.op_core.ptr,
20999df49d7eSJed Brown                 p_mult_fine.ptr,
21009df49d7eSJed Brown                 rstr_coarse.ptr,
21019df49d7eSJed Brown                 basis_coarse.ptr,
21029df49d7eSJed Brown                 interpCtoF.as_ptr(),
21039df49d7eSJed Brown                 &mut ptr_coarse,
21049df49d7eSJed Brown                 &mut ptr_prolong,
21059df49d7eSJed Brown                 &mut ptr_restrict,
21069df49d7eSJed Brown             )
2107656ef1e5SJeremy L Thompson         })?;
21082b671a0aSJeremy L Thompson         let op_coarse = unsafe { Operator::from_raw(ptr_coarse)? };
21092b671a0aSJeremy L Thompson         let op_prolong = unsafe { Operator::from_raw(ptr_prolong)? };
21102b671a0aSJeremy L Thompson         let op_restrict = unsafe { Operator::from_raw(ptr_restrict)? };
21119df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
21129df49d7eSJed Brown     }
21139df49d7eSJed Brown }
21149df49d7eSJed Brown 
21159df49d7eSJed Brown // -----------------------------------------------------------------------------
21169df49d7eSJed Brown // Composite Operator
21179df49d7eSJed Brown // -----------------------------------------------------------------------------
21189df49d7eSJed Brown impl<'a> CompositeOperator<'a> {
21199df49d7eSJed Brown     // Constructor
2120594ef120SJeremy L Thompson     pub fn create(ceed: &crate::Ceed) -> crate::Result<Self> {
21219df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
2122*ed094490SJeremy L Thompson         ceed.check_error(unsafe { bind_ceed::CeedOperatorCreateComposite(ceed.ptr, &mut ptr) })?;
21239df49d7eSJed Brown         Ok(Self {
21241142270cSJeremy L Thompson             op_core: OperatorCore {
21251142270cSJeremy L Thompson                 ptr,
21261142270cSJeremy L Thompson                 _lifeline: PhantomData,
21271142270cSJeremy L Thompson             },
21289df49d7eSJed Brown         })
21299df49d7eSJed Brown     }
21309df49d7eSJed Brown 
2131ea6b5821SJeremy L Thompson     /// Set name for CompositeOperator printing
2132ea6b5821SJeremy L Thompson     ///
2133ea6b5821SJeremy L Thompson     /// * 'name' - Name to set
2134ea6b5821SJeremy L Thompson     ///
2135ea6b5821SJeremy L Thompson     /// ```
2136eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
2137ea6b5821SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
2138ea6b5821SJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
2139ea6b5821SJeremy L Thompson     ///
2140ea6b5821SJeremy L Thompson     /// // Sub operator field arguments
2141ea6b5821SJeremy L Thompson     /// let ne = 3;
2142bf55b007SJeremy L Thompson     /// let q = 4_usize;
2143ea6b5821SJeremy L Thompson     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
2144ea6b5821SJeremy L Thompson     /// for i in 0..ne {
2145ea6b5821SJeremy L Thompson     ///     ind[2 * i + 0] = i as i32;
2146ea6b5821SJeremy L Thompson     ///     ind[2 * i + 1] = (i + 1) as i32;
2147ea6b5821SJeremy L Thompson     /// }
2148ea6b5821SJeremy L Thompson     /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
2149ea6b5821SJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2150d9267b76SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
2151ea6b5821SJeremy L Thompson     ///
2152ea6b5821SJeremy L Thompson     /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2153ea6b5821SJeremy L Thompson     ///
2154ea6b5821SJeremy L Thompson     /// let qdata_mass = ceed.vector(q * ne)?;
2155ea6b5821SJeremy L Thompson     /// let qdata_diff = ceed.vector(q * ne)?;
2156ea6b5821SJeremy L Thompson     ///
2157ea6b5821SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
2158ea6b5821SJeremy L Thompson     /// let op_mass = ceed
2159ea6b5821SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2160ea6b5821SJeremy L Thompson     ///     .name("Mass term")?
2161ea6b5821SJeremy L Thompson     ///     .field("u", &r, &b, VectorOpt::Active)?
2162356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2163ea6b5821SJeremy L Thompson     ///     .field("v", &r, &b, VectorOpt::Active)?;
2164ea6b5821SJeremy L Thompson     ///
2165ea6b5821SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
2166ea6b5821SJeremy L Thompson     /// let op_diff = ceed
2167ea6b5821SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2168ea6b5821SJeremy L Thompson     ///     .name("Poisson term")?
2169ea6b5821SJeremy L Thompson     ///     .field("du", &r, &b, VectorOpt::Active)?
2170356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2171ea6b5821SJeremy L Thompson     ///     .field("dv", &r, &b, VectorOpt::Active)?;
2172ea6b5821SJeremy L Thompson     ///
2173ea6b5821SJeremy L Thompson     /// let op = ceed
2174ea6b5821SJeremy L Thompson     ///     .composite_operator()?
2175ea6b5821SJeremy L Thompson     ///     .name("Screened Poisson")?
2176ea6b5821SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2177ea6b5821SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
2178ea6b5821SJeremy L Thompson     /// # Ok(())
2179ea6b5821SJeremy L Thompson     /// # }
2180ea6b5821SJeremy L Thompson     /// ```
2181ea6b5821SJeremy L Thompson     #[allow(unused_mut)]
2182ea6b5821SJeremy L Thompson     pub fn name(mut self, name: &str) -> crate::Result<Self> {
2183ea6b5821SJeremy L Thompson         self.op_core.name(name)?;
2184ea6b5821SJeremy L Thompson         Ok(self)
2185ea6b5821SJeremy L Thompson     }
2186ea6b5821SJeremy L Thompson 
21879df49d7eSJed Brown     /// Apply Operator to a vector
21889df49d7eSJed Brown     ///
2189ea6b5821SJeremy L Thompson     /// * `input`  - Inpuht Vector
21909df49d7eSJed Brown     /// * `output` - Output Vector
21919df49d7eSJed Brown     ///
21929df49d7eSJed Brown     /// ```
2193eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, Scalar, VectorOpt};
21944d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
21959df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
21969df49d7eSJed Brown     /// let ne = 4;
21979df49d7eSJed Brown     /// let p = 3;
21989df49d7eSJed Brown     /// let q = 4;
21999df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
22009df49d7eSJed Brown     ///
22019df49d7eSJed Brown     /// // Vectors
2202c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
2203c68be7a2SJeremy L Thompson     /// let mut qdata_mass = ceed.vector(ne * q)?;
22049df49d7eSJed Brown     /// qdata_mass.set_value(0.0);
2205c68be7a2SJeremy L Thompson     /// let mut qdata_diff = ceed.vector(ne * q)?;
22069df49d7eSJed Brown     /// qdata_diff.set_value(0.0);
2207c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
22089df49d7eSJed Brown     /// u.set_value(1.0);
2209c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
22109df49d7eSJed Brown     /// v.set_value(0.0);
22119df49d7eSJed Brown     ///
22129df49d7eSJed Brown     /// // Restrictions
22139df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
22149df49d7eSJed Brown     /// for i in 0..ne {
22159df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
22169df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
22179df49d7eSJed Brown     /// }
2218c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
22199df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
22209df49d7eSJed Brown     /// for i in 0..ne {
22219df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
22229df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
22239df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
22249df49d7eSJed Brown     /// }
2225c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
22269df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2227c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
22289df49d7eSJed Brown     ///
22299df49d7eSJed Brown     /// // Bases
2230c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2231c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
22329df49d7eSJed Brown     ///
22339df49d7eSJed Brown     /// // Build quadrature data
2234c68be7a2SJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
2235c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
2236c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2237c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2238356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2239c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_mass)?;
22409df49d7eSJed Brown     ///
2241c68be7a2SJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
2242c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
2243c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2244c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2245356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2246c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_diff)?;
22479df49d7eSJed Brown     ///
22489df49d7eSJed Brown     /// // Application operator
2249c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
22509df49d7eSJed Brown     /// let op_mass = ceed
2251c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2252c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
2253356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2254c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
22559df49d7eSJed Brown     ///
2256c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
22579df49d7eSJed Brown     /// let op_diff = ceed
2258c68be7a2SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2259c68be7a2SJeremy L Thompson     ///     .field("du", &ru, &bu, VectorOpt::Active)?
2260356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2261c68be7a2SJeremy L Thompson     ///     .field("dv", &ru, &bu, VectorOpt::Active)?;
22629df49d7eSJed Brown     ///
22639df49d7eSJed Brown     /// let op_composite = ceed
2264c68be7a2SJeremy L Thompson     ///     .composite_operator()?
2265c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2266c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
22679df49d7eSJed Brown     ///
22689df49d7eSJed Brown     /// v.set_value(0.0);
2269c68be7a2SJeremy L Thompson     /// op_composite.apply(&u, &mut v)?;
22709df49d7eSJed Brown     ///
22719df49d7eSJed Brown     /// // Check
2272e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
22739df49d7eSJed Brown     /// assert!(
227480a9ef05SNatalie Beams     ///     (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
22759df49d7eSJed Brown     ///     "Incorrect interval length computed"
22769df49d7eSJed Brown     /// );
2277c68be7a2SJeremy L Thompson     /// # Ok(())
2278c68be7a2SJeremy L Thompson     /// # }
22799df49d7eSJed Brown     /// ```
22809df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
22819df49d7eSJed Brown         self.op_core.apply(input, output)
22829df49d7eSJed Brown     }
22839df49d7eSJed Brown 
22849df49d7eSJed Brown     /// Apply Operator to a vector and add result to output vector
22859df49d7eSJed Brown     ///
22869df49d7eSJed Brown     /// * `input`  - Input Vector
22879df49d7eSJed Brown     /// * `output` - Output Vector
22889df49d7eSJed Brown     ///
22899df49d7eSJed Brown     /// ```
2290eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, Scalar, VectorOpt};
22914d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
22929df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
22939df49d7eSJed Brown     /// let ne = 4;
22949df49d7eSJed Brown     /// let p = 3;
22959df49d7eSJed Brown     /// let q = 4;
22969df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
22979df49d7eSJed Brown     ///
22989df49d7eSJed Brown     /// // Vectors
2299c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
2300c68be7a2SJeremy L Thompson     /// let mut qdata_mass = ceed.vector(ne * q)?;
23019df49d7eSJed Brown     /// qdata_mass.set_value(0.0);
2302c68be7a2SJeremy L Thompson     /// let mut qdata_diff = ceed.vector(ne * q)?;
23039df49d7eSJed Brown     /// qdata_diff.set_value(0.0);
2304c68be7a2SJeremy L Thompson     /// let mut u = ceed.vector(ndofs)?;
23059df49d7eSJed Brown     /// u.set_value(1.0);
2306c68be7a2SJeremy L Thompson     /// let mut v = ceed.vector(ndofs)?;
23079df49d7eSJed Brown     /// v.set_value(0.0);
23089df49d7eSJed Brown     ///
23099df49d7eSJed Brown     /// // Restrictions
23109df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
23119df49d7eSJed Brown     /// for i in 0..ne {
23129df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
23139df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
23149df49d7eSJed Brown     /// }
2315c68be7a2SJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
23169df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
23179df49d7eSJed Brown     /// for i in 0..ne {
23189df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
23199df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
23209df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
23219df49d7eSJed Brown     /// }
2322c68be7a2SJeremy L Thompson     /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
23239df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
2324c68be7a2SJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
23259df49d7eSJed Brown     ///
23269df49d7eSJed Brown     /// // Bases
2327c68be7a2SJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
2328c68be7a2SJeremy L Thompson     /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;
23299df49d7eSJed Brown     ///
23309df49d7eSJed Brown     /// // Build quadrature data
2331c68be7a2SJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
2332c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
2333c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2334c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2335356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2336c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_mass)?;
23379df49d7eSJed Brown     ///
2338c68be7a2SJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
2339c68be7a2SJeremy L Thompson     /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
2340c68be7a2SJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
2341c68be7a2SJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2342356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?
2343c68be7a2SJeremy L Thompson     ///     .apply(&x, &mut qdata_diff)?;
23449df49d7eSJed Brown     ///
23459df49d7eSJed Brown     /// // Application operator
2346c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
23479df49d7eSJed Brown     /// let op_mass = ceed
2348c68be7a2SJeremy L Thompson     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
2349c68be7a2SJeremy L Thompson     ///     .field("u", &ru, &bu, VectorOpt::Active)?
2350356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_mass)?
2351c68be7a2SJeremy L Thompson     ///     .field("v", &ru, &bu, VectorOpt::Active)?;
23529df49d7eSJed Brown     ///
2353c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
23549df49d7eSJed Brown     /// let op_diff = ceed
2355c68be7a2SJeremy L Thompson     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?
2356c68be7a2SJeremy L Thompson     ///     .field("du", &ru, &bu, VectorOpt::Active)?
2357356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, &qdata_diff)?
2358c68be7a2SJeremy L Thompson     ///     .field("dv", &ru, &bu, VectorOpt::Active)?;
23599df49d7eSJed Brown     ///
23609df49d7eSJed Brown     /// let op_composite = ceed
2361c68be7a2SJeremy L Thompson     ///     .composite_operator()?
2362c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_mass)?
2363c68be7a2SJeremy L Thompson     ///     .sub_operator(&op_diff)?;
23649df49d7eSJed Brown     ///
23659df49d7eSJed Brown     /// v.set_value(1.0);
2366c68be7a2SJeremy L Thompson     /// op_composite.apply_add(&u, &mut v)?;
23679df49d7eSJed Brown     ///
23689df49d7eSJed Brown     /// // Check
2369e78171edSJeremy L Thompson     /// let sum: Scalar = v.view()?.iter().sum();
23709df49d7eSJed Brown     /// assert!(
237180a9ef05SNatalie Beams     ///     (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON,
23729df49d7eSJed Brown     ///     "Incorrect interval length computed"
23739df49d7eSJed Brown     /// );
2374c68be7a2SJeremy L Thompson     /// # Ok(())
2375c68be7a2SJeremy L Thompson     /// # }
23769df49d7eSJed Brown     /// ```
23779df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
23789df49d7eSJed Brown         self.op_core.apply_add(input, output)
23799df49d7eSJed Brown     }
23809df49d7eSJed Brown 
23819df49d7eSJed Brown     /// Add a sub-Operator to a Composite Operator
23829df49d7eSJed Brown     ///
23839df49d7eSJed Brown     /// * `subop` - Sub-Operator
23849df49d7eSJed Brown     ///
23859df49d7eSJed Brown     /// ```
2386eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, QFunctionOpt};
23874d27c890SJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
23889df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
2389c68be7a2SJeremy L Thompson     /// let mut op = ceed.composite_operator()?;
23909df49d7eSJed Brown     ///
2391c68be7a2SJeremy L Thompson     /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
2392c68be7a2SJeremy L Thompson     /// let op_mass = ceed.operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?;
2393c68be7a2SJeremy L Thompson     /// op = op.sub_operator(&op_mass)?;
23949df49d7eSJed Brown     ///
2395c68be7a2SJeremy L Thompson     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?;
2396c68be7a2SJeremy L Thompson     /// let op_diff = ceed.operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?;
2397c68be7a2SJeremy L Thompson     /// op = op.sub_operator(&op_diff)?;
2398c68be7a2SJeremy L Thompson     /// # Ok(())
2399c68be7a2SJeremy L Thompson     /// # }
24009df49d7eSJed Brown     /// ```
24019df49d7eSJed Brown     #[allow(unused_mut)]
24029df49d7eSJed Brown     pub fn sub_operator(mut self, subop: &Operator) -> crate::Result<Self> {
2403656ef1e5SJeremy L Thompson         self.op_core.check_error(unsafe {
2404*ed094490SJeremy L Thompson             bind_ceed::CeedOperatorCompositeAddSub(self.op_core.ptr, subop.op_core.ptr)
2405656ef1e5SJeremy L Thompson         })?;
24069df49d7eSJed Brown         Ok(self)
24079df49d7eSJed Brown     }
24089df49d7eSJed Brown 
24096f97ff0aSJeremy L Thompson     /// Check if CompositeOperator is setup correctly
24106f97ff0aSJeremy L Thompson     ///
24116f97ff0aSJeremy L Thompson     /// ```
2412eb07d68fSJeremy L Thompson     /// # use libceed::{prelude::*, BasisOpt, ElemRestrictionOpt, MemType, QFunctionOpt, QuadMode, VectorOpt};
24136f97ff0aSJeremy L Thompson     /// # fn main() -> libceed::Result<()> {
24146f97ff0aSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
24156f97ff0aSJeremy L Thompson     /// let ne = 4;
24166f97ff0aSJeremy L Thompson     /// let p = 3;
24176f97ff0aSJeremy L Thompson     /// let q = 4;
24186f97ff0aSJeremy L Thompson     /// let ndofs = p * ne - ne + 1;
24196f97ff0aSJeremy L Thompson     ///
24206f97ff0aSJeremy L Thompson     /// // Restrictions
24216f97ff0aSJeremy L Thompson     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
24226f97ff0aSJeremy L Thompson     /// for i in 0..ne {
24236f97ff0aSJeremy L Thompson     ///     indx[2 * i + 0] = i as i32;
24246f97ff0aSJeremy L Thompson     ///     indx[2 * i + 1] = (i + 1) as i32;
24256f97ff0aSJeremy L Thompson     /// }
24266f97ff0aSJeremy L Thompson     /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?;
24276f97ff0aSJeremy L Thompson     /// let strides: [i32; 3] = [1, q as i32, q as i32];
24286f97ff0aSJeremy L Thompson     /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;
24296f97ff0aSJeremy L Thompson     ///
24306f97ff0aSJeremy L Thompson     /// // Bases
24316f97ff0aSJeremy L Thompson     /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
24326f97ff0aSJeremy L Thompson     ///
24336f97ff0aSJeremy L Thompson     /// // Build quadrature data
24346f97ff0aSJeremy L Thompson     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?;
24356f97ff0aSJeremy L Thompson     /// let op_build_mass = ceed
24366f97ff0aSJeremy L Thompson     ///     .operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)?
24376f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
24386f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2439356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
24406f97ff0aSJeremy L Thompson     ///
24416f97ff0aSJeremy L Thompson     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?;
24426f97ff0aSJeremy L Thompson     /// let op_build_diff = ceed
24436f97ff0aSJeremy L Thompson     ///     .operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)?
24446f97ff0aSJeremy L Thompson     ///     .field("dx", &rx, &bx, VectorOpt::Active)?
24456f97ff0aSJeremy L Thompson     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
2446356036faSJeremy L Thompson     ///     .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
24476f97ff0aSJeremy L Thompson     ///
24486f97ff0aSJeremy L Thompson     /// let op_build = ceed
24496f97ff0aSJeremy L Thompson     ///     .composite_operator()?
24506f97ff0aSJeremy L Thompson     ///     .sub_operator(&op_build_mass)?
24516f97ff0aSJeremy L Thompson     ///     .sub_operator(&op_build_diff)?;
24526f97ff0aSJeremy L Thompson     ///
24536f97ff0aSJeremy L Thompson     /// // Check
24546f97ff0aSJeremy L Thompson     /// assert!(op_build.check().is_ok(), "Operator setup incorrectly");
24556f97ff0aSJeremy L Thompson     /// # Ok(())
24566f97ff0aSJeremy L Thompson     /// # }
24576f97ff0aSJeremy L Thompson     /// ```
24586f97ff0aSJeremy L Thompson     pub fn check(self) -> crate::Result<Self> {
24596f97ff0aSJeremy L Thompson         self.op_core.check()?;
24606f97ff0aSJeremy L Thompson         Ok(self)
24616f97ff0aSJeremy L Thompson     }
24626f97ff0aSJeremy L Thompson 
24639df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
24649df49d7eSJed Brown     ///
24659df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
24669df49d7eSJed Brown     ///
24679df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24689df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24699df49d7eSJed Brown     ///
24709df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24719df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
2472b748b478SJeremy L Thompson     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
24739df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
24749df49d7eSJed Brown     }
24759df49d7eSJed Brown 
24769df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
24779df49d7eSJed Brown     ///
24789df49d7eSJed Brown     /// This overwrites a Vector with the point block diagonal of a linear
24799df49d7eSJed Brown     ///   Operator.
24809df49d7eSJed Brown     ///
24819df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24829df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24839df49d7eSJed Brown     ///
24849df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24859df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
24869df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
24879df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
24889df49d7eSJed Brown     }
24899df49d7eSJed Brown 
24909df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
24919df49d7eSJed Brown     ///
24929df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
24939df49d7eSJed Brown     ///
24949df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
24959df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
24969df49d7eSJed Brown     ///
24979df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
24989df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
24999df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
25009df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
25019df49d7eSJed Brown     ///                   this vector are derived from the active vector for
25029df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
25039df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
25049df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
25059df49d7eSJed Brown         &self,
25069df49d7eSJed Brown         assembled: &mut Vector,
25079df49d7eSJed Brown     ) -> crate::Result<i32> {
25089df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
25099df49d7eSJed Brown     }
25109df49d7eSJed Brown 
25119df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
25129df49d7eSJed Brown     ///
25139df49d7eSJed Brown     /// This sums into a Vector with the diagonal of a linear Operator.
25149df49d7eSJed Brown     ///
25159df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
25169df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
25179df49d7eSJed Brown     ///
25189df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
25199df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
25209df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
25219df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
25229df49d7eSJed Brown     ///                   this vector are derived from the active vector for
25239df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
25249df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
25259df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
25269df49d7eSJed Brown         &self,
25279df49d7eSJed Brown         assembled: &mut Vector,
25289df49d7eSJed Brown     ) -> crate::Result<i32> {
25299df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
25309df49d7eSJed Brown     }
25319df49d7eSJed Brown }
25329df49d7eSJed Brown 
25339df49d7eSJed Brown // -----------------------------------------------------------------------------
2534