pub fn create_multigrid_level_tensor_H1(
        &self,
        p_mult_fine: &Vector,
        rstr_coarse: &ElemRestriction,
        basis_coarse: &Basis,
        interpCtoF: &Vec<f64>,
    ) -> crate::Result<(Operator, Operator, Operator)> {
        let mut ptr_coarse = std::ptr::null_mut();
        let mut ptr_prolong = std::ptr::null_mut();
        let mut ptr_restrict = std::ptr::null_mut();
        let ierr = unsafe {
            bind_ceed::CeedOperatorMultigridLevelCreateTensorH1(
                self.op_core.ptr,
                p_mult_fine.ptr,
                rstr_coarse.ptr,
                basis_coarse.ptr,
                interpCtoF.as_ptr(),
                &mut ptr_coarse,
                &mut ptr_prolong,
                &mut ptr_restrict,
            )
        };
        self.op_core.ceed.check_error(ierr)?;
        let op_coarse = Operator::from_raw(self.op_core.ceed, ptr_coarse)?;
        let op_prolong = Operator::from_raw(self.op_core.ceed, ptr_prolong)?;
        let op_restrict = Operator::from_raw(self.op_core.ceed, ptr_restrict)?;
        Ok((op_coarse, op_prolong, op_restrict))
    }
