xref: /libCEED/rust/libceed/src/operator.rs (revision 9df49d7ef0a77c7a3baec2427d8a7274681409b6)
1*9df49d7eSJed Brown // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2*9df49d7eSJed Brown // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3*9df49d7eSJed Brown // reserved. See files LICENSE and NOTICE for details.
4*9df49d7eSJed Brown //
5*9df49d7eSJed Brown // This file is part of CEED, a collection of benchmarks, miniapps, software
6*9df49d7eSJed Brown // libraries and APIs for efficient high-order finite element and spectral
7*9df49d7eSJed Brown // element discretizations for exascale applications. For more information and
8*9df49d7eSJed Brown // source code availability see http://github.com/ceed.
9*9df49d7eSJed Brown //
10*9df49d7eSJed Brown // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11*9df49d7eSJed Brown // a collaborative effort of two U.S. Department of Energy organizations (Office
12*9df49d7eSJed Brown // of Science and the National Nuclear Security Administration) responsible for
13*9df49d7eSJed Brown // the planning and preparation of a capable exascale ecosystem, including
14*9df49d7eSJed Brown // software, applications, hardware, advanced system engineering and early
15*9df49d7eSJed Brown // testbed platforms, in support of the nation's exascale computing imperative
16*9df49d7eSJed Brown 
17*9df49d7eSJed Brown //! A Ceed Operator defines the finite/spectral element operator associated to a
18*9df49d7eSJed Brown //! Ceed QFunction. A Ceed Operator connects Ceed ElemRestrictions,
19*9df49d7eSJed Brown //! Ceed Bases, and Ceed QFunctions.
20*9df49d7eSJed Brown 
21*9df49d7eSJed Brown use crate::prelude::*;
22*9df49d7eSJed Brown 
23*9df49d7eSJed Brown // -----------------------------------------------------------------------------
24*9df49d7eSJed Brown // CeedOperator context wrapper
25*9df49d7eSJed Brown // -----------------------------------------------------------------------------
26*9df49d7eSJed Brown pub(crate) struct OperatorCore<'a> {
27*9df49d7eSJed Brown     ceed: &'a crate::Ceed,
28*9df49d7eSJed Brown     ptr: bind_ceed::CeedOperator,
29*9df49d7eSJed Brown }
30*9df49d7eSJed Brown 
31*9df49d7eSJed Brown pub struct Operator<'a> {
32*9df49d7eSJed Brown     op_core: OperatorCore<'a>,
33*9df49d7eSJed Brown }
34*9df49d7eSJed Brown 
35*9df49d7eSJed Brown pub struct CompositeOperator<'a> {
36*9df49d7eSJed Brown     op_core: OperatorCore<'a>,
37*9df49d7eSJed Brown }
38*9df49d7eSJed Brown 
39*9df49d7eSJed Brown // -----------------------------------------------------------------------------
40*9df49d7eSJed Brown // Destructor
41*9df49d7eSJed Brown // -----------------------------------------------------------------------------
42*9df49d7eSJed Brown impl<'a> Drop for OperatorCore<'a> {
43*9df49d7eSJed Brown     fn drop(&mut self) {
44*9df49d7eSJed Brown         unsafe {
45*9df49d7eSJed Brown             bind_ceed::CeedOperatorDestroy(&mut self.ptr);
46*9df49d7eSJed Brown         }
47*9df49d7eSJed Brown     }
48*9df49d7eSJed Brown }
49*9df49d7eSJed Brown 
50*9df49d7eSJed Brown // -----------------------------------------------------------------------------
51*9df49d7eSJed Brown // Display
52*9df49d7eSJed Brown // -----------------------------------------------------------------------------
53*9df49d7eSJed Brown impl<'a> fmt::Display for OperatorCore<'a> {
54*9df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55*9df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
56*9df49d7eSJed Brown         let mut sizeloc = crate::MAX_BUFFER_LENGTH;
57*9df49d7eSJed Brown         let cstring = unsafe {
58*9df49d7eSJed Brown             let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc);
59*9df49d7eSJed Brown             bind_ceed::CeedOperatorView(self.ptr, file);
60*9df49d7eSJed Brown             bind_ceed::fclose(file);
61*9df49d7eSJed Brown             CString::from_raw(ptr)
62*9df49d7eSJed Brown         };
63*9df49d7eSJed Brown         cstring.to_string_lossy().fmt(f)
64*9df49d7eSJed Brown     }
65*9df49d7eSJed Brown }
66*9df49d7eSJed Brown 
67*9df49d7eSJed Brown /// View an Operator
68*9df49d7eSJed Brown ///
69*9df49d7eSJed Brown /// ```
70*9df49d7eSJed Brown /// # use libceed::prelude::*;
71*9df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
72*9df49d7eSJed Brown /// let qf = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
73*9df49d7eSJed Brown ///
74*9df49d7eSJed Brown /// // Operator field arguments
75*9df49d7eSJed Brown /// let ne = 3;
76*9df49d7eSJed Brown /// let q = 4 as usize;
77*9df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne];
78*9df49d7eSJed Brown /// for i in 0..ne {
79*9df49d7eSJed Brown ///     ind[2 * i + 0] = i as i32;
80*9df49d7eSJed Brown ///     ind[2 * i + 1] = (i + 1) as i32;
81*9df49d7eSJed Brown /// }
82*9df49d7eSJed Brown /// let r = ceed
83*9df49d7eSJed Brown ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)
84*9df49d7eSJed Brown ///     .unwrap();
85*9df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32];
86*9df49d7eSJed Brown /// let rq = ceed
87*9df49d7eSJed Brown ///     .strided_elem_restriction(ne, 2, 1, q * ne, strides)
88*9df49d7eSJed Brown ///     .unwrap();
89*9df49d7eSJed Brown ///
90*9df49d7eSJed Brown /// let b = ceed
91*9df49d7eSJed Brown ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
92*9df49d7eSJed Brown ///     .unwrap();
93*9df49d7eSJed Brown ///
94*9df49d7eSJed Brown /// // Operator fields
95*9df49d7eSJed Brown /// let op = ceed
96*9df49d7eSJed Brown ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)
97*9df49d7eSJed Brown ///     .unwrap()
98*9df49d7eSJed Brown ///     .field("dx", &r, &b, VectorOpt::Active)
99*9df49d7eSJed Brown ///     .unwrap()
100*9df49d7eSJed Brown ///     .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)
101*9df49d7eSJed Brown ///     .unwrap()
102*9df49d7eSJed Brown ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
103*9df49d7eSJed Brown ///     .unwrap();
104*9df49d7eSJed Brown ///
105*9df49d7eSJed Brown /// println!("{}", op);
106*9df49d7eSJed Brown /// ```
107*9df49d7eSJed Brown impl<'a> fmt::Display for Operator<'a> {
108*9df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109*9df49d7eSJed Brown         self.op_core.fmt(f)
110*9df49d7eSJed Brown     }
111*9df49d7eSJed Brown }
112*9df49d7eSJed Brown 
113*9df49d7eSJed Brown /// View a composite Operator
114*9df49d7eSJed Brown ///
115*9df49d7eSJed Brown /// ```
116*9df49d7eSJed Brown /// # use libceed::prelude::*;
117*9df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init();
118*9df49d7eSJed Brown ///
119*9df49d7eSJed Brown /// // Sub operator field arguments
120*9df49d7eSJed Brown /// let ne = 3;
121*9df49d7eSJed Brown /// let q = 4 as usize;
122*9df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne];
123*9df49d7eSJed Brown /// for i in 0..ne {
124*9df49d7eSJed Brown ///     ind[2 * i + 0] = i as i32;
125*9df49d7eSJed Brown ///     ind[2 * i + 1] = (i + 1) as i32;
126*9df49d7eSJed Brown /// }
127*9df49d7eSJed Brown /// let r = ceed
128*9df49d7eSJed Brown ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)
129*9df49d7eSJed Brown ///     .unwrap();
130*9df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32];
131*9df49d7eSJed Brown /// let rq = ceed
132*9df49d7eSJed Brown ///     .strided_elem_restriction(ne, 2, 1, q * ne, strides)
133*9df49d7eSJed Brown ///     .unwrap();
134*9df49d7eSJed Brown ///
135*9df49d7eSJed Brown /// let b = ceed
136*9df49d7eSJed Brown ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
137*9df49d7eSJed Brown ///     .unwrap();
138*9df49d7eSJed Brown ///
139*9df49d7eSJed Brown /// let qdata_mass = ceed.vector(q * ne).unwrap();
140*9df49d7eSJed Brown /// let qdata_diff = ceed.vector(q * ne).unwrap();
141*9df49d7eSJed Brown ///
142*9df49d7eSJed Brown /// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
143*9df49d7eSJed Brown /// let op_mass = ceed
144*9df49d7eSJed Brown ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
145*9df49d7eSJed Brown ///     .unwrap()
146*9df49d7eSJed Brown ///     .field("u", &r, &b, VectorOpt::Active)
147*9df49d7eSJed Brown ///     .unwrap()
148*9df49d7eSJed Brown ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)
149*9df49d7eSJed Brown ///     .unwrap()
150*9df49d7eSJed Brown ///     .field("v", &r, &b, VectorOpt::Active)
151*9df49d7eSJed Brown ///     .unwrap();
152*9df49d7eSJed Brown ///
153*9df49d7eSJed Brown /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply").unwrap();
154*9df49d7eSJed Brown /// let op_diff = ceed
155*9df49d7eSJed Brown ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)
156*9df49d7eSJed Brown ///     .unwrap()
157*9df49d7eSJed Brown ///     .field("du", &r, &b, VectorOpt::Active)
158*9df49d7eSJed Brown ///     .unwrap()
159*9df49d7eSJed Brown ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)
160*9df49d7eSJed Brown ///     .unwrap()
161*9df49d7eSJed Brown ///     .field("dv", &r, &b, VectorOpt::Active)
162*9df49d7eSJed Brown ///     .unwrap();
163*9df49d7eSJed Brown ///
164*9df49d7eSJed Brown /// let op = ceed
165*9df49d7eSJed Brown ///     .composite_operator()
166*9df49d7eSJed Brown ///     .unwrap()
167*9df49d7eSJed Brown ///     .sub_operator(&op_mass)
168*9df49d7eSJed Brown ///     .unwrap()
169*9df49d7eSJed Brown ///     .sub_operator(&op_diff)
170*9df49d7eSJed Brown ///     .unwrap();
171*9df49d7eSJed Brown ///
172*9df49d7eSJed Brown /// println!("{}", op);
173*9df49d7eSJed Brown /// ```
174*9df49d7eSJed Brown impl<'a> fmt::Display for CompositeOperator<'a> {
175*9df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176*9df49d7eSJed Brown         self.op_core.fmt(f)
177*9df49d7eSJed Brown     }
178*9df49d7eSJed Brown }
179*9df49d7eSJed Brown 
180*9df49d7eSJed Brown // -----------------------------------------------------------------------------
181*9df49d7eSJed Brown // Core functionality
182*9df49d7eSJed Brown // -----------------------------------------------------------------------------
183*9df49d7eSJed Brown impl<'a> OperatorCore<'a> {
184*9df49d7eSJed Brown     // Common implementations
185*9df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
186*9df49d7eSJed Brown         let ierr = unsafe {
187*9df49d7eSJed Brown             bind_ceed::CeedOperatorApply(
188*9df49d7eSJed Brown                 self.ptr,
189*9df49d7eSJed Brown                 input.ptr,
190*9df49d7eSJed Brown                 output.ptr,
191*9df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
192*9df49d7eSJed Brown             )
193*9df49d7eSJed Brown         };
194*9df49d7eSJed Brown         self.ceed.check_error(ierr)
195*9df49d7eSJed Brown     }
196*9df49d7eSJed Brown 
197*9df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
198*9df49d7eSJed Brown         let ierr = unsafe {
199*9df49d7eSJed Brown             bind_ceed::CeedOperatorApplyAdd(
200*9df49d7eSJed Brown                 self.ptr,
201*9df49d7eSJed Brown                 input.ptr,
202*9df49d7eSJed Brown                 output.ptr,
203*9df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
204*9df49d7eSJed Brown             )
205*9df49d7eSJed Brown         };
206*9df49d7eSJed Brown         self.ceed.check_error(ierr)
207*9df49d7eSJed Brown     }
208*9df49d7eSJed Brown 
209*9df49d7eSJed Brown     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
210*9df49d7eSJed Brown         let ierr = unsafe {
211*9df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleDiagonal(
212*9df49d7eSJed Brown                 self.ptr,
213*9df49d7eSJed Brown                 assembled.ptr,
214*9df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
215*9df49d7eSJed Brown             )
216*9df49d7eSJed Brown         };
217*9df49d7eSJed Brown         self.ceed.check_error(ierr)
218*9df49d7eSJed Brown     }
219*9df49d7eSJed Brown 
220*9df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
221*9df49d7eSJed Brown         let ierr = unsafe {
222*9df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleAddDiagonal(
223*9df49d7eSJed Brown                 self.ptr,
224*9df49d7eSJed Brown                 assembled.ptr,
225*9df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
226*9df49d7eSJed Brown             )
227*9df49d7eSJed Brown         };
228*9df49d7eSJed Brown         self.ceed.check_error(ierr)
229*9df49d7eSJed Brown     }
230*9df49d7eSJed Brown 
231*9df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
232*9df49d7eSJed Brown         &self,
233*9df49d7eSJed Brown         assembled: &mut Vector,
234*9df49d7eSJed Brown     ) -> crate::Result<i32> {
235*9df49d7eSJed Brown         let ierr = unsafe {
236*9df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssemblePointBlockDiagonal(
237*9df49d7eSJed Brown                 self.ptr,
238*9df49d7eSJed Brown                 assembled.ptr,
239*9df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
240*9df49d7eSJed Brown             )
241*9df49d7eSJed Brown         };
242*9df49d7eSJed Brown         self.ceed.check_error(ierr)
243*9df49d7eSJed Brown     }
244*9df49d7eSJed Brown 
245*9df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
246*9df49d7eSJed Brown         &self,
247*9df49d7eSJed Brown         assembled: &mut Vector,
248*9df49d7eSJed Brown     ) -> crate::Result<i32> {
249*9df49d7eSJed Brown         let ierr = unsafe {
250*9df49d7eSJed Brown             bind_ceed::CeedOperatorLinearAssembleAddPointBlockDiagonal(
251*9df49d7eSJed Brown                 self.ptr,
252*9df49d7eSJed Brown                 assembled.ptr,
253*9df49d7eSJed Brown                 bind_ceed::CEED_REQUEST_IMMEDIATE,
254*9df49d7eSJed Brown             )
255*9df49d7eSJed Brown         };
256*9df49d7eSJed Brown         self.ceed.check_error(ierr)
257*9df49d7eSJed Brown     }
258*9df49d7eSJed Brown }
259*9df49d7eSJed Brown 
260*9df49d7eSJed Brown // -----------------------------------------------------------------------------
261*9df49d7eSJed Brown // Operator
262*9df49d7eSJed Brown // -----------------------------------------------------------------------------
263*9df49d7eSJed Brown impl<'a> Operator<'a> {
264*9df49d7eSJed Brown     // Constructor
265*9df49d7eSJed Brown     pub fn create<'b>(
266*9df49d7eSJed Brown         ceed: &'a crate::Ceed,
267*9df49d7eSJed Brown         qf: impl Into<QFunctionOpt<'b>>,
268*9df49d7eSJed Brown         dqf: impl Into<QFunctionOpt<'b>>,
269*9df49d7eSJed Brown         dqfT: impl Into<QFunctionOpt<'b>>,
270*9df49d7eSJed Brown     ) -> crate::Result<Self> {
271*9df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
272*9df49d7eSJed Brown         let ierr = unsafe {
273*9df49d7eSJed Brown             bind_ceed::CeedOperatorCreate(
274*9df49d7eSJed Brown                 ceed.ptr,
275*9df49d7eSJed Brown                 qf.into().to_raw(),
276*9df49d7eSJed Brown                 dqf.into().to_raw(),
277*9df49d7eSJed Brown                 dqfT.into().to_raw(),
278*9df49d7eSJed Brown                 &mut ptr,
279*9df49d7eSJed Brown             )
280*9df49d7eSJed Brown         };
281*9df49d7eSJed Brown         ceed.check_error(ierr)?;
282*9df49d7eSJed Brown         Ok(Self {
283*9df49d7eSJed Brown             op_core: OperatorCore { ceed, ptr },
284*9df49d7eSJed Brown         })
285*9df49d7eSJed Brown     }
286*9df49d7eSJed Brown 
287*9df49d7eSJed Brown     fn from_raw(ceed: &'a crate::Ceed, ptr: bind_ceed::CeedOperator) -> crate::Result<Self> {
288*9df49d7eSJed Brown         Ok(Self {
289*9df49d7eSJed Brown             op_core: OperatorCore { ceed, ptr },
290*9df49d7eSJed Brown         })
291*9df49d7eSJed Brown     }
292*9df49d7eSJed Brown 
293*9df49d7eSJed Brown     /// Apply Operator to a vector
294*9df49d7eSJed Brown     ///
295*9df49d7eSJed Brown     /// * `input`  - Input Vector
296*9df49d7eSJed Brown     /// * `output` - Output Vector
297*9df49d7eSJed Brown     ///
298*9df49d7eSJed Brown     /// ```
299*9df49d7eSJed Brown     /// # use libceed::prelude::*;
300*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
301*9df49d7eSJed Brown     /// let ne = 4;
302*9df49d7eSJed Brown     /// let p = 3;
303*9df49d7eSJed Brown     /// let q = 4;
304*9df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
305*9df49d7eSJed Brown     ///
306*9df49d7eSJed Brown     /// // Vectors
307*9df49d7eSJed Brown     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0]).unwrap();
308*9df49d7eSJed Brown     /// let mut qdata = ceed.vector(ne * q).unwrap();
309*9df49d7eSJed Brown     /// qdata.set_value(0.0);
310*9df49d7eSJed Brown     /// let u = ceed.vector_from_slice(&vec![1.0; ndofs]).unwrap();
311*9df49d7eSJed Brown     /// let mut v = ceed.vector(ndofs).unwrap();
312*9df49d7eSJed Brown     /// v.set_value(0.0);
313*9df49d7eSJed Brown     ///
314*9df49d7eSJed Brown     /// // Restrictions
315*9df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
316*9df49d7eSJed Brown     /// for i in 0..ne {
317*9df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
318*9df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
319*9df49d7eSJed Brown     /// }
320*9df49d7eSJed Brown     /// let rx = ceed
321*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
322*9df49d7eSJed Brown     ///     .unwrap();
323*9df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
324*9df49d7eSJed Brown     /// for i in 0..ne {
325*9df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
326*9df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
327*9df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
328*9df49d7eSJed Brown     /// }
329*9df49d7eSJed Brown     /// let ru = ceed
330*9df49d7eSJed Brown     ///     .elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)
331*9df49d7eSJed Brown     ///     .unwrap();
332*9df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
333*9df49d7eSJed Brown     /// let rq = ceed
334*9df49d7eSJed Brown     ///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
335*9df49d7eSJed Brown     ///     .unwrap();
336*9df49d7eSJed Brown     ///
337*9df49d7eSJed Brown     /// // Bases
338*9df49d7eSJed Brown     /// let bx = ceed
339*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
340*9df49d7eSJed Brown     ///     .unwrap();
341*9df49d7eSJed Brown     /// let bu = ceed
342*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)
343*9df49d7eSJed Brown     ///     .unwrap();
344*9df49d7eSJed Brown     ///
345*9df49d7eSJed Brown     /// // Build quadrature data
346*9df49d7eSJed Brown     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
347*9df49d7eSJed Brown     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)
348*9df49d7eSJed Brown     ///     .unwrap()
349*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
350*9df49d7eSJed Brown     ///     .unwrap()
351*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
352*9df49d7eSJed Brown     ///     .unwrap()
353*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
354*9df49d7eSJed Brown     ///     .unwrap()
355*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata)
356*9df49d7eSJed Brown     ///     .unwrap();
357*9df49d7eSJed Brown     ///
358*9df49d7eSJed Brown     /// // Mass operator
359*9df49d7eSJed Brown     /// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
360*9df49d7eSJed Brown     /// let op_mass = ceed
361*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
362*9df49d7eSJed Brown     ///     .unwrap()
363*9df49d7eSJed Brown     ///     .field("u", &ru, &bu, VectorOpt::Active)
364*9df49d7eSJed Brown     ///     .unwrap()
365*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata)
366*9df49d7eSJed Brown     ///     .unwrap()
367*9df49d7eSJed Brown     ///     .field("v", &ru, &bu, VectorOpt::Active)
368*9df49d7eSJed Brown     ///     .unwrap();
369*9df49d7eSJed Brown     ///
370*9df49d7eSJed Brown     /// v.set_value(0.0);
371*9df49d7eSJed Brown     /// op_mass.apply(&u, &mut v).unwrap();
372*9df49d7eSJed Brown     ///
373*9df49d7eSJed Brown     /// // Check
374*9df49d7eSJed Brown     /// let sum: f64 = v.view().iter().sum();
375*9df49d7eSJed Brown     /// assert!(
376*9df49d7eSJed Brown     ///     (sum - 2.0).abs() < 1e-15,
377*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
378*9df49d7eSJed Brown     /// );
379*9df49d7eSJed Brown     /// ```
380*9df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
381*9df49d7eSJed Brown         self.op_core.apply(input, output)
382*9df49d7eSJed Brown     }
383*9df49d7eSJed Brown 
384*9df49d7eSJed Brown     /// Apply Operator to a vector and add result to output vector
385*9df49d7eSJed Brown     ///
386*9df49d7eSJed Brown     /// * `input`  - Input Vector
387*9df49d7eSJed Brown     /// * `output` - Output Vector
388*9df49d7eSJed Brown     ///
389*9df49d7eSJed Brown     /// ```
390*9df49d7eSJed Brown     /// # use libceed::prelude::*;
391*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
392*9df49d7eSJed Brown     /// let ne = 4;
393*9df49d7eSJed Brown     /// let p = 3;
394*9df49d7eSJed Brown     /// let q = 4;
395*9df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
396*9df49d7eSJed Brown     ///
397*9df49d7eSJed Brown     /// // Vectors
398*9df49d7eSJed Brown     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0]).unwrap();
399*9df49d7eSJed Brown     /// let mut qdata = ceed.vector(ne * q).unwrap();
400*9df49d7eSJed Brown     /// qdata.set_value(0.0);
401*9df49d7eSJed Brown     /// let u = ceed.vector_from_slice(&vec![1.0; ndofs]).unwrap();
402*9df49d7eSJed Brown     /// let mut v = ceed.vector(ndofs).unwrap();
403*9df49d7eSJed Brown     ///
404*9df49d7eSJed Brown     /// // Restrictions
405*9df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
406*9df49d7eSJed Brown     /// for i in 0..ne {
407*9df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
408*9df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
409*9df49d7eSJed Brown     /// }
410*9df49d7eSJed Brown     /// let rx = ceed
411*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
412*9df49d7eSJed Brown     ///     .unwrap();
413*9df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
414*9df49d7eSJed Brown     /// for i in 0..ne {
415*9df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
416*9df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
417*9df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
418*9df49d7eSJed Brown     /// }
419*9df49d7eSJed Brown     /// let ru = ceed
420*9df49d7eSJed Brown     ///     .elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)
421*9df49d7eSJed Brown     ///     .unwrap();
422*9df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
423*9df49d7eSJed Brown     /// let rq = ceed
424*9df49d7eSJed Brown     ///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
425*9df49d7eSJed Brown     ///     .unwrap();
426*9df49d7eSJed Brown     ///
427*9df49d7eSJed Brown     /// // Bases
428*9df49d7eSJed Brown     /// let bx = ceed
429*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
430*9df49d7eSJed Brown     ///     .unwrap();
431*9df49d7eSJed Brown     /// let bu = ceed
432*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)
433*9df49d7eSJed Brown     ///     .unwrap();
434*9df49d7eSJed Brown     ///
435*9df49d7eSJed Brown     /// // Build quadrature data
436*9df49d7eSJed Brown     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
437*9df49d7eSJed Brown     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)
438*9df49d7eSJed Brown     ///     .unwrap()
439*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
440*9df49d7eSJed Brown     ///     .unwrap()
441*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
442*9df49d7eSJed Brown     ///     .unwrap()
443*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
444*9df49d7eSJed Brown     ///     .unwrap()
445*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata)
446*9df49d7eSJed Brown     ///     .unwrap();
447*9df49d7eSJed Brown     ///
448*9df49d7eSJed Brown     /// // Mass operator
449*9df49d7eSJed Brown     /// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
450*9df49d7eSJed Brown     /// let op_mass = ceed
451*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
452*9df49d7eSJed Brown     ///     .unwrap()
453*9df49d7eSJed Brown     ///     .field("u", &ru, &bu, VectorOpt::Active)
454*9df49d7eSJed Brown     ///     .unwrap()
455*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata)
456*9df49d7eSJed Brown     ///     .unwrap()
457*9df49d7eSJed Brown     ///     .field("v", &ru, &bu, VectorOpt::Active)
458*9df49d7eSJed Brown     ///     .unwrap();
459*9df49d7eSJed Brown     ///
460*9df49d7eSJed Brown     /// v.set_value(1.0);
461*9df49d7eSJed Brown     /// op_mass.apply_add(&u, &mut v).unwrap();
462*9df49d7eSJed Brown     ///
463*9df49d7eSJed Brown     /// // Check
464*9df49d7eSJed Brown     /// let sum: f64 = v.view().iter().sum();
465*9df49d7eSJed Brown     /// assert!(
466*9df49d7eSJed Brown     ///     (sum - (2.0 + ndofs as f64)).abs() < 1e-15,
467*9df49d7eSJed Brown     ///     "Incorrect interval length computed and added"
468*9df49d7eSJed Brown     /// );
469*9df49d7eSJed Brown     /// ```
470*9df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
471*9df49d7eSJed Brown         self.op_core.apply_add(input, output)
472*9df49d7eSJed Brown     }
473*9df49d7eSJed Brown 
474*9df49d7eSJed Brown     /// Provide a field to a Operator for use by its QFunction
475*9df49d7eSJed Brown     ///
476*9df49d7eSJed Brown     /// * `fieldname` - Name of the field (to be matched with the name used by
477*9df49d7eSJed Brown     ///                   the QFunction)
478*9df49d7eSJed Brown     /// * `r`         - ElemRestriction
479*9df49d7eSJed Brown     /// * `b`         - Basis in which the field resides or `BasisCollocated` if
480*9df49d7eSJed Brown     ///                   collocated with quadrature points
481*9df49d7eSJed Brown     /// * `v`         - Vector to be used by Operator or `VectorActive` if field
482*9df49d7eSJed Brown     ///                   is active or `VectorNone` if using `Weight` with the
483*9df49d7eSJed Brown     ///                   QFunction
484*9df49d7eSJed Brown     ///
485*9df49d7eSJed Brown     ///
486*9df49d7eSJed Brown     /// ```
487*9df49d7eSJed Brown     /// # use libceed::prelude::*;
488*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
489*9df49d7eSJed Brown     /// let qf = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
490*9df49d7eSJed Brown     /// let mut op = ceed
491*9df49d7eSJed Brown     ///     .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)
492*9df49d7eSJed Brown     ///     .unwrap();
493*9df49d7eSJed Brown     ///
494*9df49d7eSJed Brown     /// // Operator field arguments
495*9df49d7eSJed Brown     /// let ne = 3;
496*9df49d7eSJed Brown     /// let q = 4;
497*9df49d7eSJed Brown     /// let mut ind: Vec<i32> = vec![0; 2 * ne];
498*9df49d7eSJed Brown     /// for i in 0..ne {
499*9df49d7eSJed Brown     ///     ind[2 * i + 0] = i as i32;
500*9df49d7eSJed Brown     ///     ind[2 * i + 1] = (i + 1) as i32;
501*9df49d7eSJed Brown     /// }
502*9df49d7eSJed Brown     /// let r = ceed
503*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)
504*9df49d7eSJed Brown     ///     .unwrap();
505*9df49d7eSJed Brown     ///
506*9df49d7eSJed Brown     /// let b = ceed
507*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
508*9df49d7eSJed Brown     ///     .unwrap();
509*9df49d7eSJed Brown     ///
510*9df49d7eSJed Brown     /// // Operator field
511*9df49d7eSJed Brown     /// op = op.field("dx", &r, &b, VectorOpt::Active).unwrap();
512*9df49d7eSJed Brown     /// ```
513*9df49d7eSJed Brown     #[allow(unused_mut)]
514*9df49d7eSJed Brown     pub fn field<'b>(
515*9df49d7eSJed Brown         mut self,
516*9df49d7eSJed Brown         fieldname: &str,
517*9df49d7eSJed Brown         r: impl Into<ElemRestrictionOpt<'b>>,
518*9df49d7eSJed Brown         b: impl Into<BasisOpt<'b>>,
519*9df49d7eSJed Brown         v: impl Into<VectorOpt<'b>>,
520*9df49d7eSJed Brown     ) -> crate::Result<Self> {
521*9df49d7eSJed Brown         let fieldname = CString::new(fieldname).expect("CString::new failed");
522*9df49d7eSJed Brown         let fieldname = fieldname.as_ptr() as *const i8;
523*9df49d7eSJed Brown         let ierr = unsafe {
524*9df49d7eSJed Brown             bind_ceed::CeedOperatorSetField(
525*9df49d7eSJed Brown                 self.op_core.ptr,
526*9df49d7eSJed Brown                 fieldname,
527*9df49d7eSJed Brown                 r.into().to_raw(),
528*9df49d7eSJed Brown                 b.into().to_raw(),
529*9df49d7eSJed Brown                 v.into().to_raw(),
530*9df49d7eSJed Brown             )
531*9df49d7eSJed Brown         };
532*9df49d7eSJed Brown         self.op_core.ceed.check_error(ierr)?;
533*9df49d7eSJed Brown         Ok(self)
534*9df49d7eSJed Brown     }
535*9df49d7eSJed Brown 
536*9df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
537*9df49d7eSJed Brown     ///
538*9df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
539*9df49d7eSJed Brown     ///
540*9df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
541*9df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
542*9df49d7eSJed Brown     ///
543*9df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
544*9df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
545*9df49d7eSJed Brown     ///
546*9df49d7eSJed Brown     /// ```
547*9df49d7eSJed Brown     /// # use libceed::prelude::*;
548*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
549*9df49d7eSJed Brown     /// let ne = 4;
550*9df49d7eSJed Brown     /// let p = 3;
551*9df49d7eSJed Brown     /// let q = 4;
552*9df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
553*9df49d7eSJed Brown     ///
554*9df49d7eSJed Brown     /// // Vectors
555*9df49d7eSJed Brown     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0]).unwrap();
556*9df49d7eSJed Brown     /// let mut qdata = ceed.vector(ne * q).unwrap();
557*9df49d7eSJed Brown     /// qdata.set_value(0.0);
558*9df49d7eSJed Brown     /// let mut u = ceed.vector(ndofs).unwrap();
559*9df49d7eSJed Brown     /// u.set_value(1.0);
560*9df49d7eSJed Brown     /// let mut v = ceed.vector(ndofs).unwrap();
561*9df49d7eSJed Brown     /// v.set_value(0.0);
562*9df49d7eSJed Brown     ///
563*9df49d7eSJed Brown     /// // Restrictions
564*9df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
565*9df49d7eSJed Brown     /// for i in 0..ne {
566*9df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
567*9df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
568*9df49d7eSJed Brown     /// }
569*9df49d7eSJed Brown     /// let rx = ceed
570*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
571*9df49d7eSJed Brown     ///     .unwrap();
572*9df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
573*9df49d7eSJed Brown     /// for i in 0..ne {
574*9df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
575*9df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
576*9df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
577*9df49d7eSJed Brown     /// }
578*9df49d7eSJed Brown     /// let ru = ceed
579*9df49d7eSJed Brown     ///     .elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)
580*9df49d7eSJed Brown     ///     .unwrap();
581*9df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
582*9df49d7eSJed Brown     /// let rq = ceed
583*9df49d7eSJed Brown     ///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
584*9df49d7eSJed Brown     ///     .unwrap();
585*9df49d7eSJed Brown     ///
586*9df49d7eSJed Brown     /// // Bases
587*9df49d7eSJed Brown     /// let bx = ceed
588*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
589*9df49d7eSJed Brown     ///     .unwrap();
590*9df49d7eSJed Brown     /// let bu = ceed
591*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)
592*9df49d7eSJed Brown     ///     .unwrap();
593*9df49d7eSJed Brown     ///
594*9df49d7eSJed Brown     /// // Build quadrature data
595*9df49d7eSJed Brown     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
596*9df49d7eSJed Brown     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)
597*9df49d7eSJed Brown     ///     .unwrap()
598*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
599*9df49d7eSJed Brown     ///     .unwrap()
600*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
601*9df49d7eSJed Brown     ///     .unwrap()
602*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
603*9df49d7eSJed Brown     ///     .unwrap()
604*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata)
605*9df49d7eSJed Brown     ///     .unwrap();
606*9df49d7eSJed Brown     ///
607*9df49d7eSJed Brown     /// // Mass operator
608*9df49d7eSJed Brown     /// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
609*9df49d7eSJed Brown     /// let op_mass = ceed
610*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
611*9df49d7eSJed Brown     ///     .unwrap()
612*9df49d7eSJed Brown     ///     .field("u", &ru, &bu, VectorOpt::Active)
613*9df49d7eSJed Brown     ///     .unwrap()
614*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata)
615*9df49d7eSJed Brown     ///     .unwrap()
616*9df49d7eSJed Brown     ///     .field("v", &ru, &bu, VectorOpt::Active)
617*9df49d7eSJed Brown     ///     .unwrap();
618*9df49d7eSJed Brown     ///
619*9df49d7eSJed Brown     /// // Diagonal
620*9df49d7eSJed Brown     /// let mut diag = ceed.vector(ndofs).unwrap();
621*9df49d7eSJed Brown     /// diag.set_value(0.0);
622*9df49d7eSJed Brown     /// op_mass.linear_assemble_diagonal(&mut diag).unwrap();
623*9df49d7eSJed Brown     ///
624*9df49d7eSJed Brown     /// // Manual diagonal computation
625*9df49d7eSJed Brown     /// let mut true_diag = ceed.vector(ndofs).unwrap();
626*9df49d7eSJed Brown     /// for i in 0..ndofs {
627*9df49d7eSJed Brown     ///     u.set_value(0.0);
628*9df49d7eSJed Brown     ///     {
629*9df49d7eSJed Brown     ///         let mut u_array = u.view_mut();
630*9df49d7eSJed Brown     ///         u_array[i] = 1.;
631*9df49d7eSJed Brown     ///     }
632*9df49d7eSJed Brown     ///
633*9df49d7eSJed Brown     ///     op_mass.apply(&u, &mut v).unwrap();
634*9df49d7eSJed Brown     ///
635*9df49d7eSJed Brown     ///     {
636*9df49d7eSJed Brown     ///         let v_array = v.view_mut();
637*9df49d7eSJed Brown     ///         let mut true_array = true_diag.view_mut();
638*9df49d7eSJed Brown     ///         true_array[i] = v_array[i];
639*9df49d7eSJed Brown     ///     }
640*9df49d7eSJed Brown     /// }
641*9df49d7eSJed Brown     ///
642*9df49d7eSJed Brown     /// // Check
643*9df49d7eSJed Brown     /// diag.view()
644*9df49d7eSJed Brown     ///     .iter()
645*9df49d7eSJed Brown     ///     .zip(true_diag.view().iter())
646*9df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
647*9df49d7eSJed Brown     ///         assert!(
648*9df49d7eSJed Brown     ///             (*computed - *actual).abs() < 1e-15,
649*9df49d7eSJed Brown     ///             "Diagonal entry incorrect"
650*9df49d7eSJed Brown     ///         );
651*9df49d7eSJed Brown     ///     });
652*9df49d7eSJed Brown     /// ```
653*9df49d7eSJed Brown     pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
654*9df49d7eSJed Brown         self.op_core.linear_assemble_diagonal(assembled)
655*9df49d7eSJed Brown     }
656*9df49d7eSJed Brown 
657*9df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
658*9df49d7eSJed Brown     ///
659*9df49d7eSJed Brown     /// This sums into a Vector with the diagonal of a linear Operator.
660*9df49d7eSJed Brown     ///
661*9df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
662*9df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
663*9df49d7eSJed Brown     ///
664*9df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
665*9df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
666*9df49d7eSJed Brown     ///
667*9df49d7eSJed Brown     ///
668*9df49d7eSJed Brown     /// ```
669*9df49d7eSJed Brown     /// # use libceed::prelude::*;
670*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
671*9df49d7eSJed Brown     /// let ne = 4;
672*9df49d7eSJed Brown     /// let p = 3;
673*9df49d7eSJed Brown     /// let q = 4;
674*9df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
675*9df49d7eSJed Brown     ///
676*9df49d7eSJed Brown     /// // Vectors
677*9df49d7eSJed Brown     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0]).unwrap();
678*9df49d7eSJed Brown     /// let mut qdata = ceed.vector(ne * q).unwrap();
679*9df49d7eSJed Brown     /// qdata.set_value(0.0);
680*9df49d7eSJed Brown     /// let mut u = ceed.vector(ndofs).unwrap();
681*9df49d7eSJed Brown     /// u.set_value(1.0);
682*9df49d7eSJed Brown     /// let mut v = ceed.vector(ndofs).unwrap();
683*9df49d7eSJed Brown     /// v.set_value(0.0);
684*9df49d7eSJed Brown     ///
685*9df49d7eSJed Brown     /// // Restrictions
686*9df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
687*9df49d7eSJed Brown     /// for i in 0..ne {
688*9df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
689*9df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
690*9df49d7eSJed Brown     /// }
691*9df49d7eSJed Brown     /// let rx = ceed
692*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
693*9df49d7eSJed Brown     ///     .unwrap();
694*9df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
695*9df49d7eSJed Brown     /// for i in 0..ne {
696*9df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
697*9df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
698*9df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
699*9df49d7eSJed Brown     /// }
700*9df49d7eSJed Brown     /// let ru = ceed
701*9df49d7eSJed Brown     ///     .elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)
702*9df49d7eSJed Brown     ///     .unwrap();
703*9df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
704*9df49d7eSJed Brown     /// let rq = ceed
705*9df49d7eSJed Brown     ///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
706*9df49d7eSJed Brown     ///     .unwrap();
707*9df49d7eSJed Brown     ///
708*9df49d7eSJed Brown     /// // Bases
709*9df49d7eSJed Brown     /// let bx = ceed
710*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
711*9df49d7eSJed Brown     ///     .unwrap();
712*9df49d7eSJed Brown     /// let bu = ceed
713*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)
714*9df49d7eSJed Brown     ///     .unwrap();
715*9df49d7eSJed Brown     ///
716*9df49d7eSJed Brown     /// // Build quadrature data
717*9df49d7eSJed Brown     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
718*9df49d7eSJed Brown     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)
719*9df49d7eSJed Brown     ///     .unwrap()
720*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
721*9df49d7eSJed Brown     ///     .unwrap()
722*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
723*9df49d7eSJed Brown     ///     .unwrap()
724*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
725*9df49d7eSJed Brown     ///     .unwrap()
726*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata)
727*9df49d7eSJed Brown     ///     .unwrap();
728*9df49d7eSJed Brown     ///
729*9df49d7eSJed Brown     /// // Mass operator
730*9df49d7eSJed Brown     /// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
731*9df49d7eSJed Brown     /// let op_mass = ceed
732*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
733*9df49d7eSJed Brown     ///     .unwrap()
734*9df49d7eSJed Brown     ///     .field("u", &ru, &bu, VectorOpt::Active)
735*9df49d7eSJed Brown     ///     .unwrap()
736*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata)
737*9df49d7eSJed Brown     ///     .unwrap()
738*9df49d7eSJed Brown     ///     .field("v", &ru, &bu, VectorOpt::Active)
739*9df49d7eSJed Brown     ///     .unwrap();
740*9df49d7eSJed Brown     ///
741*9df49d7eSJed Brown     /// // Diagonal
742*9df49d7eSJed Brown     /// let mut diag = ceed.vector(ndofs).unwrap();
743*9df49d7eSJed Brown     /// diag.set_value(1.0);
744*9df49d7eSJed Brown     /// op_mass.linear_assemble_add_diagonal(&mut diag).unwrap();
745*9df49d7eSJed Brown     ///
746*9df49d7eSJed Brown     /// // Manual diagonal computation
747*9df49d7eSJed Brown     /// let mut true_diag = ceed.vector(ndofs).unwrap();
748*9df49d7eSJed Brown     /// for i in 0..ndofs {
749*9df49d7eSJed Brown     ///     u.set_value(0.0);
750*9df49d7eSJed Brown     ///     {
751*9df49d7eSJed Brown     ///         let mut u_array = u.view_mut();
752*9df49d7eSJed Brown     ///         u_array[i] = 1.;
753*9df49d7eSJed Brown     ///     }
754*9df49d7eSJed Brown     ///
755*9df49d7eSJed Brown     ///     op_mass.apply(&u, &mut v).unwrap();
756*9df49d7eSJed Brown     ///
757*9df49d7eSJed Brown     ///     {
758*9df49d7eSJed Brown     ///         let v_array = v.view_mut();
759*9df49d7eSJed Brown     ///         let mut true_array = true_diag.view_mut();
760*9df49d7eSJed Brown     ///         true_array[i] = v_array[i] + 1.0;
761*9df49d7eSJed Brown     ///     }
762*9df49d7eSJed Brown     /// }
763*9df49d7eSJed Brown     ///
764*9df49d7eSJed Brown     /// // Check
765*9df49d7eSJed Brown     /// diag.view()
766*9df49d7eSJed Brown     ///     .iter()
767*9df49d7eSJed Brown     ///     .zip(true_diag.view().iter())
768*9df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
769*9df49d7eSJed Brown     ///         assert!(
770*9df49d7eSJed Brown     ///             (*computed - *actual).abs() < 1e-15,
771*9df49d7eSJed Brown     ///             "Diagonal entry incorrect"
772*9df49d7eSJed Brown     ///         );
773*9df49d7eSJed Brown     ///     });
774*9df49d7eSJed Brown     /// ```
775*9df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
776*9df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
777*9df49d7eSJed Brown     }
778*9df49d7eSJed Brown 
779*9df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
780*9df49d7eSJed Brown     ///
781*9df49d7eSJed Brown     /// This overwrites a Vector with the point block diagonal of a linear
782*9df49d7eSJed Brown     /// Operator.
783*9df49d7eSJed Brown     ///
784*9df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
785*9df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
786*9df49d7eSJed Brown     ///
787*9df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
788*9df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
789*9df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
790*9df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
791*9df49d7eSJed Brown     ///                   this vector are derived from the active vector for
792*9df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
793*9df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
794*9df49d7eSJed Brown     ///
795*9df49d7eSJed Brown     /// ```
796*9df49d7eSJed Brown     /// # use libceed::prelude::*;
797*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
798*9df49d7eSJed Brown     /// let ne = 4;
799*9df49d7eSJed Brown     /// let p = 3;
800*9df49d7eSJed Brown     /// let q = 4;
801*9df49d7eSJed Brown     /// let ncomp = 2;
802*9df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
803*9df49d7eSJed Brown     ///
804*9df49d7eSJed Brown     /// // Vectors
805*9df49d7eSJed Brown     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0]).unwrap();
806*9df49d7eSJed Brown     /// let mut qdata = ceed.vector(ne * q).unwrap();
807*9df49d7eSJed Brown     /// qdata.set_value(0.0);
808*9df49d7eSJed Brown     /// let mut u = ceed.vector(ncomp * ndofs).unwrap();
809*9df49d7eSJed Brown     /// u.set_value(1.0);
810*9df49d7eSJed Brown     /// let mut v = ceed.vector(ncomp * ndofs).unwrap();
811*9df49d7eSJed Brown     /// v.set_value(0.0);
812*9df49d7eSJed Brown     ///
813*9df49d7eSJed Brown     /// // Restrictions
814*9df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
815*9df49d7eSJed Brown     /// for i in 0..ne {
816*9df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
817*9df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
818*9df49d7eSJed Brown     /// }
819*9df49d7eSJed Brown     /// let rx = ceed
820*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
821*9df49d7eSJed Brown     ///     .unwrap();
822*9df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
823*9df49d7eSJed Brown     /// for i in 0..ne {
824*9df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
825*9df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
826*9df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
827*9df49d7eSJed Brown     /// }
828*9df49d7eSJed Brown     /// let ru = ceed
829*9df49d7eSJed Brown     ///     .elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)
830*9df49d7eSJed Brown     ///     .unwrap();
831*9df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
832*9df49d7eSJed Brown     /// let rq = ceed
833*9df49d7eSJed Brown     ///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
834*9df49d7eSJed Brown     ///     .unwrap();
835*9df49d7eSJed Brown     ///
836*9df49d7eSJed Brown     /// // Bases
837*9df49d7eSJed Brown     /// let bx = ceed
838*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
839*9df49d7eSJed Brown     ///     .unwrap();
840*9df49d7eSJed Brown     /// let bu = ceed
841*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)
842*9df49d7eSJed Brown     ///     .unwrap();
843*9df49d7eSJed Brown     ///
844*9df49d7eSJed Brown     /// // Build quadrature data
845*9df49d7eSJed Brown     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
846*9df49d7eSJed Brown     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)
847*9df49d7eSJed Brown     ///     .unwrap()
848*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
849*9df49d7eSJed Brown     ///     .unwrap()
850*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
851*9df49d7eSJed Brown     ///     .unwrap()
852*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
853*9df49d7eSJed Brown     ///     .unwrap()
854*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata)
855*9df49d7eSJed Brown     ///     .unwrap();
856*9df49d7eSJed Brown     ///
857*9df49d7eSJed Brown     /// // Mass operator
858*9df49d7eSJed Brown     /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
859*9df49d7eSJed Brown     ///     // Number of quadrature points
860*9df49d7eSJed Brown     ///     let q = qdata.len();
861*9df49d7eSJed Brown     ///
862*9df49d7eSJed Brown     ///     // Iterate over quadrature points
863*9df49d7eSJed Brown     ///     for i in 0..q {
864*9df49d7eSJed Brown     ///         v[i + 0 * q] = u[i + 1 * q] * qdata[i];
865*9df49d7eSJed Brown     ///         v[i + 1 * q] = u[i + 0 * q] * qdata[i];
866*9df49d7eSJed Brown     ///     }
867*9df49d7eSJed Brown     ///
868*9df49d7eSJed Brown     ///     // Return clean error code
869*9df49d7eSJed Brown     ///     0
870*9df49d7eSJed Brown     /// };
871*9df49d7eSJed Brown     ///
872*9df49d7eSJed Brown     /// let qf_mass = ceed
873*9df49d7eSJed Brown     ///     .q_function_interior(1, Box::new(mass_2_comp))
874*9df49d7eSJed Brown     ///     .unwrap()
875*9df49d7eSJed Brown     ///     .input("u", 2, EvalMode::Interp)
876*9df49d7eSJed Brown     ///     .unwrap()
877*9df49d7eSJed Brown     ///     .input("qdata", 1, EvalMode::None)
878*9df49d7eSJed Brown     ///     .unwrap()
879*9df49d7eSJed Brown     ///     .output("v", 2, EvalMode::Interp)
880*9df49d7eSJed Brown     ///     .unwrap();
881*9df49d7eSJed Brown     ///
882*9df49d7eSJed Brown     /// let op_mass = ceed
883*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
884*9df49d7eSJed Brown     ///     .unwrap()
885*9df49d7eSJed Brown     ///     .field("u", &ru, &bu, VectorOpt::Active)
886*9df49d7eSJed Brown     ///     .unwrap()
887*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata)
888*9df49d7eSJed Brown     ///     .unwrap()
889*9df49d7eSJed Brown     ///     .field("v", &ru, &bu, VectorOpt::Active)
890*9df49d7eSJed Brown     ///     .unwrap();
891*9df49d7eSJed Brown     ///
892*9df49d7eSJed Brown     /// // Diagonal
893*9df49d7eSJed Brown     /// let mut diag = ceed.vector(ncomp * ncomp * ndofs).unwrap();
894*9df49d7eSJed Brown     /// diag.set_value(0.0);
895*9df49d7eSJed Brown     /// op_mass
896*9df49d7eSJed Brown     ///     .linear_assemble_point_block_diagonal(&mut diag)
897*9df49d7eSJed Brown     ///     .unwrap();
898*9df49d7eSJed Brown     ///
899*9df49d7eSJed Brown     /// // Manual diagonal computation
900*9df49d7eSJed Brown     /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs).unwrap();
901*9df49d7eSJed Brown     /// for i in 0..ndofs {
902*9df49d7eSJed Brown     ///     for j in 0..ncomp {
903*9df49d7eSJed Brown     ///         u.set_value(0.0);
904*9df49d7eSJed Brown     ///         {
905*9df49d7eSJed Brown     ///             let mut u_array = u.view_mut();
906*9df49d7eSJed Brown     ///             u_array[i + j * ndofs] = 1.;
907*9df49d7eSJed Brown     ///         }
908*9df49d7eSJed Brown     ///
909*9df49d7eSJed Brown     ///         op_mass.apply(&u, &mut v).unwrap();
910*9df49d7eSJed Brown     ///
911*9df49d7eSJed Brown     ///         {
912*9df49d7eSJed Brown     ///             let v_array = v.view_mut();
913*9df49d7eSJed Brown     ///             let mut true_array = true_diag.view_mut();
914*9df49d7eSJed Brown     ///             for k in 0..ncomp {
915*9df49d7eSJed Brown     ///                 true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
916*9df49d7eSJed Brown     ///             }
917*9df49d7eSJed Brown     ///         }
918*9df49d7eSJed Brown     ///     }
919*9df49d7eSJed Brown     /// }
920*9df49d7eSJed Brown     ///
921*9df49d7eSJed Brown     /// // Check
922*9df49d7eSJed Brown     /// diag.view()
923*9df49d7eSJed Brown     ///     .iter()
924*9df49d7eSJed Brown     ///     .zip(true_diag.view().iter())
925*9df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
926*9df49d7eSJed Brown     ///         assert!(
927*9df49d7eSJed Brown     ///             (*computed - *actual).abs() < 1e-15,
928*9df49d7eSJed Brown     ///             "Diagonal entry incorrect"
929*9df49d7eSJed Brown     ///         );
930*9df49d7eSJed Brown     ///     });
931*9df49d7eSJed Brown     /// ```
932*9df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
933*9df49d7eSJed Brown         &self,
934*9df49d7eSJed Brown         assembled: &mut Vector,
935*9df49d7eSJed Brown     ) -> crate::Result<i32> {
936*9df49d7eSJed Brown         self.op_core.linear_assemble_point_block_diagonal(assembled)
937*9df49d7eSJed Brown     }
938*9df49d7eSJed Brown 
939*9df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
940*9df49d7eSJed Brown     ///
941*9df49d7eSJed Brown     /// This sums into a Vector with the point block diagonal of a linear
942*9df49d7eSJed Brown     /// Operator.
943*9df49d7eSJed Brown     ///
944*9df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
945*9df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
946*9df49d7eSJed Brown     ///
947*9df49d7eSJed Brown     /// * `op`        -     Operator to assemble QFunction
948*9df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
949*9df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
950*9df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
951*9df49d7eSJed Brown     ///                   this vector are derived from the active vector for
952*9df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
953*9df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
954*9df49d7eSJed Brown     ///
955*9df49d7eSJed Brown     /// ```
956*9df49d7eSJed Brown     /// # use libceed::prelude::*;
957*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
958*9df49d7eSJed Brown     /// let ne = 4;
959*9df49d7eSJed Brown     /// let p = 3;
960*9df49d7eSJed Brown     /// let q = 4;
961*9df49d7eSJed Brown     /// let ncomp = 2;
962*9df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
963*9df49d7eSJed Brown     ///
964*9df49d7eSJed Brown     /// // Vectors
965*9df49d7eSJed Brown     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0]).unwrap();
966*9df49d7eSJed Brown     /// let mut qdata = ceed.vector(ne * q).unwrap();
967*9df49d7eSJed Brown     /// qdata.set_value(0.0);
968*9df49d7eSJed Brown     /// let mut u = ceed.vector(ncomp * ndofs).unwrap();
969*9df49d7eSJed Brown     /// u.set_value(1.0);
970*9df49d7eSJed Brown     /// let mut v = ceed.vector(ncomp * ndofs).unwrap();
971*9df49d7eSJed Brown     /// v.set_value(0.0);
972*9df49d7eSJed Brown     ///
973*9df49d7eSJed Brown     /// // Restrictions
974*9df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
975*9df49d7eSJed Brown     /// for i in 0..ne {
976*9df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
977*9df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
978*9df49d7eSJed Brown     /// }
979*9df49d7eSJed Brown     /// let rx = ceed
980*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
981*9df49d7eSJed Brown     ///     .unwrap();
982*9df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
983*9df49d7eSJed Brown     /// for i in 0..ne {
984*9df49d7eSJed Brown     ///     indu[p * i + 0] = (2 * i) as i32;
985*9df49d7eSJed Brown     ///     indu[p * i + 1] = (2 * i + 1) as i32;
986*9df49d7eSJed Brown     ///     indu[p * i + 2] = (2 * i + 2) as i32;
987*9df49d7eSJed Brown     /// }
988*9df49d7eSJed Brown     /// let ru = ceed
989*9df49d7eSJed Brown     ///     .elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)
990*9df49d7eSJed Brown     ///     .unwrap();
991*9df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
992*9df49d7eSJed Brown     /// let rq = ceed
993*9df49d7eSJed Brown     ///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
994*9df49d7eSJed Brown     ///     .unwrap();
995*9df49d7eSJed Brown     ///
996*9df49d7eSJed Brown     /// // Bases
997*9df49d7eSJed Brown     /// let bx = ceed
998*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
999*9df49d7eSJed Brown     ///     .unwrap();
1000*9df49d7eSJed Brown     /// let bu = ceed
1001*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)
1002*9df49d7eSJed Brown     ///     .unwrap();
1003*9df49d7eSJed Brown     ///
1004*9df49d7eSJed Brown     /// // Build quadrature data
1005*9df49d7eSJed Brown     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
1006*9df49d7eSJed Brown     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)
1007*9df49d7eSJed Brown     ///     .unwrap()
1008*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
1009*9df49d7eSJed Brown     ///     .unwrap()
1010*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
1011*9df49d7eSJed Brown     ///     .unwrap()
1012*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
1013*9df49d7eSJed Brown     ///     .unwrap()
1014*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata)
1015*9df49d7eSJed Brown     ///     .unwrap();
1016*9df49d7eSJed Brown     ///
1017*9df49d7eSJed Brown     /// // Mass operator
1018*9df49d7eSJed Brown     /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
1019*9df49d7eSJed Brown     ///     // Number of quadrature points
1020*9df49d7eSJed Brown     ///     let q = qdata.len();
1021*9df49d7eSJed Brown     ///
1022*9df49d7eSJed Brown     ///     // Iterate over quadrature points
1023*9df49d7eSJed Brown     ///     for i in 0..q {
1024*9df49d7eSJed Brown     ///         v[i + 0 * q] = u[i + 1 * q] * qdata[i];
1025*9df49d7eSJed Brown     ///         v[i + 1 * q] = u[i + 0 * q] * qdata[i];
1026*9df49d7eSJed Brown     ///     }
1027*9df49d7eSJed Brown     ///
1028*9df49d7eSJed Brown     ///     // Return clean error code
1029*9df49d7eSJed Brown     ///     0
1030*9df49d7eSJed Brown     /// };
1031*9df49d7eSJed Brown     ///
1032*9df49d7eSJed Brown     /// let qf_mass = ceed
1033*9df49d7eSJed Brown     ///     .q_function_interior(1, Box::new(mass_2_comp))
1034*9df49d7eSJed Brown     ///     .unwrap()
1035*9df49d7eSJed Brown     ///     .input("u", 2, EvalMode::Interp)
1036*9df49d7eSJed Brown     ///     .unwrap()
1037*9df49d7eSJed Brown     ///     .input("qdata", 1, EvalMode::None)
1038*9df49d7eSJed Brown     ///     .unwrap()
1039*9df49d7eSJed Brown     ///     .output("v", 2, EvalMode::Interp)
1040*9df49d7eSJed Brown     ///     .unwrap();
1041*9df49d7eSJed Brown     ///
1042*9df49d7eSJed Brown     /// let op_mass = ceed
1043*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
1044*9df49d7eSJed Brown     ///     .unwrap()
1045*9df49d7eSJed Brown     ///     .field("u", &ru, &bu, VectorOpt::Active)
1046*9df49d7eSJed Brown     ///     .unwrap()
1047*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata)
1048*9df49d7eSJed Brown     ///     .unwrap()
1049*9df49d7eSJed Brown     ///     .field("v", &ru, &bu, VectorOpt::Active)
1050*9df49d7eSJed Brown     ///     .unwrap();
1051*9df49d7eSJed Brown     ///
1052*9df49d7eSJed Brown     /// // Diagonal
1053*9df49d7eSJed Brown     /// let mut diag = ceed.vector(ncomp * ncomp * ndofs).unwrap();
1054*9df49d7eSJed Brown     /// diag.set_value(1.0);
1055*9df49d7eSJed Brown     /// op_mass
1056*9df49d7eSJed Brown     ///     .linear_assemble_add_point_block_diagonal(&mut diag)
1057*9df49d7eSJed Brown     ///     .unwrap();
1058*9df49d7eSJed Brown     ///
1059*9df49d7eSJed Brown     /// // Manual diagonal computation
1060*9df49d7eSJed Brown     /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs).unwrap();
1061*9df49d7eSJed Brown     /// for i in 0..ndofs {
1062*9df49d7eSJed Brown     ///     for j in 0..ncomp {
1063*9df49d7eSJed Brown     ///         u.set_value(0.0);
1064*9df49d7eSJed Brown     ///         {
1065*9df49d7eSJed Brown     ///             let mut u_array = u.view_mut();
1066*9df49d7eSJed Brown     ///             u_array[i + j * ndofs] = 1.;
1067*9df49d7eSJed Brown     ///         }
1068*9df49d7eSJed Brown     ///
1069*9df49d7eSJed Brown     ///         op_mass.apply(&u, &mut v).unwrap();
1070*9df49d7eSJed Brown     ///
1071*9df49d7eSJed Brown     ///         {
1072*9df49d7eSJed Brown     ///             let v_array = v.view_mut();
1073*9df49d7eSJed Brown     ///             let mut true_array = true_diag.view_mut();
1074*9df49d7eSJed Brown     ///             for k in 0..ncomp {
1075*9df49d7eSJed Brown     ///                 true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
1076*9df49d7eSJed Brown     ///             }
1077*9df49d7eSJed Brown     ///         }
1078*9df49d7eSJed Brown     ///     }
1079*9df49d7eSJed Brown     /// }
1080*9df49d7eSJed Brown     ///
1081*9df49d7eSJed Brown     /// // Check
1082*9df49d7eSJed Brown     /// diag.view()
1083*9df49d7eSJed Brown     ///     .iter()
1084*9df49d7eSJed Brown     ///     .zip(true_diag.view().iter())
1085*9df49d7eSJed Brown     ///     .for_each(|(computed, actual)| {
1086*9df49d7eSJed Brown     ///         assert!(
1087*9df49d7eSJed Brown     ///             (*computed - 1.0 - *actual).abs() < 1e-15,
1088*9df49d7eSJed Brown     ///             "Diagonal entry incorrect"
1089*9df49d7eSJed Brown     ///         );
1090*9df49d7eSJed Brown     ///     });
1091*9df49d7eSJed Brown     /// ```
1092*9df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
1093*9df49d7eSJed Brown         &self,
1094*9df49d7eSJed Brown         assembled: &mut Vector,
1095*9df49d7eSJed Brown     ) -> crate::Result<i32> {
1096*9df49d7eSJed Brown         self.op_core
1097*9df49d7eSJed Brown             .linear_assemble_add_point_block_diagonal(assembled)
1098*9df49d7eSJed Brown     }
1099*9df49d7eSJed Brown 
1100*9df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
1101*9df49d7eSJed Brown     ///   given Operator, creating the prolongation basis from the fine and
1102*9df49d7eSJed Brown     ///   coarse grid interpolation
1103*9df49d7eSJed Brown     ///
1104*9df49d7eSJed Brown     /// * `p_mult_fine`  - Lvector multiplicity in parallel gather/scatter
1105*9df49d7eSJed Brown     /// * `rstr_coarse`  - Coarse grid restriction
1106*9df49d7eSJed Brown     /// * `basis_coarse` - Coarse grid active vector basis
1107*9df49d7eSJed Brown     ///
1108*9df49d7eSJed Brown     /// ```
1109*9df49d7eSJed Brown     /// # use libceed::prelude::*;
1110*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
1111*9df49d7eSJed Brown     /// let ne = 15;
1112*9df49d7eSJed Brown     /// let p_coarse = 3;
1113*9df49d7eSJed Brown     /// let p_fine = 5;
1114*9df49d7eSJed Brown     /// let q = 6;
1115*9df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
1116*9df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
1117*9df49d7eSJed Brown     ///
1118*9df49d7eSJed Brown     /// // Vectors
1119*9df49d7eSJed Brown     /// let x_array = (0..ne + 1)
1120*9df49d7eSJed Brown     ///     .map(|i| 2.0 * i as f64 / ne as f64 - 1.0)
1121*9df49d7eSJed Brown     ///     .collect::<Vec<f64>>();
1122*9df49d7eSJed Brown     /// let x = ceed.vector_from_slice(&x_array).unwrap();
1123*9df49d7eSJed Brown     /// let mut qdata = ceed.vector(ne * q).unwrap();
1124*9df49d7eSJed Brown     /// qdata.set_value(0.0);
1125*9df49d7eSJed Brown     /// let mut u_coarse = ceed.vector(ndofs_coarse).unwrap();
1126*9df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1127*9df49d7eSJed Brown     /// let mut u_fine = ceed.vector(ndofs_fine).unwrap();
1128*9df49d7eSJed Brown     /// u_fine.set_value(1.0);
1129*9df49d7eSJed Brown     /// let mut v_coarse = ceed.vector(ndofs_coarse).unwrap();
1130*9df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1131*9df49d7eSJed Brown     /// let mut v_fine = ceed.vector(ndofs_fine).unwrap();
1132*9df49d7eSJed Brown     /// v_fine.set_value(0.0);
1133*9df49d7eSJed Brown     /// let mut multiplicity = ceed.vector(ndofs_fine).unwrap();
1134*9df49d7eSJed Brown     /// multiplicity.set_value(1.0);
1135*9df49d7eSJed Brown     ///
1136*9df49d7eSJed Brown     /// // Restrictions
1137*9df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1138*9df49d7eSJed Brown     /// let rq = ceed
1139*9df49d7eSJed Brown     ///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
1140*9df49d7eSJed Brown     ///     .unwrap();
1141*9df49d7eSJed Brown     ///
1142*9df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
1143*9df49d7eSJed Brown     /// for i in 0..ne {
1144*9df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
1145*9df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
1146*9df49d7eSJed Brown     /// }
1147*9df49d7eSJed Brown     /// let rx = ceed
1148*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
1149*9df49d7eSJed Brown     ///     .unwrap();
1150*9df49d7eSJed Brown     ///
1151*9df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
1152*9df49d7eSJed Brown     /// for i in 0..ne {
1153*9df49d7eSJed Brown     ///     for j in 0..p_coarse {
1154*9df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
1155*9df49d7eSJed Brown     ///     }
1156*9df49d7eSJed Brown     /// }
1157*9df49d7eSJed Brown     /// let ru_coarse = ceed
1158*9df49d7eSJed Brown     ///     .elem_restriction(
1159*9df49d7eSJed Brown     ///         ne,
1160*9df49d7eSJed Brown     ///         p_coarse,
1161*9df49d7eSJed Brown     ///         1,
1162*9df49d7eSJed Brown     ///         1,
1163*9df49d7eSJed Brown     ///         ndofs_coarse,
1164*9df49d7eSJed Brown     ///         MemType::Host,
1165*9df49d7eSJed Brown     ///         &indu_coarse,
1166*9df49d7eSJed Brown     ///     )
1167*9df49d7eSJed Brown     ///     .unwrap();
1168*9df49d7eSJed Brown     ///
1169*9df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
1170*9df49d7eSJed Brown     /// for i in 0..ne {
1171*9df49d7eSJed Brown     ///     for j in 0..p_fine {
1172*9df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
1173*9df49d7eSJed Brown     ///     }
1174*9df49d7eSJed Brown     /// }
1175*9df49d7eSJed Brown     /// let ru_fine = ceed
1176*9df49d7eSJed Brown     ///     .elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)
1177*9df49d7eSJed Brown     ///     .unwrap();
1178*9df49d7eSJed Brown     ///
1179*9df49d7eSJed Brown     /// // Bases
1180*9df49d7eSJed Brown     /// let bx = ceed
1181*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
1182*9df49d7eSJed Brown     ///     .unwrap();
1183*9df49d7eSJed Brown     /// let bu_coarse = ceed
1184*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)
1185*9df49d7eSJed Brown     ///     .unwrap();
1186*9df49d7eSJed Brown     /// let bu_fine = ceed
1187*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)
1188*9df49d7eSJed Brown     ///     .unwrap();
1189*9df49d7eSJed Brown     ///
1190*9df49d7eSJed Brown     /// // Build quadrature data
1191*9df49d7eSJed Brown     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
1192*9df49d7eSJed Brown     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)
1193*9df49d7eSJed Brown     ///     .unwrap()
1194*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
1195*9df49d7eSJed Brown     ///     .unwrap()
1196*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
1197*9df49d7eSJed Brown     ///     .unwrap()
1198*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
1199*9df49d7eSJed Brown     ///     .unwrap()
1200*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata)
1201*9df49d7eSJed Brown     ///     .unwrap();
1202*9df49d7eSJed Brown     ///
1203*9df49d7eSJed Brown     /// // Mass operator
1204*9df49d7eSJed Brown     /// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
1205*9df49d7eSJed Brown     /// let op_mass_fine = ceed
1206*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
1207*9df49d7eSJed Brown     ///     .unwrap()
1208*9df49d7eSJed Brown     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)
1209*9df49d7eSJed Brown     ///     .unwrap()
1210*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata)
1211*9df49d7eSJed Brown     ///     .unwrap()
1212*9df49d7eSJed Brown     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)
1213*9df49d7eSJed Brown     ///     .unwrap();
1214*9df49d7eSJed Brown     ///
1215*9df49d7eSJed Brown     /// // Multigrid setup
1216*9df49d7eSJed Brown     /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine
1217*9df49d7eSJed Brown     ///     .create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)
1218*9df49d7eSJed Brown     ///     .unwrap();
1219*9df49d7eSJed Brown     ///
1220*9df49d7eSJed Brown     /// // Coarse problem
1221*9df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1222*9df49d7eSJed Brown     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse).unwrap();
1223*9df49d7eSJed Brown     ///
1224*9df49d7eSJed Brown     /// // Check
1225*9df49d7eSJed Brown     /// let sum: f64 = v_coarse.view().iter().sum();
1226*9df49d7eSJed Brown     /// assert!(
1227*9df49d7eSJed Brown     ///     (sum - 2.0).abs() < 1e-15,
1228*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
1229*9df49d7eSJed Brown     /// );
1230*9df49d7eSJed Brown     ///
1231*9df49d7eSJed Brown     /// // Prolong
1232*9df49d7eSJed Brown     /// op_prolong.apply(&u_coarse, &mut u_fine).unwrap();
1233*9df49d7eSJed Brown     ///
1234*9df49d7eSJed Brown     /// // Fine problem
1235*9df49d7eSJed Brown     /// op_mass_fine.apply(&u_fine, &mut v_fine).unwrap();
1236*9df49d7eSJed Brown     ///
1237*9df49d7eSJed Brown     /// // Check
1238*9df49d7eSJed Brown     /// let sum: f64 = v_fine.view().iter().sum();
1239*9df49d7eSJed Brown     /// assert!(
1240*9df49d7eSJed Brown     ///     (sum - 2.0).abs() < 1e-15,
1241*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
1242*9df49d7eSJed Brown     /// );
1243*9df49d7eSJed Brown     ///
1244*9df49d7eSJed Brown     /// // Restrict
1245*9df49d7eSJed Brown     /// op_restrict.apply(&v_fine, &mut v_coarse).unwrap();
1246*9df49d7eSJed Brown     ///
1247*9df49d7eSJed Brown     /// // Check
1248*9df49d7eSJed Brown     /// let sum: f64 = v_coarse.view().iter().sum();
1249*9df49d7eSJed Brown     /// assert!(
1250*9df49d7eSJed Brown     ///     (sum - 2.0).abs() < 1e-15,
1251*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
1252*9df49d7eSJed Brown     /// );
1253*9df49d7eSJed Brown     /// ```
1254*9df49d7eSJed Brown     pub fn create_multigrid_level(
1255*9df49d7eSJed Brown         &self,
1256*9df49d7eSJed Brown         p_mult_fine: &Vector,
1257*9df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
1258*9df49d7eSJed Brown         basis_coarse: &Basis,
1259*9df49d7eSJed Brown     ) -> crate::Result<(Operator, Operator, Operator)> {
1260*9df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
1261*9df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
1262*9df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
1263*9df49d7eSJed Brown         let ierr = unsafe {
1264*9df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreate(
1265*9df49d7eSJed Brown                 self.op_core.ptr,
1266*9df49d7eSJed Brown                 p_mult_fine.ptr,
1267*9df49d7eSJed Brown                 rstr_coarse.ptr,
1268*9df49d7eSJed Brown                 basis_coarse.ptr,
1269*9df49d7eSJed Brown                 &mut ptr_coarse,
1270*9df49d7eSJed Brown                 &mut ptr_prolong,
1271*9df49d7eSJed Brown                 &mut ptr_restrict,
1272*9df49d7eSJed Brown             )
1273*9df49d7eSJed Brown         };
1274*9df49d7eSJed Brown         self.op_core.ceed.check_error(ierr)?;
1275*9df49d7eSJed Brown         let op_coarse = Operator::from_raw(self.op_core.ceed, ptr_coarse)?;
1276*9df49d7eSJed Brown         let op_prolong = Operator::from_raw(self.op_core.ceed, ptr_prolong)?;
1277*9df49d7eSJed Brown         let op_restrict = Operator::from_raw(self.op_core.ceed, ptr_restrict)?;
1278*9df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
1279*9df49d7eSJed Brown     }
1280*9df49d7eSJed Brown 
1281*9df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
1282*9df49d7eSJed Brown     ///   given Operator with a tensor basis for the active basis
1283*9df49d7eSJed Brown     ///
1284*9df49d7eSJed Brown     /// * `p_mult_fine`   - Lvector multiplicity in parallel gather/scatter
1285*9df49d7eSJed Brown     /// * `rstr_coarse`   - Coarse grid restriction
1286*9df49d7eSJed Brown     /// * `basis_coarse`  - Coarse grid active vector basis
1287*9df49d7eSJed Brown     /// * `interp_c_to_f` - Matrix for coarse to fine
1288*9df49d7eSJed Brown     ///
1289*9df49d7eSJed Brown     /// ```
1290*9df49d7eSJed Brown     /// # use libceed::prelude::*;
1291*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
1292*9df49d7eSJed Brown     /// let ne = 15;
1293*9df49d7eSJed Brown     /// let p_coarse = 3;
1294*9df49d7eSJed Brown     /// let p_fine = 5;
1295*9df49d7eSJed Brown     /// let q = 6;
1296*9df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
1297*9df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
1298*9df49d7eSJed Brown     ///
1299*9df49d7eSJed Brown     /// // Vectors
1300*9df49d7eSJed Brown     /// let x_array = (0..ne + 1)
1301*9df49d7eSJed Brown     ///     .map(|i| 2.0 * i as f64 / ne as f64 - 1.0)
1302*9df49d7eSJed Brown     ///     .collect::<Vec<f64>>();
1303*9df49d7eSJed Brown     /// let x = ceed.vector_from_slice(&x_array).unwrap();
1304*9df49d7eSJed Brown     /// let mut qdata = ceed.vector(ne * q).unwrap();
1305*9df49d7eSJed Brown     /// qdata.set_value(0.0);
1306*9df49d7eSJed Brown     /// let mut u_coarse = ceed.vector(ndofs_coarse).unwrap();
1307*9df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1308*9df49d7eSJed Brown     /// let mut u_fine = ceed.vector(ndofs_fine).unwrap();
1309*9df49d7eSJed Brown     /// u_fine.set_value(1.0);
1310*9df49d7eSJed Brown     /// let mut v_coarse = ceed.vector(ndofs_coarse).unwrap();
1311*9df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1312*9df49d7eSJed Brown     /// let mut v_fine = ceed.vector(ndofs_fine).unwrap();
1313*9df49d7eSJed Brown     /// v_fine.set_value(0.0);
1314*9df49d7eSJed Brown     /// let mut multiplicity = ceed.vector(ndofs_fine).unwrap();
1315*9df49d7eSJed Brown     /// multiplicity.set_value(1.0);
1316*9df49d7eSJed Brown     ///
1317*9df49d7eSJed Brown     /// // Restrictions
1318*9df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1319*9df49d7eSJed Brown     /// let rq = ceed
1320*9df49d7eSJed Brown     ///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
1321*9df49d7eSJed Brown     ///     .unwrap();
1322*9df49d7eSJed Brown     ///
1323*9df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
1324*9df49d7eSJed Brown     /// for i in 0..ne {
1325*9df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
1326*9df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
1327*9df49d7eSJed Brown     /// }
1328*9df49d7eSJed Brown     /// let rx = ceed
1329*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
1330*9df49d7eSJed Brown     ///     .unwrap();
1331*9df49d7eSJed Brown     ///
1332*9df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
1333*9df49d7eSJed Brown     /// for i in 0..ne {
1334*9df49d7eSJed Brown     ///     for j in 0..p_coarse {
1335*9df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
1336*9df49d7eSJed Brown     ///     }
1337*9df49d7eSJed Brown     /// }
1338*9df49d7eSJed Brown     /// let ru_coarse = ceed
1339*9df49d7eSJed Brown     ///     .elem_restriction(
1340*9df49d7eSJed Brown     ///         ne,
1341*9df49d7eSJed Brown     ///         p_coarse,
1342*9df49d7eSJed Brown     ///         1,
1343*9df49d7eSJed Brown     ///         1,
1344*9df49d7eSJed Brown     ///         ndofs_coarse,
1345*9df49d7eSJed Brown     ///         MemType::Host,
1346*9df49d7eSJed Brown     ///         &indu_coarse,
1347*9df49d7eSJed Brown     ///     )
1348*9df49d7eSJed Brown     ///     .unwrap();
1349*9df49d7eSJed Brown     ///
1350*9df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
1351*9df49d7eSJed Brown     /// for i in 0..ne {
1352*9df49d7eSJed Brown     ///     for j in 0..p_fine {
1353*9df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
1354*9df49d7eSJed Brown     ///     }
1355*9df49d7eSJed Brown     /// }
1356*9df49d7eSJed Brown     /// let ru_fine = ceed
1357*9df49d7eSJed Brown     ///     .elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)
1358*9df49d7eSJed Brown     ///     .unwrap();
1359*9df49d7eSJed Brown     ///
1360*9df49d7eSJed Brown     /// // Bases
1361*9df49d7eSJed Brown     /// let bx = ceed
1362*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
1363*9df49d7eSJed Brown     ///     .unwrap();
1364*9df49d7eSJed Brown     /// let bu_coarse = ceed
1365*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)
1366*9df49d7eSJed Brown     ///     .unwrap();
1367*9df49d7eSJed Brown     /// let bu_fine = ceed
1368*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)
1369*9df49d7eSJed Brown     ///     .unwrap();
1370*9df49d7eSJed Brown     ///
1371*9df49d7eSJed Brown     /// // Build quadrature data
1372*9df49d7eSJed Brown     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
1373*9df49d7eSJed Brown     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)
1374*9df49d7eSJed Brown     ///     .unwrap()
1375*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
1376*9df49d7eSJed Brown     ///     .unwrap()
1377*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
1378*9df49d7eSJed Brown     ///     .unwrap()
1379*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
1380*9df49d7eSJed Brown     ///     .unwrap()
1381*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata)
1382*9df49d7eSJed Brown     ///     .unwrap();
1383*9df49d7eSJed Brown     ///
1384*9df49d7eSJed Brown     /// // Mass operator
1385*9df49d7eSJed Brown     /// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
1386*9df49d7eSJed Brown     /// let op_mass_fine = ceed
1387*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
1388*9df49d7eSJed Brown     ///     .unwrap()
1389*9df49d7eSJed Brown     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)
1390*9df49d7eSJed Brown     ///     .unwrap()
1391*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata)
1392*9df49d7eSJed Brown     ///     .unwrap()
1393*9df49d7eSJed Brown     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)
1394*9df49d7eSJed Brown     ///     .unwrap();
1395*9df49d7eSJed Brown     ///
1396*9df49d7eSJed Brown     /// // Multigrid setup
1397*9df49d7eSJed Brown     /// let mut interp_c_to_f: Vec<f64> = vec![0.; p_coarse * p_fine];
1398*9df49d7eSJed Brown     /// {
1399*9df49d7eSJed Brown     ///     let mut coarse = ceed.vector(p_coarse).unwrap();
1400*9df49d7eSJed Brown     ///     let mut fine = ceed.vector(p_fine).unwrap();
1401*9df49d7eSJed Brown     ///     let basis_c_to_f = ceed
1402*9df49d7eSJed Brown     ///         .basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)
1403*9df49d7eSJed Brown     ///         .unwrap();
1404*9df49d7eSJed Brown     ///     for i in 0..p_coarse {
1405*9df49d7eSJed Brown     ///         coarse.set_value(0.0);
1406*9df49d7eSJed Brown     ///         {
1407*9df49d7eSJed Brown     ///             let mut array = coarse.view_mut();
1408*9df49d7eSJed Brown     ///             array[i] = 1.;
1409*9df49d7eSJed Brown     ///         }
1410*9df49d7eSJed Brown     ///         basis_c_to_f
1411*9df49d7eSJed Brown     ///             .apply(
1412*9df49d7eSJed Brown     ///                 1,
1413*9df49d7eSJed Brown     ///                 TransposeMode::NoTranspose,
1414*9df49d7eSJed Brown     ///                 EvalMode::Interp,
1415*9df49d7eSJed Brown     ///                 &coarse,
1416*9df49d7eSJed Brown     ///                 &mut fine,
1417*9df49d7eSJed Brown     ///             )
1418*9df49d7eSJed Brown     ///             .unwrap();
1419*9df49d7eSJed Brown     ///         let array = fine.view();
1420*9df49d7eSJed Brown     ///         for j in 0..p_fine {
1421*9df49d7eSJed Brown     ///             interp_c_to_f[j * p_coarse + i] = array[j];
1422*9df49d7eSJed Brown     ///         }
1423*9df49d7eSJed Brown     ///     }
1424*9df49d7eSJed Brown     /// }
1425*9df49d7eSJed Brown     /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine
1426*9df49d7eSJed Brown     ///     .create_multigrid_level_tensor_H1(&multiplicity, &ru_coarse, &bu_coarse, &interp_c_to_f)
1427*9df49d7eSJed Brown     ///     .unwrap();
1428*9df49d7eSJed Brown     ///
1429*9df49d7eSJed Brown     /// // Coarse problem
1430*9df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1431*9df49d7eSJed Brown     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse).unwrap();
1432*9df49d7eSJed Brown     ///
1433*9df49d7eSJed Brown     /// // Check
1434*9df49d7eSJed Brown     /// let sum: f64 = v_coarse.view().iter().sum();
1435*9df49d7eSJed Brown     /// assert!(
1436*9df49d7eSJed Brown     ///     (sum - 2.0).abs() < 1e-15,
1437*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
1438*9df49d7eSJed Brown     /// );
1439*9df49d7eSJed Brown     ///
1440*9df49d7eSJed Brown     /// // Prolong
1441*9df49d7eSJed Brown     /// op_prolong.apply(&u_coarse, &mut u_fine).unwrap();
1442*9df49d7eSJed Brown     ///
1443*9df49d7eSJed Brown     /// // Fine problem
1444*9df49d7eSJed Brown     /// op_mass_fine.apply(&u_fine, &mut v_fine).unwrap();
1445*9df49d7eSJed Brown     ///
1446*9df49d7eSJed Brown     /// // Check
1447*9df49d7eSJed Brown     /// let sum: f64 = v_fine.view().iter().sum();
1448*9df49d7eSJed Brown     /// assert!(
1449*9df49d7eSJed Brown     ///     (sum - 2.0).abs() < 1e-15,
1450*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
1451*9df49d7eSJed Brown     /// );
1452*9df49d7eSJed Brown     ///
1453*9df49d7eSJed Brown     /// // Restrict
1454*9df49d7eSJed Brown     /// op_restrict.apply(&v_fine, &mut v_coarse).unwrap();
1455*9df49d7eSJed Brown     ///
1456*9df49d7eSJed Brown     /// // Check
1457*9df49d7eSJed Brown     /// let sum: f64 = v_coarse.view().iter().sum();
1458*9df49d7eSJed Brown     /// assert!(
1459*9df49d7eSJed Brown     ///     (sum - 2.0).abs() < 1e-15,
1460*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
1461*9df49d7eSJed Brown     /// );
1462*9df49d7eSJed Brown     /// ```
1463*9df49d7eSJed Brown     pub fn create_multigrid_level_tensor_H1(
1464*9df49d7eSJed Brown         &self,
1465*9df49d7eSJed Brown         p_mult_fine: &Vector,
1466*9df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
1467*9df49d7eSJed Brown         basis_coarse: &Basis,
1468*9df49d7eSJed Brown         interpCtoF: &Vec<f64>,
1469*9df49d7eSJed Brown     ) -> crate::Result<(Operator, Operator, Operator)> {
1470*9df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
1471*9df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
1472*9df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
1473*9df49d7eSJed Brown         let ierr = unsafe {
1474*9df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreateTensorH1(
1475*9df49d7eSJed Brown                 self.op_core.ptr,
1476*9df49d7eSJed Brown                 p_mult_fine.ptr,
1477*9df49d7eSJed Brown                 rstr_coarse.ptr,
1478*9df49d7eSJed Brown                 basis_coarse.ptr,
1479*9df49d7eSJed Brown                 interpCtoF.as_ptr(),
1480*9df49d7eSJed Brown                 &mut ptr_coarse,
1481*9df49d7eSJed Brown                 &mut ptr_prolong,
1482*9df49d7eSJed Brown                 &mut ptr_restrict,
1483*9df49d7eSJed Brown             )
1484*9df49d7eSJed Brown         };
1485*9df49d7eSJed Brown         self.op_core.ceed.check_error(ierr)?;
1486*9df49d7eSJed Brown         let op_coarse = Operator::from_raw(self.op_core.ceed, ptr_coarse)?;
1487*9df49d7eSJed Brown         let op_prolong = Operator::from_raw(self.op_core.ceed, ptr_prolong)?;
1488*9df49d7eSJed Brown         let op_restrict = Operator::from_raw(self.op_core.ceed, ptr_restrict)?;
1489*9df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
1490*9df49d7eSJed Brown     }
1491*9df49d7eSJed Brown 
1492*9df49d7eSJed Brown     /// Create a multigrid coarse Operator and level transfer Operators for a
1493*9df49d7eSJed Brown     ///   given Operator with a non-tensor basis for the active basis
1494*9df49d7eSJed Brown     ///
1495*9df49d7eSJed Brown     /// * `p_mult_fine`   - Lvector multiplicity in parallel gather/scatter
1496*9df49d7eSJed Brown     /// * `rstr_coarse`   - Coarse grid restriction
1497*9df49d7eSJed Brown     /// * `basis_coarse`  - Coarse grid active vector basis
1498*9df49d7eSJed Brown     /// * `interp_c_to_f` - Matrix for coarse to fine
1499*9df49d7eSJed Brown     ///
1500*9df49d7eSJed Brown     /// ```
1501*9df49d7eSJed Brown     /// # use libceed::prelude::*;
1502*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
1503*9df49d7eSJed Brown     /// let ne = 15;
1504*9df49d7eSJed Brown     /// let p_coarse = 3;
1505*9df49d7eSJed Brown     /// let p_fine = 5;
1506*9df49d7eSJed Brown     /// let q = 6;
1507*9df49d7eSJed Brown     /// let ndofs_coarse = p_coarse * ne - ne + 1;
1508*9df49d7eSJed Brown     /// let ndofs_fine = p_fine * ne - ne + 1;
1509*9df49d7eSJed Brown     ///
1510*9df49d7eSJed Brown     /// // Vectors
1511*9df49d7eSJed Brown     /// let x_array = (0..ne + 1)
1512*9df49d7eSJed Brown     ///     .map(|i| 2.0 * i as f64 / ne as f64 - 1.0)
1513*9df49d7eSJed Brown     ///     .collect::<Vec<f64>>();
1514*9df49d7eSJed Brown     /// let x = ceed.vector_from_slice(&x_array).unwrap();
1515*9df49d7eSJed Brown     /// let mut qdata = ceed.vector(ne * q).unwrap();
1516*9df49d7eSJed Brown     /// qdata.set_value(0.0);
1517*9df49d7eSJed Brown     /// let mut u_coarse = ceed.vector(ndofs_coarse).unwrap();
1518*9df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1519*9df49d7eSJed Brown     /// let mut u_fine = ceed.vector(ndofs_fine).unwrap();
1520*9df49d7eSJed Brown     /// u_fine.set_value(1.0);
1521*9df49d7eSJed Brown     /// let mut v_coarse = ceed.vector(ndofs_coarse).unwrap();
1522*9df49d7eSJed Brown     /// v_coarse.set_value(0.0);
1523*9df49d7eSJed Brown     /// let mut v_fine = ceed.vector(ndofs_fine).unwrap();
1524*9df49d7eSJed Brown     /// v_fine.set_value(0.0);
1525*9df49d7eSJed Brown     /// let mut multiplicity = ceed.vector(ndofs_fine).unwrap();
1526*9df49d7eSJed Brown     /// multiplicity.set_value(1.0);
1527*9df49d7eSJed Brown     ///
1528*9df49d7eSJed Brown     /// // Restrictions
1529*9df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1530*9df49d7eSJed Brown     /// let rq = ceed
1531*9df49d7eSJed Brown     ///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
1532*9df49d7eSJed Brown     ///     .unwrap();
1533*9df49d7eSJed Brown     ///
1534*9df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
1535*9df49d7eSJed Brown     /// for i in 0..ne {
1536*9df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
1537*9df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
1538*9df49d7eSJed Brown     /// }
1539*9df49d7eSJed Brown     /// let rx = ceed
1540*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
1541*9df49d7eSJed Brown     ///     .unwrap();
1542*9df49d7eSJed Brown     ///
1543*9df49d7eSJed Brown     /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
1544*9df49d7eSJed Brown     /// for i in 0..ne {
1545*9df49d7eSJed Brown     ///     for j in 0..p_coarse {
1546*9df49d7eSJed Brown     ///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
1547*9df49d7eSJed Brown     ///     }
1548*9df49d7eSJed Brown     /// }
1549*9df49d7eSJed Brown     /// let ru_coarse = ceed
1550*9df49d7eSJed Brown     ///     .elem_restriction(
1551*9df49d7eSJed Brown     ///         ne,
1552*9df49d7eSJed Brown     ///         p_coarse,
1553*9df49d7eSJed Brown     ///         1,
1554*9df49d7eSJed Brown     ///         1,
1555*9df49d7eSJed Brown     ///         ndofs_coarse,
1556*9df49d7eSJed Brown     ///         MemType::Host,
1557*9df49d7eSJed Brown     ///         &indu_coarse,
1558*9df49d7eSJed Brown     ///     )
1559*9df49d7eSJed Brown     ///     .unwrap();
1560*9df49d7eSJed Brown     ///
1561*9df49d7eSJed Brown     /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
1562*9df49d7eSJed Brown     /// for i in 0..ne {
1563*9df49d7eSJed Brown     ///     for j in 0..p_fine {
1564*9df49d7eSJed Brown     ///         indu_fine[p_fine * i + j] = (i + j) as i32;
1565*9df49d7eSJed Brown     ///     }
1566*9df49d7eSJed Brown     /// }
1567*9df49d7eSJed Brown     /// let ru_fine = ceed
1568*9df49d7eSJed Brown     ///     .elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)
1569*9df49d7eSJed Brown     ///     .unwrap();
1570*9df49d7eSJed Brown     ///
1571*9df49d7eSJed Brown     /// // Bases
1572*9df49d7eSJed Brown     /// let bx = ceed
1573*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
1574*9df49d7eSJed Brown     ///     .unwrap();
1575*9df49d7eSJed Brown     /// let bu_coarse = ceed
1576*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)
1577*9df49d7eSJed Brown     ///     .unwrap();
1578*9df49d7eSJed Brown     /// let bu_fine = ceed
1579*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)
1580*9df49d7eSJed Brown     ///     .unwrap();
1581*9df49d7eSJed Brown     ///
1582*9df49d7eSJed Brown     /// // Build quadrature data
1583*9df49d7eSJed Brown     /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
1584*9df49d7eSJed Brown     /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)
1585*9df49d7eSJed Brown     ///     .unwrap()
1586*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
1587*9df49d7eSJed Brown     ///     .unwrap()
1588*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
1589*9df49d7eSJed Brown     ///     .unwrap()
1590*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
1591*9df49d7eSJed Brown     ///     .unwrap()
1592*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata)
1593*9df49d7eSJed Brown     ///     .unwrap();
1594*9df49d7eSJed Brown     ///
1595*9df49d7eSJed Brown     /// // Mass operator
1596*9df49d7eSJed Brown     /// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
1597*9df49d7eSJed Brown     /// let op_mass_fine = ceed
1598*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
1599*9df49d7eSJed Brown     ///     .unwrap()
1600*9df49d7eSJed Brown     ///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)
1601*9df49d7eSJed Brown     ///     .unwrap()
1602*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata)
1603*9df49d7eSJed Brown     ///     .unwrap()
1604*9df49d7eSJed Brown     ///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)
1605*9df49d7eSJed Brown     ///     .unwrap();
1606*9df49d7eSJed Brown     ///
1607*9df49d7eSJed Brown     /// // Multigrid setup
1608*9df49d7eSJed Brown     /// let mut interp_c_to_f: Vec<f64> = vec![0.; p_coarse * p_fine];
1609*9df49d7eSJed Brown     /// {
1610*9df49d7eSJed Brown     ///     let mut coarse = ceed.vector(p_coarse).unwrap();
1611*9df49d7eSJed Brown     ///     let mut fine = ceed.vector(p_fine).unwrap();
1612*9df49d7eSJed Brown     ///     let basis_c_to_f = ceed
1613*9df49d7eSJed Brown     ///         .basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)
1614*9df49d7eSJed Brown     ///         .unwrap();
1615*9df49d7eSJed Brown     ///     for i in 0..p_coarse {
1616*9df49d7eSJed Brown     ///         coarse.set_value(0.0);
1617*9df49d7eSJed Brown     ///         {
1618*9df49d7eSJed Brown     ///             let mut array = coarse.view_mut();
1619*9df49d7eSJed Brown     ///             array[i] = 1.;
1620*9df49d7eSJed Brown     ///         }
1621*9df49d7eSJed Brown     ///         basis_c_to_f
1622*9df49d7eSJed Brown     ///             .apply(
1623*9df49d7eSJed Brown     ///                 1,
1624*9df49d7eSJed Brown     ///                 TransposeMode::NoTranspose,
1625*9df49d7eSJed Brown     ///                 EvalMode::Interp,
1626*9df49d7eSJed Brown     ///                 &coarse,
1627*9df49d7eSJed Brown     ///                 &mut fine,
1628*9df49d7eSJed Brown     ///             )
1629*9df49d7eSJed Brown     ///             .unwrap();
1630*9df49d7eSJed Brown     ///         let array = fine.view();
1631*9df49d7eSJed Brown     ///         for j in 0..p_fine {
1632*9df49d7eSJed Brown     ///             interp_c_to_f[j * p_coarse + i] = array[j];
1633*9df49d7eSJed Brown     ///         }
1634*9df49d7eSJed Brown     ///     }
1635*9df49d7eSJed Brown     /// }
1636*9df49d7eSJed Brown     /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine
1637*9df49d7eSJed Brown     ///     .create_multigrid_level_H1(&multiplicity, &ru_coarse, &bu_coarse, &interp_c_to_f)
1638*9df49d7eSJed Brown     ///     .unwrap();
1639*9df49d7eSJed Brown     ///
1640*9df49d7eSJed Brown     /// // Coarse problem
1641*9df49d7eSJed Brown     /// u_coarse.set_value(1.0);
1642*9df49d7eSJed Brown     /// op_mass_coarse.apply(&u_coarse, &mut v_coarse).unwrap();
1643*9df49d7eSJed Brown     ///
1644*9df49d7eSJed Brown     /// // Check
1645*9df49d7eSJed Brown     /// let sum: f64 = v_coarse.view().iter().sum();
1646*9df49d7eSJed Brown     /// assert!(
1647*9df49d7eSJed Brown     ///     (sum - 2.0).abs() < 1e-15,
1648*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
1649*9df49d7eSJed Brown     /// );
1650*9df49d7eSJed Brown     ///
1651*9df49d7eSJed Brown     /// // Prolong
1652*9df49d7eSJed Brown     /// op_prolong.apply(&u_coarse, &mut u_fine).unwrap();
1653*9df49d7eSJed Brown     ///
1654*9df49d7eSJed Brown     /// // Fine problem
1655*9df49d7eSJed Brown     /// op_mass_fine.apply(&u_fine, &mut v_fine).unwrap();
1656*9df49d7eSJed Brown     ///
1657*9df49d7eSJed Brown     /// // Check
1658*9df49d7eSJed Brown     /// let sum: f64 = v_fine.view().iter().sum();
1659*9df49d7eSJed Brown     /// assert!(
1660*9df49d7eSJed Brown     ///     (sum - 2.0).abs() < 1e-15,
1661*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
1662*9df49d7eSJed Brown     /// );
1663*9df49d7eSJed Brown     ///
1664*9df49d7eSJed Brown     /// // Restrict
1665*9df49d7eSJed Brown     /// op_restrict.apply(&v_fine, &mut v_coarse).unwrap();
1666*9df49d7eSJed Brown     ///
1667*9df49d7eSJed Brown     /// // Check
1668*9df49d7eSJed Brown     /// let sum: f64 = v_coarse.view().iter().sum();
1669*9df49d7eSJed Brown     /// assert!(
1670*9df49d7eSJed Brown     ///     (sum - 2.0).abs() < 1e-15,
1671*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
1672*9df49d7eSJed Brown     /// );
1673*9df49d7eSJed Brown     /// ```
1674*9df49d7eSJed Brown     pub fn create_multigrid_level_H1(
1675*9df49d7eSJed Brown         &self,
1676*9df49d7eSJed Brown         p_mult_fine: &Vector,
1677*9df49d7eSJed Brown         rstr_coarse: &ElemRestriction,
1678*9df49d7eSJed Brown         basis_coarse: &Basis,
1679*9df49d7eSJed Brown         interpCtoF: &[f64],
1680*9df49d7eSJed Brown     ) -> crate::Result<(Operator, Operator, Operator)> {
1681*9df49d7eSJed Brown         let mut ptr_coarse = std::ptr::null_mut();
1682*9df49d7eSJed Brown         let mut ptr_prolong = std::ptr::null_mut();
1683*9df49d7eSJed Brown         let mut ptr_restrict = std::ptr::null_mut();
1684*9df49d7eSJed Brown         let ierr = unsafe {
1685*9df49d7eSJed Brown             bind_ceed::CeedOperatorMultigridLevelCreateH1(
1686*9df49d7eSJed Brown                 self.op_core.ptr,
1687*9df49d7eSJed Brown                 p_mult_fine.ptr,
1688*9df49d7eSJed Brown                 rstr_coarse.ptr,
1689*9df49d7eSJed Brown                 basis_coarse.ptr,
1690*9df49d7eSJed Brown                 interpCtoF.as_ptr(),
1691*9df49d7eSJed Brown                 &mut ptr_coarse,
1692*9df49d7eSJed Brown                 &mut ptr_prolong,
1693*9df49d7eSJed Brown                 &mut ptr_restrict,
1694*9df49d7eSJed Brown             )
1695*9df49d7eSJed Brown         };
1696*9df49d7eSJed Brown         self.op_core.ceed.check_error(ierr)?;
1697*9df49d7eSJed Brown         let op_coarse = Operator::from_raw(self.op_core.ceed, ptr_coarse)?;
1698*9df49d7eSJed Brown         let op_prolong = Operator::from_raw(self.op_core.ceed, ptr_prolong)?;
1699*9df49d7eSJed Brown         let op_restrict = Operator::from_raw(self.op_core.ceed, ptr_restrict)?;
1700*9df49d7eSJed Brown         Ok((op_coarse, op_prolong, op_restrict))
1701*9df49d7eSJed Brown     }
1702*9df49d7eSJed Brown }
1703*9df49d7eSJed Brown 
1704*9df49d7eSJed Brown // -----------------------------------------------------------------------------
1705*9df49d7eSJed Brown // Composite Operator
1706*9df49d7eSJed Brown // -----------------------------------------------------------------------------
1707*9df49d7eSJed Brown impl<'a> CompositeOperator<'a> {
1708*9df49d7eSJed Brown     // Constructor
1709*9df49d7eSJed Brown     pub fn create(ceed: &'a crate::Ceed) -> crate::Result<Self> {
1710*9df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
1711*9df49d7eSJed Brown         let ierr = unsafe { bind_ceed::CeedCompositeOperatorCreate(ceed.ptr, &mut ptr) };
1712*9df49d7eSJed Brown         ceed.check_error(ierr)?;
1713*9df49d7eSJed Brown         Ok(Self {
1714*9df49d7eSJed Brown             op_core: OperatorCore { ceed, ptr },
1715*9df49d7eSJed Brown         })
1716*9df49d7eSJed Brown     }
1717*9df49d7eSJed Brown 
1718*9df49d7eSJed Brown     /// Apply Operator to a vector
1719*9df49d7eSJed Brown     ///
1720*9df49d7eSJed Brown     /// * `input`  - Input Vector
1721*9df49d7eSJed Brown     /// * `output` - Output Vector
1722*9df49d7eSJed Brown     ///
1723*9df49d7eSJed Brown     /// ```
1724*9df49d7eSJed Brown     /// # use libceed::prelude::*;
1725*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
1726*9df49d7eSJed Brown     /// let ne = 4;
1727*9df49d7eSJed Brown     /// let p = 3;
1728*9df49d7eSJed Brown     /// let q = 4;
1729*9df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
1730*9df49d7eSJed Brown     ///
1731*9df49d7eSJed Brown     /// // Vectors
1732*9df49d7eSJed Brown     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0]).unwrap();
1733*9df49d7eSJed Brown     /// let mut qdata_mass = ceed.vector(ne * q).unwrap();
1734*9df49d7eSJed Brown     /// qdata_mass.set_value(0.0);
1735*9df49d7eSJed Brown     /// let mut qdata_diff = ceed.vector(ne * q).unwrap();
1736*9df49d7eSJed Brown     /// qdata_diff.set_value(0.0);
1737*9df49d7eSJed Brown     /// let mut u = ceed.vector(ndofs).unwrap();
1738*9df49d7eSJed Brown     /// u.set_value(1.0);
1739*9df49d7eSJed Brown     /// let mut v = ceed.vector(ndofs).unwrap();
1740*9df49d7eSJed Brown     /// v.set_value(0.0);
1741*9df49d7eSJed Brown     ///
1742*9df49d7eSJed Brown     /// // Restrictions
1743*9df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
1744*9df49d7eSJed Brown     /// for i in 0..ne {
1745*9df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
1746*9df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
1747*9df49d7eSJed Brown     /// }
1748*9df49d7eSJed Brown     /// let rx = ceed
1749*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
1750*9df49d7eSJed Brown     ///     .unwrap();
1751*9df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
1752*9df49d7eSJed Brown     /// for i in 0..ne {
1753*9df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
1754*9df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
1755*9df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
1756*9df49d7eSJed Brown     /// }
1757*9df49d7eSJed Brown     /// let ru = ceed
1758*9df49d7eSJed Brown     ///     .elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)
1759*9df49d7eSJed Brown     ///     .unwrap();
1760*9df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1761*9df49d7eSJed Brown     /// let rq = ceed
1762*9df49d7eSJed Brown     ///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
1763*9df49d7eSJed Brown     ///     .unwrap();
1764*9df49d7eSJed Brown     ///
1765*9df49d7eSJed Brown     /// // Bases
1766*9df49d7eSJed Brown     /// let bx = ceed
1767*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
1768*9df49d7eSJed Brown     ///     .unwrap();
1769*9df49d7eSJed Brown     /// let bu = ceed
1770*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)
1771*9df49d7eSJed Brown     ///     .unwrap();
1772*9df49d7eSJed Brown     ///
1773*9df49d7eSJed Brown     /// // Build quadrature data
1774*9df49d7eSJed Brown     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
1775*9df49d7eSJed Brown     /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)
1776*9df49d7eSJed Brown     ///     .unwrap()
1777*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
1778*9df49d7eSJed Brown     ///     .unwrap()
1779*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
1780*9df49d7eSJed Brown     ///     .unwrap()
1781*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
1782*9df49d7eSJed Brown     ///     .unwrap()
1783*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata_mass)
1784*9df49d7eSJed Brown     ///     .unwrap();
1785*9df49d7eSJed Brown     ///
1786*9df49d7eSJed Brown     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild").unwrap();
1787*9df49d7eSJed Brown     /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)
1788*9df49d7eSJed Brown     ///     .unwrap()
1789*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
1790*9df49d7eSJed Brown     ///     .unwrap()
1791*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
1792*9df49d7eSJed Brown     ///     .unwrap()
1793*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
1794*9df49d7eSJed Brown     ///     .unwrap()
1795*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata_diff)
1796*9df49d7eSJed Brown     ///     .unwrap();
1797*9df49d7eSJed Brown     ///
1798*9df49d7eSJed Brown     /// // Application operator
1799*9df49d7eSJed Brown     /// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
1800*9df49d7eSJed Brown     /// let op_mass = ceed
1801*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
1802*9df49d7eSJed Brown     ///     .unwrap()
1803*9df49d7eSJed Brown     ///     .field("u", &ru, &bu, VectorOpt::Active)
1804*9df49d7eSJed Brown     ///     .unwrap()
1805*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)
1806*9df49d7eSJed Brown     ///     .unwrap()
1807*9df49d7eSJed Brown     ///     .field("v", &ru, &bu, VectorOpt::Active)
1808*9df49d7eSJed Brown     ///     .unwrap();
1809*9df49d7eSJed Brown     ///
1810*9df49d7eSJed Brown     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply").unwrap();
1811*9df49d7eSJed Brown     /// let op_diff = ceed
1812*9df49d7eSJed Brown     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)
1813*9df49d7eSJed Brown     ///     .unwrap()
1814*9df49d7eSJed Brown     ///     .field("du", &ru, &bu, VectorOpt::Active)
1815*9df49d7eSJed Brown     ///     .unwrap()
1816*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)
1817*9df49d7eSJed Brown     ///     .unwrap()
1818*9df49d7eSJed Brown     ///     .field("dv", &ru, &bu, VectorOpt::Active)
1819*9df49d7eSJed Brown     ///     .unwrap();
1820*9df49d7eSJed Brown     ///
1821*9df49d7eSJed Brown     /// let op_composite = ceed
1822*9df49d7eSJed Brown     ///     .composite_operator()
1823*9df49d7eSJed Brown     ///     .unwrap()
1824*9df49d7eSJed Brown     ///     .sub_operator(&op_mass)
1825*9df49d7eSJed Brown     ///     .unwrap()
1826*9df49d7eSJed Brown     ///     .sub_operator(&op_diff)
1827*9df49d7eSJed Brown     ///     .unwrap();
1828*9df49d7eSJed Brown     ///
1829*9df49d7eSJed Brown     /// v.set_value(0.0);
1830*9df49d7eSJed Brown     /// op_composite.apply(&u, &mut v).unwrap();
1831*9df49d7eSJed Brown     ///
1832*9df49d7eSJed Brown     /// // Check
1833*9df49d7eSJed Brown     /// let sum: f64 = v.view().iter().sum();
1834*9df49d7eSJed Brown     /// assert!(
1835*9df49d7eSJed Brown     ///     (sum - 2.0).abs() < 1e-15,
1836*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
1837*9df49d7eSJed Brown     /// );
1838*9df49d7eSJed Brown     /// ```
1839*9df49d7eSJed Brown     pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
1840*9df49d7eSJed Brown         self.op_core.apply(input, output)
1841*9df49d7eSJed Brown     }
1842*9df49d7eSJed Brown 
1843*9df49d7eSJed Brown     /// Apply Operator to a vector and add result to output vector
1844*9df49d7eSJed Brown     ///
1845*9df49d7eSJed Brown     /// * `input`  - Input Vector
1846*9df49d7eSJed Brown     /// * `output` - Output Vector
1847*9df49d7eSJed Brown     ///
1848*9df49d7eSJed Brown     /// ```
1849*9df49d7eSJed Brown     /// # use libceed::prelude::*;
1850*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
1851*9df49d7eSJed Brown     /// let ne = 4;
1852*9df49d7eSJed Brown     /// let p = 3;
1853*9df49d7eSJed Brown     /// let q = 4;
1854*9df49d7eSJed Brown     /// let ndofs = p * ne - ne + 1;
1855*9df49d7eSJed Brown     ///
1856*9df49d7eSJed Brown     /// // Vectors
1857*9df49d7eSJed Brown     /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0]).unwrap();
1858*9df49d7eSJed Brown     /// let mut qdata_mass = ceed.vector(ne * q).unwrap();
1859*9df49d7eSJed Brown     /// qdata_mass.set_value(0.0);
1860*9df49d7eSJed Brown     /// let mut qdata_diff = ceed.vector(ne * q).unwrap();
1861*9df49d7eSJed Brown     /// qdata_diff.set_value(0.0);
1862*9df49d7eSJed Brown     /// let mut u = ceed.vector(ndofs).unwrap();
1863*9df49d7eSJed Brown     /// u.set_value(1.0);
1864*9df49d7eSJed Brown     /// let mut v = ceed.vector(ndofs).unwrap();
1865*9df49d7eSJed Brown     /// v.set_value(0.0);
1866*9df49d7eSJed Brown     ///
1867*9df49d7eSJed Brown     /// // Restrictions
1868*9df49d7eSJed Brown     /// let mut indx: Vec<i32> = vec![0; 2 * ne];
1869*9df49d7eSJed Brown     /// for i in 0..ne {
1870*9df49d7eSJed Brown     ///     indx[2 * i + 0] = i as i32;
1871*9df49d7eSJed Brown     ///     indx[2 * i + 1] = (i + 1) as i32;
1872*9df49d7eSJed Brown     /// }
1873*9df49d7eSJed Brown     /// let rx = ceed
1874*9df49d7eSJed Brown     ///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
1875*9df49d7eSJed Brown     ///     .unwrap();
1876*9df49d7eSJed Brown     /// let mut indu: Vec<i32> = vec![0; p * ne];
1877*9df49d7eSJed Brown     /// for i in 0..ne {
1878*9df49d7eSJed Brown     ///     indu[p * i + 0] = i as i32;
1879*9df49d7eSJed Brown     ///     indu[p * i + 1] = (i + 1) as i32;
1880*9df49d7eSJed Brown     ///     indu[p * i + 2] = (i + 2) as i32;
1881*9df49d7eSJed Brown     /// }
1882*9df49d7eSJed Brown     /// let ru = ceed
1883*9df49d7eSJed Brown     ///     .elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)
1884*9df49d7eSJed Brown     ///     .unwrap();
1885*9df49d7eSJed Brown     /// let strides: [i32; 3] = [1, q as i32, q as i32];
1886*9df49d7eSJed Brown     /// let rq = ceed
1887*9df49d7eSJed Brown     ///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
1888*9df49d7eSJed Brown     ///     .unwrap();
1889*9df49d7eSJed Brown     ///
1890*9df49d7eSJed Brown     /// // Bases
1891*9df49d7eSJed Brown     /// let bx = ceed
1892*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
1893*9df49d7eSJed Brown     ///     .unwrap();
1894*9df49d7eSJed Brown     /// let bu = ceed
1895*9df49d7eSJed Brown     ///     .basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)
1896*9df49d7eSJed Brown     ///     .unwrap();
1897*9df49d7eSJed Brown     ///
1898*9df49d7eSJed Brown     /// // Build quadrature data
1899*9df49d7eSJed Brown     /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
1900*9df49d7eSJed Brown     /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)
1901*9df49d7eSJed Brown     ///     .unwrap()
1902*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
1903*9df49d7eSJed Brown     ///     .unwrap()
1904*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
1905*9df49d7eSJed Brown     ///     .unwrap()
1906*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
1907*9df49d7eSJed Brown     ///     .unwrap()
1908*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata_mass)
1909*9df49d7eSJed Brown     ///     .unwrap();
1910*9df49d7eSJed Brown     ///
1911*9df49d7eSJed Brown     /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild").unwrap();
1912*9df49d7eSJed Brown     /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)
1913*9df49d7eSJed Brown     ///     .unwrap()
1914*9df49d7eSJed Brown     ///     .field("dx", &rx, &bx, VectorOpt::Active)
1915*9df49d7eSJed Brown     ///     .unwrap()
1916*9df49d7eSJed Brown     ///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
1917*9df49d7eSJed Brown     ///     .unwrap()
1918*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
1919*9df49d7eSJed Brown     ///     .unwrap()
1920*9df49d7eSJed Brown     ///     .apply(&x, &mut qdata_diff)
1921*9df49d7eSJed Brown     ///     .unwrap();
1922*9df49d7eSJed Brown     ///
1923*9df49d7eSJed Brown     /// // Application operator
1924*9df49d7eSJed Brown     /// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
1925*9df49d7eSJed Brown     /// let op_mass = ceed
1926*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
1927*9df49d7eSJed Brown     ///     .unwrap()
1928*9df49d7eSJed Brown     ///     .field("u", &ru, &bu, VectorOpt::Active)
1929*9df49d7eSJed Brown     ///     .unwrap()
1930*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)
1931*9df49d7eSJed Brown     ///     .unwrap()
1932*9df49d7eSJed Brown     ///     .field("v", &ru, &bu, VectorOpt::Active)
1933*9df49d7eSJed Brown     ///     .unwrap();
1934*9df49d7eSJed Brown     ///
1935*9df49d7eSJed Brown     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply").unwrap();
1936*9df49d7eSJed Brown     /// let op_diff = ceed
1937*9df49d7eSJed Brown     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)
1938*9df49d7eSJed Brown     ///     .unwrap()
1939*9df49d7eSJed Brown     ///     .field("du", &ru, &bu, VectorOpt::Active)
1940*9df49d7eSJed Brown     ///     .unwrap()
1941*9df49d7eSJed Brown     ///     .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)
1942*9df49d7eSJed Brown     ///     .unwrap()
1943*9df49d7eSJed Brown     ///     .field("dv", &ru, &bu, VectorOpt::Active)
1944*9df49d7eSJed Brown     ///     .unwrap();
1945*9df49d7eSJed Brown     ///
1946*9df49d7eSJed Brown     /// let op_composite = ceed
1947*9df49d7eSJed Brown     ///     .composite_operator()
1948*9df49d7eSJed Brown     ///     .unwrap()
1949*9df49d7eSJed Brown     ///     .sub_operator(&op_mass)
1950*9df49d7eSJed Brown     ///     .unwrap()
1951*9df49d7eSJed Brown     ///     .sub_operator(&op_diff)
1952*9df49d7eSJed Brown     ///     .unwrap();
1953*9df49d7eSJed Brown     ///
1954*9df49d7eSJed Brown     /// v.set_value(1.0);
1955*9df49d7eSJed Brown     /// op_composite.apply_add(&u, &mut v).unwrap();
1956*9df49d7eSJed Brown     ///
1957*9df49d7eSJed Brown     /// // Check
1958*9df49d7eSJed Brown     /// let sum: f64 = v.view().iter().sum();
1959*9df49d7eSJed Brown     /// assert!(
1960*9df49d7eSJed Brown     ///     (sum - (2.0 + ndofs as f64)).abs() < 1e-15,
1961*9df49d7eSJed Brown     ///     "Incorrect interval length computed"
1962*9df49d7eSJed Brown     /// );
1963*9df49d7eSJed Brown     /// ```
1964*9df49d7eSJed Brown     pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> {
1965*9df49d7eSJed Brown         self.op_core.apply_add(input, output)
1966*9df49d7eSJed Brown     }
1967*9df49d7eSJed Brown 
1968*9df49d7eSJed Brown     /// Add a sub-Operator to a Composite Operator
1969*9df49d7eSJed Brown     ///
1970*9df49d7eSJed Brown     /// * `subop` - Sub-Operator
1971*9df49d7eSJed Brown     ///
1972*9df49d7eSJed Brown     /// ```
1973*9df49d7eSJed Brown     /// # use libceed::prelude::*;
1974*9df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
1975*9df49d7eSJed Brown     /// let mut op = ceed.composite_operator().unwrap();
1976*9df49d7eSJed Brown     ///
1977*9df49d7eSJed Brown     /// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
1978*9df49d7eSJed Brown     /// let op_mass = ceed
1979*9df49d7eSJed Brown     ///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
1980*9df49d7eSJed Brown     ///     .unwrap();
1981*9df49d7eSJed Brown     /// op = op.sub_operator(&op_mass).unwrap();
1982*9df49d7eSJed Brown     ///
1983*9df49d7eSJed Brown     /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply").unwrap();
1984*9df49d7eSJed Brown     /// let op_diff = ceed
1985*9df49d7eSJed Brown     ///     .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)
1986*9df49d7eSJed Brown     ///     .unwrap();
1987*9df49d7eSJed Brown     /// op = op.sub_operator(&op_diff).unwrap();
1988*9df49d7eSJed Brown     /// ```
1989*9df49d7eSJed Brown     #[allow(unused_mut)]
1990*9df49d7eSJed Brown     pub fn sub_operator(mut self, subop: &Operator) -> crate::Result<Self> {
1991*9df49d7eSJed Brown         let ierr =
1992*9df49d7eSJed Brown             unsafe { bind_ceed::CeedCompositeOperatorAddSub(self.op_core.ptr, subop.op_core.ptr) };
1993*9df49d7eSJed Brown         self.op_core.ceed.check_error(ierr)?;
1994*9df49d7eSJed Brown         Ok(self)
1995*9df49d7eSJed Brown     }
1996*9df49d7eSJed Brown 
1997*9df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
1998*9df49d7eSJed Brown     ///
1999*9df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
2000*9df49d7eSJed Brown     ///
2001*9df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
2002*9df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
2003*9df49d7eSJed Brown     ///
2004*9df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
2005*9df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
2006*9df49d7eSJed Brown     pub fn linear_asssemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
2007*9df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
2008*9df49d7eSJed Brown     }
2009*9df49d7eSJed Brown 
2010*9df49d7eSJed Brown     /// Assemble the point block diagonal of a square linear Operator
2011*9df49d7eSJed Brown     ///
2012*9df49d7eSJed Brown     /// This overwrites a Vector with the point block diagonal of a linear
2013*9df49d7eSJed Brown     ///   Operator.
2014*9df49d7eSJed Brown     ///
2015*9df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
2016*9df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
2017*9df49d7eSJed Brown     ///
2018*9df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
2019*9df49d7eSJed Brown     /// * `assembled` - Vector to store assembled Operator diagonal
2020*9df49d7eSJed Brown     pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> {
2021*9df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
2022*9df49d7eSJed Brown     }
2023*9df49d7eSJed Brown 
2024*9df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
2025*9df49d7eSJed Brown     ///
2026*9df49d7eSJed Brown     /// This overwrites a Vector with the diagonal of a linear Operator.
2027*9df49d7eSJed Brown     ///
2028*9df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
2029*9df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
2030*9df49d7eSJed Brown     ///
2031*9df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
2032*9df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
2033*9df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
2034*9df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
2035*9df49d7eSJed Brown     ///                   this vector are derived from the active vector for
2036*9df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
2037*9df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
2038*9df49d7eSJed Brown     pub fn linear_assemble_point_block_diagonal(
2039*9df49d7eSJed Brown         &self,
2040*9df49d7eSJed Brown         assembled: &mut Vector,
2041*9df49d7eSJed Brown     ) -> crate::Result<i32> {
2042*9df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
2043*9df49d7eSJed Brown     }
2044*9df49d7eSJed Brown 
2045*9df49d7eSJed Brown     /// Assemble the diagonal of a square linear Operator
2046*9df49d7eSJed Brown     ///
2047*9df49d7eSJed Brown     /// This sums into a Vector with the diagonal of a linear Operator.
2048*9df49d7eSJed Brown     ///
2049*9df49d7eSJed Brown     /// Note: Currently only non-composite Operators with a single field and
2050*9df49d7eSJed Brown     ///      composite Operators with single field sub-operators are supported.
2051*9df49d7eSJed Brown     ///
2052*9df49d7eSJed Brown     /// * `op`        - Operator to assemble QFunction
2053*9df49d7eSJed Brown     /// * `assembled` - Vector to store assembled CeedOperator point block
2054*9df49d7eSJed Brown     ///                   diagonal, provided in row-major form with an
2055*9df49d7eSJed Brown     ///                   `ncomp * ncomp` block at each node. The dimensions of
2056*9df49d7eSJed Brown     ///                   this vector are derived from the active vector for
2057*9df49d7eSJed Brown     ///                   the CeedOperator. The array has shape
2058*9df49d7eSJed Brown     ///                   `[nodes, component out, component in]`.
2059*9df49d7eSJed Brown     pub fn linear_assemble_add_point_block_diagonal(
2060*9df49d7eSJed Brown         &self,
2061*9df49d7eSJed Brown         assembled: &mut Vector,
2062*9df49d7eSJed Brown     ) -> crate::Result<i32> {
2063*9df49d7eSJed Brown         self.op_core.linear_assemble_add_diagonal(assembled)
2064*9df49d7eSJed Brown     }
2065*9df49d7eSJed Brown }
2066*9df49d7eSJed Brown 
2067*9df49d7eSJed Brown // -----------------------------------------------------------------------------
2068