libceed/
operator.rs

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