/// Create a multigrid coarse Operator and level transfer Operators for a
///   given Operator with a tensor basis for the active basis
///
/// * `p_mult_fine`   - Lvector multiplicity in parallel gather/scatter
/// * `rstr_coarse`   - Coarse grid restriction
/// * `basis_coarse`  - Coarse grid active vector basis
/// * `interp_c_to_f` - Matrix for coarse to fine
///
/// ```
/// # use libceed::prelude::*;
/// # let ceed = libceed::Ceed::default_init();
/// let ne = 15;
/// let p_coarse = 3;
/// let p_fine = 5;
/// let q = 6;
/// let ndofs_coarse = p_coarse * ne - ne + 1;
/// let ndofs_fine = p_fine * ne - ne + 1;
///
/// // Vectors
/// let x_array = (0..ne + 1)
///     .map(|i| 2.0 * i as f64 / ne as f64 - 1.0)
///     .collect::<Vec<f64>>();
/// let x = ceed.vector_from_slice(&x_array).unwrap();
/// let mut qdata = ceed.vector(ne * q).unwrap();
/// qdata.set_value(0.0);
/// let mut u_coarse = ceed.vector(ndofs_coarse).unwrap();
/// u_coarse.set_value(1.0);
/// let mut u_fine = ceed.vector(ndofs_fine).unwrap();
/// u_fine.set_value(1.0);
/// let mut v_coarse = ceed.vector(ndofs_coarse).unwrap();
/// v_coarse.set_value(0.0);
/// let mut v_fine = ceed.vector(ndofs_fine).unwrap();
/// v_fine.set_value(0.0);
/// let mut multiplicity = ceed.vector(ndofs_fine).unwrap();
/// multiplicity.set_value(1.0);
///
/// // Restrictions
/// let strides: [i32; 3] = [1, q as i32, q as i32];
/// let rq = ceed
///     .strided_elem_restriction(ne, q, 1, q * ne, strides)
///     .unwrap();
///
/// let mut indx: Vec<i32> = vec![0; 2 * ne];
/// for i in 0..ne {
///     indx[2 * i + 0] = i as i32;
///     indx[2 * i + 1] = (i + 1) as i32;
/// }
/// let rx = ceed
///     .elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)
///     .unwrap();
///
/// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne];
/// for i in 0..ne {
///     for j in 0..p_coarse {
///         indu_coarse[p_coarse * i + j] = (i + j) as i32;
///     }
/// }
/// let ru_coarse = ceed
///     .elem_restriction(
///         ne,
///         p_coarse,
///         1,
///         1,
///         ndofs_coarse,
///         MemType::Host,
///         &indu_coarse,
///     )
///     .unwrap();
///
/// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne];
/// for i in 0..ne {
///     for j in 0..p_fine {
///         indu_fine[p_fine * i + j] = (i + j) as i32;
///     }
/// }
/// let ru_fine = ceed
///     .elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)
///     .unwrap();
///
/// // Bases
/// let bx = ceed
///     .basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
///     .unwrap();
/// let bu_coarse = ceed
///     .basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)
///     .unwrap();
/// let bu_fine = ceed
///     .basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)
///     .unwrap();
///
/// // Build quadrature data
/// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
/// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)
///     .unwrap()
///     .field("dx", &rx, &bx, VectorOpt::Active)
///     .unwrap()
///     .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
///     .unwrap()
///     .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
///     .unwrap()
///     .apply(&x, &mut qdata)
///     .unwrap();
///
/// // Mass operator
/// let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
/// let op_mass_fine = ceed
///     .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
///     .unwrap()
///     .field("u", &ru_fine, &bu_fine, VectorOpt::Active)
///     .unwrap()
///     .field("qdata", &rq, BasisOpt::Collocated, &qdata)
///     .unwrap()
///     .field("v", &ru_fine, &bu_fine, VectorOpt::Active)
///     .unwrap();
///
/// // Multigrid setup
/// let mut interp_c_to_f: Vec<f64> = vec![0.; p_coarse * p_fine];
/// {
///     let mut coarse = ceed.vector(p_coarse).unwrap();
///     let mut fine = ceed.vector(p_fine).unwrap();
///     let basis_c_to_f = ceed
///         .basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)
///         .unwrap();
///     for i in 0..p_coarse {
///         coarse.set_value(0.0);
///         {
///             let mut array = coarse.view_mut();
///             array[i] = 1.;
///         }
///         basis_c_to_f
///             .apply(
///                 1,
///                 TransposeMode::NoTranspose,
///                 EvalMode::Interp,
///                 &coarse,
///                 &mut fine,
///             )
///             .unwrap();
///         let array = fine.view();
///         for j in 0..p_fine {
///             interp_c_to_f[j * p_coarse + i] = array[j];
///         }
///     }
/// }
/// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine
///     .create_multigrid_level_tensor_H1(&multiplicity, &ru_coarse, &bu_coarse, &interp_c_to_f)
///     .unwrap();
///
/// // Coarse problem
/// u_coarse.set_value(1.0);
/// op_mass_coarse.apply(&u_coarse, &mut v_coarse).unwrap();
///
/// // Check
/// let sum: f64 = v_coarse.view().iter().sum();
/// assert!(
///     (sum - 2.0).abs() < 1e-15,
///     "Incorrect interval length computed"
/// );
///
/// // Prolong
/// op_prolong.apply(&u_coarse, &mut u_fine).unwrap();
///
/// // Fine problem
/// op_mass_fine.apply(&u_fine, &mut v_fine).unwrap();
///
/// // Check
/// let sum: f64 = v_fine.view().iter().sum();
/// assert!(
///     (sum - 2.0).abs() < 1e-15,
///     "Incorrect interval length computed"
/// );
///
/// // Restrict
/// op_restrict.apply(&v_fine, &mut v_coarse).unwrap();
///
/// // Check
/// let sum: f64 = v_coarse.view().iter().sum();
/// assert!(
///     (sum - 2.0).abs() < 1e-15,
///     "Incorrect interval length computed"
/// );
/// ```
Create a multigrid coarse Operator and level transfer Operators for a
given Operator with a tensor basis for the active basis




Create a multigrid coarse Operator and level transfer Operators for a given Operator with a tensor basis for the active basis
pub fn create_multigrid_level_tensor_H1(
        &self,
        p_mult_fine: &Vector,
        rstr_coarse: &ElemRestriction,
        basis_coarse: &Basis,
        interpCtoF: &Vec<f64>,
    ) -> crate::Result<(Operator, Operator, Operator)> {
        let mut ptr_coarse = std::ptr::null_mut();
        let mut ptr_prolong = std::ptr::null_mut();
        let mut ptr_restrict = std::ptr::null_mut();
        let ierr = unsafe {
            bind_ceed::CeedOperatorMultigridLevelCreateTensorH1(
                self.op_core.ptr,
                p_mult_fine.ptr,
                rstr_coarse.ptr,
                basis_coarse.ptr,
                interpCtoF.as_ptr(),
                &mut ptr_coarse,
                &mut ptr_prolong,
                &mut ptr_restrict,
            )
        };
        self.op_core.ceed.check_error(ierr)?;
        let op_coarse = Operator::from_raw(self.op_core.ceed, ptr_coarse)?;
        let op_prolong = Operator::from_raw(self.op_core.ceed, ptr_prolong)?;
        let op_restrict = Operator::from_raw(self.op_core.ceed, ptr_restrict)?;
        Ok((op_coarse, op_prolong, op_restrict))
    }
pub fn create_multigrid_level_tensor_H1 ( & self , p_mult_fine : & Vector , rstr_coarse : & ElemRestriction , basis_coarse : & Basis , interpCtoF : & Vec < f64 > , ) -> crate :: Result < ( Operator , Operator , Operator ) > { let mut ptr_coarse = std :: ptr :: null_mut ( ) ; let mut ptr_prolong = std :: ptr :: null_mut ( ) ; let mut ptr_restrict = std :: ptr :: null_mut ( ) ; let ierr = unsafe { bind_ceed :: CeedOperatorMultigridLevelCreateTensorH1 ( self . op_core . ptr , p_mult_fine . ptr , rstr_coarse . ptr , basis_coarse . ptr , interpCtoF . as_ptr ( ) , & mut ptr_coarse , & mut ptr_prolong , & mut ptr_restrict , ) } ; self . op_core . ceed . check_error ( ierr ) ? ; let op_coarse = Operator :: from_raw ( self . op_core . ceed , ptr_coarse ) ? ; let op_prolong = Operator :: from_raw ( self . op_core . ceed , ptr_prolong ) ? ; let op_restrict = Operator :: from_raw ( self . op_core . ceed , ptr_restrict ) ? ; Ok ( ( op_coarse , op_prolong , op_restrict ) ) }
Create a multigrid coarse Operator and level transfer Operators for a
given Operator with a tensor basis for the active basis
Create a multigrid coarse Operator and level transfer Operators for a given Operator with a tensor basis for the active basis
&self
p_mult_fine
&Vector
rstr_coarse
&ElemRestriction
basis_coarse
&Basis
interpCtoF
&Vec<f64>
&self
p_mult_fine
&Vector
rstr_coarse
&ElemRestriction
basis_coarse
&Basis
interpCtoF
&Vec<f64>
use libceed::prelude::*;
None
let ceed = libceed::ceed::default_init();


Vectors
let x_array = (0..ne + 1)
.map(|i| 2.0 * i as f64 / ne as f64 - 1.0)
.collect::>();
let x = ceed.vector_from_slice(&x_array).unwrap();
let mut qdata = ceed.vector(ne * q).unwrap();
qdata.set_value(0.0);
let mut u_coarse = ceed.vector(ndofs_coarse).unwrap();
u_coarse.set_value(1.0);
let mut u_fine = ceed.vector(ndofs_fine).unwrap();
u_fine.set_value(1.0);
let mut v_coarse = ceed.vector(ndofs_coarse).unwrap();
v_coarse.set_value(0.0);
let mut v_fine = ceed.vector(ndofs_fine).unwrap();
v_fine.set_value(0.0);
let mut multiplicity = ceed.vector(ndofs_fine).unwrap();
multiplicity.set_value(1.0).

Restrictions
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed
.strided_elem_restriction(ne, q, 1, q * ne, strides)
.unwrap().



let mut indu_coarse: Vec = vec![0; p_coarse * ne];
for i in 0..ne {
for j in 0..p_coarse {
indu_coarse[p_coarse * i + j] = (i + j) as i32;
}
}
let ru_coarse = ceed
.elem_restriction(
ne,
p_coarse,
1,
1,
ndofs_coarse,
MemType::Host,
&indu_coarse,
)
.unwrap().

let mut indu_fine: Vec = vec![0; p_fine * ne];
for i in 0..ne {
for j in 0..p_fine {
indu_fine[p_fine * i + j] = (i + j) as i32;
}
}
let ru_fine = ceed
.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)
.unwrap().

Bases
let bx = ceed
.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)
.unwrap();
let bu_coarse = ceed
.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)
.unwrap();
let bu_fine = ceed
.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)
.unwrap().

Build quadrature data
let qf_build = ceed.q_function_interior_by_name("Mass1DBuild").unwrap();
ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)
.unwrap()
.field("dx", ℞, &bx, VectorOpt::Active)
.unwrap()
.field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)
.unwrap()
.field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)
.unwrap()
.apply(&x, &mut qdata)
.unwrap().

Mass operator
let qf_mass = ceed.q_function_interior_by_name("MassApply").unwrap();
let op_mass_fine = ceed
.operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)
.unwrap()
.field("u", &ru_fine, &bu_fine, VectorOpt::Active)
.unwrap()
.field("qdata", &rq, BasisOpt::Collocated, &qdata)
.unwrap()
.field("v", &ru_fine, &bu_fine, VectorOpt::Active)
.unwrap().

Multigrid setup
let mut interp_c_to_f: Vec = vec![0.; p_coarse * p_fine];
{
let mut coarse = ceed.vector(p_coarse).unwrap();
let mut fine = ceed.vector(p_fine).unwrap();
let basis_c_to_f = ceed
.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)
.unwrap();
for i in 0..p_coarse {
coarse.set_value(0.0);
{
let mut array = coarse.view_mut();
array[i] = 1.;
}
basis_c_to_f
.apply(
1,
TransposeMode::NoTranspose,
EvalMode::Interp,
&coarse,
&mut fine,
)
.unwrap();
let array = fine.view();
for j in 0..p_fine {
interp_c_to_f[j * p_coarse + i] = array[j];
}
}
}
let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine
.create_multigrid_level_tensor_H1(&multiplicity, &ru_coarse, &bu_coarse, &interp_c_to_f)
.unwrap().

Coarse problem
u_coarse.set_value(1.0);
op_mass_coarse.apply(&u_coarse, &mut v_coarse).unwrap().

Check
let sum: f64 = v_coarse.view().iter().sum();
assert!(
(sum - 2.0).abs() < 1e-15,
"Incorrect interval length computed"
).

Prolong
op_prolong.apply(&u_coarse, &mut u_fine).unwrap().

Fine problem
op_mass_fine.apply(&u_fine, &mut v_fine).unwrap().

Check
let sum: f64 = v_fine.view().iter().sum();
assert!(
(sum - 2.0).abs() < 1e-15,
"Incorrect interval length computed"
).

Restrict
op_restrict.apply(&v_fine, &mut v_coarse).unwrap().

Check
let sum: f64 = v_coarse.view().iter().sum();
assert!(
(sum - 2.0).abs() < 1e-15,
"Incorrect interval length computed"
);
```
Vectors let x_array = ( 0 .. ne + 1 ) . map ( |i| 2 . 0 * i as f64 / ne as f64 - 1 . 0 ) . collect :: > () ; let x = ceed . vector_from_slice ( &x_array ) . unwrap () ; let mut qdata = ceed . vector ( ne * q ) . unwrap () ; qdata . set_value ( 0 . 0 ) ; let mut u_coarse = ceed . vector ( ndofs_coarse ) . unwrap () ; u_coarse . set_value ( 1 . 0 ) ; let mut u_fine = ceed . vector ( ndofs_fine ) . unwrap () ; u_fine . set_value ( 1 . 0 ) ; let mut v_coarse = ceed . vector ( ndofs_coarse ) . unwrap () ; v_coarse . set_value ( 0 . 0 ) ; let mut v_fine = ceed . vector ( ndofs_fine ) . unwrap () ; v_fine . set_value ( 0 . 0 ) ; let mut multiplicity = ceed . vector ( ndofs_fine ) . unwrap () ; multiplicity . set_value ( 1 . 0 ) . Restrictions let strides : [ i32 ; 3 ] = [ 1 q as i32 q as i32 ] ; let rq = ceed . strided_elem_restriction ( ne q 1 q * ne strides ) . unwrap () . let mut indu_coarse : Vec = vec! [ 0 ; p_coarse * ne ] ; for i in 0 .. ne { for j in 0 .. p_coarse { indu_coarse [ p_coarse * i + j ] = ( i + j ) as i32 ; } } let ru_coarse = ceed . elem_restriction ( ne p_coarse 1 1 ndofs_coarse MemType :: Host &indu_coarse ) . unwrap () . let mut indu_fine : Vec = vec! [ 0 ; p_fine * ne ] ; for i in 0 .. ne { for j in 0 .. p_fine { indu_fine [ p_fine * i + j ] = ( i + j ) as i32 ; } } let ru_fine = ceed . elem_restriction ( ne p_fine 1 1 ndofs_fine MemType :: Host &indu_fine ) . unwrap () . Bases let bx = ceed . basis_tensor_H1_Lagrange ( 1 1 2 q QuadMode :: Gauss ) . unwrap () ; let bu_coarse = ceed . basis_tensor_H1_Lagrange ( 1 1 p_coarse q QuadMode :: Gauss ) . unwrap () ; let bu_fine = ceed . basis_tensor_H1_Lagrange ( 1 1 p_fine q QuadMode :: Gauss ) . unwrap () . Build quadrature data let qf_build = ceed . q_function_interior_by_name ( " Mass1DBuild " ) . unwrap () ; ceed . operator ( &qf_build QFunctionOpt :: None QFunctionOpt :: None ) . unwrap () . field ( " dx " ℞ &bx VectorOpt :: Active ) . unwrap () . field ( " weights " ElemRestrictionOpt :: None &bx VectorOpt :: None ) . unwrap () . field ( " qdata " &rq BasisOpt :: Collocated VectorOpt :: Active ) . unwrap () . apply ( &x &mut qdata ) . unwrap () . Mass operator let qf_mass = ceed . q_function_interior_by_name ( " MassApply " ) . unwrap () ; let op_mass_fine = ceed . operator ( &qf_mass QFunctionOpt :: None QFunctionOpt :: None ) . unwrap () . field ( " u " &ru_fine &bu_fine VectorOpt :: Active ) . unwrap () . field ( " qdata " &rq BasisOpt :: Collocated &qdata ) . unwrap () . field ( " v " &ru_fine &bu_fine VectorOpt :: Active ) . unwrap () . Multigrid setup let mut interp_c_to_f : Vec = vec! [ 0 . ; p_coarse * p_fine ] ; { let mut coarse = ceed . vector ( p_coarse ) . unwrap () ; let mut fine = ceed . vector ( p_fine ) . unwrap () ; let basis_c_to_f = ceed . basis_tensor_H1_Lagrange ( 1 1 p_coarse p_fine QuadMode :: GaussLobatto ) . unwrap () ; for i in 0 .. p_coarse { coarse . set_value ( 0 . 0 ) ; { let mut array = coarse . view_mut () ; array [ i ] = 1 . ; } basis_c_to_f . apply ( 1 TransposeMode :: NoTranspose EvalMode :: Interp &coarse &mut fine ) . unwrap () ; let array = fine . view () ; for j in 0 .. p_fine { interp_c_to_f [ j * p_coarse + i ] = array [ j ] ; } } } let ( op_mass_coarse op_prolong op_restrict ) = op_mass_fine . create_multigrid_level_tensor_H1 ( &multiplicity &ru_coarse &bu_coarse &interp_c_to_f ) . unwrap () . Coarse problem u_coarse . set_value ( 1 . 0 ) ; op_mass_coarse . apply ( &u_coarse &mut v_coarse ) . unwrap () . Check let sum : f64 = v_coarse . view () . iter () . sum () ; assert! ( ( sum - 2 . 0 ) . abs () < 1e - 15 " Incorrect interval length computed " ) . Prolong op_prolong . apply ( &u_coarse &mut u_fine ) . unwrap () . Fine problem op_mass_fine . apply ( &u_fine &mut v_fine ) . unwrap () . Check let sum : f64 = v_fine . view () . iter () . sum () ; assert! ( ( sum - 2 . 0 ) . abs () < 1e - 15 " Incorrect interval length computed " ) . Restrict op_restrict . apply ( &v_fine &mut v_coarse ) . unwrap () . Check let sum : f64 = v_coarse . view () . iter () . sum () ; assert! ( ( sum - 2 . 0 ) . abs () < 1e - 15 " Incorrect interval length computed " ) ; ` ` `