Struct Operator

Source
pub struct Operator<'a> { /* private fields */ }

Implementations§

Source§

impl<'a> Operator<'a>

Source

pub fn create<'b>( ceed: &Ceed, qf: impl Into<QFunctionOpt<'b>>, dqf: impl Into<QFunctionOpt<'b>>, dqfT: impl Into<QFunctionOpt<'b>>, ) -> Result<Self>

Source

pub fn name(self, name: &str) -> Result<Self>

Set name for Operator printing

  • ‘name’ - Name to set
let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;

// Operator field arguments
let ne = 3;
let q = 4 as usize;
let mut ind: Vec<i32> = vec![0; 2 * ne];
for i in 0..ne {
    ind[2 * i + 0] = i as i32;
    ind[2 * i + 1] = (i + 1) as i32;
}
let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;

let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;

// Operator fields
let op = ceed
    .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
    .name("mass")?
    .field("dx", &r, &b, VectorOpt::Active)?
    .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
    .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;
Source

pub fn apply(&self, input: &Vector<'_>, output: &mut Vector<'_>) -> Result<i32>

Apply Operator to a vector

  • input - Input Vector
  • output - Output Vector
let ne = 4;
let p = 3;
let q = 4;
let ndofs = p * ne - ne + 1;

// Vectors
let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
let mut qdata = ceed.vector(ne * q)?;
qdata.set_value(0.0);
let u = ceed.vector_from_slice(&vec![1.0; ndofs])?;
let mut v = ceed.vector(ndofs)?;
v.set_value(0.0);

// Restrictions
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)?;
let mut indu: Vec<i32> = vec![0; p * ne];
for i in 0..ne {
    indu[p * i + 0] = i as i32;
    indu[p * i + 1] = (i + 1) as i32;
    indu[p * i + 2] = (i + 2) as i32;
}
let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;

// Bases
let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;

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

// Mass operator
let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
let op_mass = ceed
    .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
    .field("u", &ru, &bu, VectorOpt::Active)?
    .field("qdata", &rq, BasisOpt::None, &qdata)?
    .field("v", &ru, &bu, VectorOpt::Active)?;

v.set_value(0.0);
op_mass.apply(&u, &mut v)?;

// Check
let sum: Scalar = v.view()?.iter().sum();
let error: Scalar = (sum - 2.0).abs();
assert!(
    error < 50.0 * libceed::EPSILON,
    "Incorrect interval length computed. Expected: 2.0, Found: {}, Error: {:.12e}",
    sum,
    error
);
Source

pub fn apply_add( &self, input: &Vector<'_>, output: &mut Vector<'_>, ) -> Result<i32>

Apply Operator to a vector and add result to output vector

  • input - Input Vector
  • output - Output Vector
let ne = 4;
let p = 3;
let q = 4;
let ndofs = p * ne - ne + 1;

// Vectors
let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
let mut qdata = ceed.vector(ne * q)?;
qdata.set_value(0.0);
let u = ceed.vector_from_slice(&vec![1.0; ndofs])?;
let mut v = ceed.vector(ndofs)?;

// Restrictions
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)?;
let mut indu: Vec<i32> = vec![0; p * ne];
for i in 0..ne {
    indu[p * i + 0] = i as i32;
    indu[p * i + 1] = (i + 1) as i32;
    indu[p * i + 2] = (i + 2) as i32;
}
let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?;
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;

// Bases
let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;

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

// Mass operator
let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
let op_mass = ceed
    .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
    .field("u", &ru, &bu, VectorOpt::Active)?
    .field("qdata", &rq, BasisOpt::None, &qdata)?
    .field("v", &ru, &bu, VectorOpt::Active)?;

v.set_value(1.0);
op_mass.apply_add(&u, &mut v)?;

// Check
let sum: Scalar = v.view()?.iter().sum();
assert!(
    (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON,
    "Incorrect interval length computed and added"
);
Source

pub fn field<'b>( self, fieldname: &str, r: impl Into<ElemRestrictionOpt<'b>>, b: impl Into<BasisOpt<'b>>, v: impl Into<VectorOpt<'b>>, ) -> Result<Self>

Provide a field to a Operator for use by its QFunction

  • fieldname - Name of the field (to be matched with the name used by the QFunction)
  • r - ElemRestriction
  • b - Basis in which the field resides or BasisOpt::None
  • v - Vector to be used by Operator or VectorOpt::Active if field is active or VectorOpt::None if using Weight with the QFunction
let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;

// Operator field arguments
let ne = 3;
let q = 4;
let mut ind: Vec<i32> = vec![0; 2 * ne];
for i in 0..ne {
    ind[2 * i + 0] = i as i32;
    ind[2 * i + 1] = (i + 1) as i32;
}
let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;

let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;

// Operator field
op = op.field("dx", &r, &b, VectorOpt::Active)?;
Source

pub fn inputs(&self) -> Result<&[OperatorField<'_>]>

Get a slice of Operator inputs

let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;

// Operator field arguments
let ne = 3;
let q = 4 as usize;
let mut ind: Vec<i32> = vec![0; 2 * ne];
for i in 0..ne {
    ind[2 * i + 0] = i as i32;
    ind[2 * i + 1] = (i + 1) as i32;
}
let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;

let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;

// Operator fields
let op = ceed
    .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
    .field("dx", &r, &b, VectorOpt::Active)?
    .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
    .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;

let inputs = op.inputs()?;

assert_eq!(inputs.len(), 2, "Incorrect inputs array");
Source

pub fn outputs(&self) -> Result<&[OperatorField<'_>]>

Get a slice of Operator outputs

let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;

// Operator field arguments
let ne = 3;
let q = 4 as usize;
let mut ind: Vec<i32> = vec![0; 2 * ne];
for i in 0..ne {
    ind[2 * i + 0] = i as i32;
    ind[2 * i + 1] = (i + 1) as i32;
}
let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;

let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;

// Operator fields
let op = ceed
    .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
    .field("dx", &r, &b, VectorOpt::Active)?
    .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
    .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;

let outputs = op.outputs()?;

assert_eq!(outputs.len(), 1, "Incorrect outputs array");
Source

pub fn check(self) -> Result<Self>

Check if Operator is setup correctly

let ne = 4;
let p = 3;
let q = 4;
let ndofs = p * ne - ne + 1;

// Restrictions
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)?;
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;

// Bases
let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;

// Build quadrature data
let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?;
let op_build = ceed
    .operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)?
    .field("dx", &rx, &bx, VectorOpt::Active)?
    .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)?
    .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;

// Check
assert!(op_build.check().is_ok(), "Operator setup incorrectly");
Source

pub fn num_elements(&self) -> usize

Get the number of elements associated with an Operator

let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;

// Operator field arguments
let ne = 3;
let q = 4;
let mut ind: Vec<i32> = vec![0; 2 * ne];
for i in 0..ne {
    ind[2 * i + 0] = i as i32;
    ind[2 * i + 1] = (i + 1) as i32;
}
let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;

let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;

// Operator field
op = op.field("dx", &r, &b, VectorOpt::Active)?;

// Check number of elements
assert_eq!(op.num_elements(), ne, "Incorrect number of elements");
Source

pub fn num_quadrature_points(&self) -> usize

Get the number of quadrature points associated with each element of an Operator

let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;
let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?;

// Operator field arguments
let ne = 3;
let q = 4;
let mut ind: Vec<i32> = vec![0; 2 * ne];
for i in 0..ne {
    ind[2 * i + 0] = i as i32;
    ind[2 * i + 1] = (i + 1) as i32;
}
let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;

let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;

// Operator field
op = op.field("dx", &r, &b, VectorOpt::Active)?;

// Check number of quadrature points
assert_eq!(
    op.num_quadrature_points(),
    q,
    "Incorrect number of quadrature points"
);
Source

pub fn linear_assemble_diagonal( &self, assembled: &mut Vector<'_>, ) -> Result<i32>

Assemble the diagonal of a square linear Operator

This overwrites a Vector with the diagonal of a linear Operator.

Note: Currently only non-composite Operators with a single field and composite Operators with single field sub-operators are supported.

  • op - Operator to assemble QFunction
  • assembled - Vector to store assembled Operator diagonal
let ne = 4;
let p = 3;
let q = 4;
let ndofs = p * ne - ne + 1;

// Vectors
let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
let mut qdata = ceed.vector(ne * q)?;
qdata.set_value(0.0);
let mut u = ceed.vector(ndofs)?;
u.set_value(1.0);
let mut v = ceed.vector(ndofs)?;
v.set_value(0.0);

// Restrictions
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)?;
let mut indu: Vec<i32> = vec![0; p * ne];
for i in 0..ne {
    indu[p * i + 0] = (2 * i) as i32;
    indu[p * i + 1] = (2 * i + 1) as i32;
    indu[p * i + 2] = (2 * i + 2) as i32;
}
let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?;
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;

// Bases
let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;

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

// Mass operator
let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
let op_mass = ceed
    .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
    .field("u", &ru, &bu, VectorOpt::Active)?
    .field("qdata", &rq, BasisOpt::None, &qdata)?
    .field("v", &ru, &bu, VectorOpt::Active)?;

// Diagonal
let mut diag = ceed.vector(ndofs)?;
diag.set_value(0.0);
op_mass.linear_assemble_diagonal(&mut diag)?;

// Manual diagonal computation
let mut true_diag = ceed.vector(ndofs)?;
true_diag.set_value(0.0)?;
for i in 0..ndofs {
    u.set_value(0.0);
    {
        let mut u_array = u.view_mut()?;
        u_array[i] = 1.;
    }

    op_mass.apply(&u, &mut v)?;

    {
        let v_array = v.view()?;
        let mut true_array = true_diag.view_mut()?;
        true_array[i] = v_array[i];
    }
}

// Check
diag.view()?
    .iter()
    .zip(true_diag.view()?.iter())
    .for_each(|(computed, actual)| {
        assert!(
            (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
            "Diagonal entry incorrect"
        );
    });
Source

pub fn linear_assemble_add_diagonal( &self, assembled: &mut Vector<'_>, ) -> Result<i32>

Assemble the diagonal of a square linear Operator

This sums into a Vector with the diagonal of a linear Operator.

Note: Currently only non-composite Operators with a single field and composite Operators with single field sub-operators are supported.

  • op - Operator to assemble QFunction
  • assembled - Vector to store assembled Operator diagonal
let ne = 4;
let p = 3;
let q = 4;
let ndofs = p * ne - ne + 1;

// Vectors
let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
let mut qdata = ceed.vector(ne * q)?;
qdata.set_value(0.0);
let mut u = ceed.vector(ndofs)?;
u.set_value(1.0);
let mut v = ceed.vector(ndofs)?;
v.set_value(0.0);

// Restrictions
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)?;
let mut indu: Vec<i32> = vec![0; p * ne];
for i in 0..ne {
    indu[p * i + 0] = (2 * i) as i32;
    indu[p * i + 1] = (2 * i + 1) as i32;
    indu[p * i + 2] = (2 * i + 2) as i32;
}
let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?;
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;

// Bases
let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?;

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

// Mass operator
let qf_mass = ceed.q_function_interior_by_name("MassApply")?;
let op_mass = ceed
    .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
    .field("u", &ru, &bu, VectorOpt::Active)?
    .field("qdata", &rq, BasisOpt::None, &qdata)?
    .field("v", &ru, &bu, VectorOpt::Active)?;

// Diagonal
let mut diag = ceed.vector(ndofs)?;
diag.set_value(1.0);
op_mass.linear_assemble_add_diagonal(&mut diag)?;

// Manual diagonal computation
let mut true_diag = ceed.vector(ndofs)?;
true_diag.set_value(0.0)?;
for i in 0..ndofs {
    u.set_value(0.0);
    {
        let mut u_array = u.view_mut()?;
        u_array[i] = 1.;
    }

    op_mass.apply(&u, &mut v)?;

    {
        let v_array = v.view()?;
        let mut true_array = true_diag.view_mut()?;
        true_array[i] = v_array[i] + 1.0;
    }
}

// Check
diag.view()?
    .iter()
    .zip(true_diag.view()?.iter())
    .for_each(|(computed, actual)| {
        assert!(
            (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
            "Diagonal entry incorrect"
        );
    });
Source

pub fn linear_assemble_point_block_diagonal( &self, assembled: &mut Vector<'_>, ) -> Result<i32>

Assemble the point block diagonal of a square linear Operator

This overwrites a Vector with the point block diagonal of a linear Operator.

Note: Currently only non-composite Operators with a single field and composite Operators with single field sub-operators are supported.

  • op - Operator to assemble QFunction
  • assembled - Vector to store assembled CeedOperator point block diagonal, provided in row-major form with an ncomp * ncomp block at each node. The dimensions of this vector are derived from the active vector for the CeedOperator. The array has shape [nodes, component out, component in].
let ne = 4;
let p = 3;
let q = 4;
let ncomp = 2;
let ndofs = p * ne - ne + 1;

// Vectors
let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
let mut qdata = ceed.vector(ne * q)?;
qdata.set_value(0.0);
let mut u = ceed.vector(ncomp * ndofs)?;
u.set_value(1.0);
let mut v = ceed.vector(ncomp * ndofs)?;
v.set_value(0.0);

// Restrictions
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)?;
let mut indu: Vec<i32> = vec![0; p * ne];
for i in 0..ne {
    indu[p * i + 0] = (2 * i) as i32;
    indu[p * i + 1] = (2 * i + 1) as i32;
    indu[p * i + 2] = (2 * i + 2) as i32;
}
let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?;
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;

// Bases
let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?;

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

// Mass operator
let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
    // Number of quadrature points
    let q = qdata.len();

    // Iterate over quadrature points
    for i in 0..q {
        v[i + 0 * q] = u[i + 1 * q] * qdata[i];
        v[i + 1 * q] = u[i + 0 * q] * qdata[i];
    }

    // Return clean error code
    0
};

let qf_mass = ceed
    .q_function_interior(1, Box::new(mass_2_comp))?
    .input("u", 2, EvalMode::Interp)?
    .input("qdata", 1, EvalMode::None)?
    .output("v", 2, EvalMode::Interp)?;

let op_mass = ceed
    .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
    .field("u", &ru, &bu, VectorOpt::Active)?
    .field("qdata", &rq, BasisOpt::None, &qdata)?
    .field("v", &ru, &bu, VectorOpt::Active)?;

// Diagonal
let mut diag = ceed.vector(ncomp * ncomp * ndofs)?;
diag.set_value(0.0);
op_mass.linear_assemble_point_block_diagonal(&mut diag)?;

// Manual diagonal computation
let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?;
true_diag.set_value(0.0)?;
for i in 0..ndofs {
    for j in 0..ncomp {
        u.set_value(0.0);
        {
            let mut u_array = u.view_mut()?;
            u_array[i + j * ndofs] = 1.;
        }

        op_mass.apply(&u, &mut v)?;

        {
            let v_array = v.view()?;
            let mut true_array = true_diag.view_mut()?;
            for k in 0..ncomp {
                true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
            }
        }
    }
}

// Check
diag.view()?
    .iter()
    .zip(true_diag.view()?.iter())
    .for_each(|(computed, actual)| {
        assert!(
            (*computed - *actual).abs() < 10.0 * libceed::EPSILON,
            "Diagonal entry incorrect"
        );
    });
Source

pub fn linear_assemble_add_point_block_diagonal( &self, assembled: &mut Vector<'_>, ) -> Result<i32>

Assemble the point block diagonal of a square linear Operator

This sums into a Vector with the point block diagonal of a linear Operator.

Note: Currently only non-composite Operators with a single field and composite Operators with single field sub-operators are supported.

  • op - Operator to assemble QFunction
  • assembled - Vector to store assembled CeedOperator point block diagonal, provided in row-major form with an ncomp * ncomp block at each node. The dimensions of this vector are derived from the active vector for the CeedOperator. The array has shape [nodes, component out, component in].
let ne = 4;
let p = 3;
let q = 4;
let ncomp = 2;
let ndofs = p * ne - ne + 1;

// Vectors
let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?;
let mut qdata = ceed.vector(ne * q)?;
qdata.set_value(0.0);
let mut u = ceed.vector(ncomp * ndofs)?;
u.set_value(1.0);
let mut v = ceed.vector(ncomp * ndofs)?;
v.set_value(0.0);

// Restrictions
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)?;
let mut indu: Vec<i32> = vec![0; p * ne];
for i in 0..ne {
    indu[p * i + 0] = (2 * i) as i32;
    indu[p * i + 1] = (2 * i + 1) as i32;
    indu[p * i + 2] = (2 * i + 2) as i32;
}
let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?;
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;

// Bases
let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;
let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?;

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

// Mass operator
let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| {
    // Number of quadrature points
    let q = qdata.len();

    // Iterate over quadrature points
    for i in 0..q {
        v[i + 0 * q] = u[i + 1 * q] * qdata[i];
        v[i + 1 * q] = u[i + 0 * q] * qdata[i];
    }

    // Return clean error code
    0
};

let qf_mass = ceed
    .q_function_interior(1, Box::new(mass_2_comp))?
    .input("u", 2, EvalMode::Interp)?
    .input("qdata", 1, EvalMode::None)?
    .output("v", 2, EvalMode::Interp)?;

let op_mass = ceed
    .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?
    .field("u", &ru, &bu, VectorOpt::Active)?
    .field("qdata", &rq, BasisOpt::None, &qdata)?
    .field("v", &ru, &bu, VectorOpt::Active)?;

// Diagonal
let mut diag = ceed.vector(ncomp * ncomp * ndofs)?;
diag.set_value(1.0);
op_mass.linear_assemble_add_point_block_diagonal(&mut diag)?;

// Manual diagonal computation
let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?;
true_diag.set_value(0.0)?;
for i in 0..ndofs {
    for j in 0..ncomp {
        u.set_value(0.0);
        {
            let mut u_array = u.view_mut()?;
            u_array[i + j * ndofs] = 1.;
        }

        op_mass.apply(&u, &mut v)?;

        {
            let v_array = v.view()?;
            let mut true_array = true_diag.view_mut()?;
            for k in 0..ncomp {
                true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs];
            }
        }
    }
}

// Check
diag.view()?
    .iter()
    .zip(true_diag.view()?.iter())
    .for_each(|(computed, actual)| {
        assert!(
            (*computed - 1.0 - *actual).abs() < 10.0 * libceed::EPSILON,
            "Diagonal entry incorrect"
        );
    });
Source

pub fn create_multigrid_level<'b>( &self, p_mult_fine: &Vector<'_>, rstr_coarse: &ElemRestriction<'_>, basis_coarse: &Basis<'_>, ) -> Result<(Operator<'b>, Operator<'b>, Operator<'b>)>

Create a multigrid coarse Operator and level transfer Operators for a given Operator, creating the prolongation basis from the fine and coarse grid interpolation

  • p_mult_fine - Lvector multiplicity in parallel gather/scatter
  • rstr_coarse - Coarse grid restriction
  • basis_coarse - Coarse grid active vector basis
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 Scalar / ne as Scalar - 1.0)
    .collect::<Vec<Scalar>>();
let x = ceed.vector_from_slice(&x_array)?;
let mut qdata = ceed.vector(ne * q)?;
qdata.set_value(0.0);
let mut u_coarse = ceed.vector(ndofs_coarse)?;
u_coarse.set_value(1.0);
let mut u_fine = ceed.vector(ndofs_fine)?;
u_fine.set_value(1.0);
let mut v_coarse = ceed.vector(ndofs_coarse)?;
v_coarse.set_value(0.0);
let mut v_fine = ceed.vector(ndofs_fine)?;
v_fine.set_value(0.0);
let mut multiplicity = ceed.vector(ndofs_fine)?;
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)?;

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)?;

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,
)?;

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)?;

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

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

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

// Multigrid setup
let (op_mass_coarse, op_prolong, op_restrict) =
    op_mass_fine.create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)?;

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

// Check
let sum: Scalar = v_coarse.view()?.iter().sum();
assert!(
    (sum - 2.0).abs() < 50.0 * libceed::EPSILON,
    "Incorrect interval length computed"
);

// Prolong
op_prolong.apply(&u_coarse, &mut u_fine)?;

// Fine problem
op_mass_fine.apply(&u_fine, &mut v_fine)?;

// Check
let sum: Scalar = v_fine.view()?.iter().sum();
assert!(
    (sum - 2.0).abs() < 50.0 * libceed::EPSILON,
    "Incorrect interval length computed"
);

// Restrict
op_restrict.apply(&v_fine, &mut v_coarse)?;

// Check
let sum: Scalar = v_coarse.view()?.iter().sum();
assert!(
    (sum - 2.0).abs() < 50.0 * libceed::EPSILON,
    "Incorrect interval length computed"
);
Source

pub fn create_multigrid_level_tensor_H1<'b>( &self, p_mult_fine: &Vector<'_>, rstr_coarse: &ElemRestriction<'_>, basis_coarse: &Basis<'_>, interpCtoF: &Vec<Scalar>, ) -> Result<(Operator<'b>, Operator<'b>, Operator<'b>)>

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
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 Scalar / ne as Scalar - 1.0)
    .collect::<Vec<Scalar>>();
let x = ceed.vector_from_slice(&x_array)?;
let mut qdata = ceed.vector(ne * q)?;
qdata.set_value(0.0);
let mut u_coarse = ceed.vector(ndofs_coarse)?;
u_coarse.set_value(1.0);
let mut u_fine = ceed.vector(ndofs_fine)?;
u_fine.set_value(1.0);
let mut v_coarse = ceed.vector(ndofs_coarse)?;
v_coarse.set_value(0.0);
let mut v_fine = ceed.vector(ndofs_fine)?;
v_fine.set_value(0.0);
let mut multiplicity = ceed.vector(ndofs_fine)?;
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)?;

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)?;

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,
)?;

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)?;

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

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

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

// Multigrid setup
let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine];
{
    let mut coarse = ceed.vector(p_coarse)?;
    let mut fine = ceed.vector(p_fine)?;
    let basis_c_to_f =
        ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?;
    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,
        )?;
        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,
)?;

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

// Check
let sum: Scalar = v_coarse.view()?.iter().sum();
assert!(
    (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
    "Incorrect interval length computed"
);

// Prolong
op_prolong.apply(&u_coarse, &mut u_fine)?;

// Fine problem
op_mass_fine.apply(&u_fine, &mut v_fine)?;

// Check
let sum: Scalar = v_fine.view()?.iter().sum();
assert!(
    (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
    "Incorrect interval length computed"
);

// Restrict
op_restrict.apply(&v_fine, &mut v_coarse)?;

// Check
let sum: Scalar = v_coarse.view()?.iter().sum();
assert!(
    (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
    "Incorrect interval length computed"
);
Source

pub fn create_multigrid_level_H1<'b>( &self, p_mult_fine: &Vector<'_>, rstr_coarse: &ElemRestriction<'_>, basis_coarse: &Basis<'_>, interpCtoF: &[Scalar], ) -> Result<(Operator<'b>, Operator<'b>, Operator<'b>)>

Create a multigrid coarse Operator and level transfer Operators for a given Operator with a non-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
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 Scalar / ne as Scalar - 1.0)
    .collect::<Vec<Scalar>>();
let x = ceed.vector_from_slice(&x_array)?;
let mut qdata = ceed.vector(ne * q)?;
qdata.set_value(0.0);
let mut u_coarse = ceed.vector(ndofs_coarse)?;
u_coarse.set_value(1.0);
let mut u_fine = ceed.vector(ndofs_fine)?;
u_fine.set_value(1.0);
let mut v_coarse = ceed.vector(ndofs_coarse)?;
v_coarse.set_value(0.0);
let mut v_fine = ceed.vector(ndofs_fine)?;
v_fine.set_value(0.0);
let mut multiplicity = ceed.vector(ndofs_fine)?;
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)?;

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)?;

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,
)?;

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)?;

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

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

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

// Multigrid setup
let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine];
{
    let mut coarse = ceed.vector(p_coarse)?;
    let mut fine = ceed.vector(p_fine)?;
    let basis_c_to_f =
        ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?;
    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,
        )?;
        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_H1(
    &multiplicity,
    &ru_coarse,
    &bu_coarse,
    &interp_c_to_f,
)?;

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

// Check
let sum: Scalar = v_coarse.view()?.iter().sum();
assert!(
    (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
    "Incorrect interval length computed"
);

// Prolong
op_prolong.apply(&u_coarse, &mut u_fine)?;

// Fine problem
op_mass_fine.apply(&u_fine, &mut v_fine)?;

// Check
let sum: Scalar = v_fine.view()?.iter().sum();
assert!(
    (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
    "Incorrect interval length computed"
);

// Restrict
op_restrict.apply(&v_fine, &mut v_coarse)?;

// Check
let sum: Scalar = v_coarse.view()?.iter().sum();
assert!(
    (sum - 2.0).abs() < 10.0 * libceed::EPSILON,
    "Incorrect interval length computed"
);

Trait Implementations§

Source§

impl<'a> Debug for Operator<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'a> Display for Operator<'a>

View an Operator

let qf = ceed.q_function_interior_by_name("Mass1DBuild")?;

// Operator field arguments
let ne = 3;
let q = 4 as usize;
let mut ind: Vec<i32> = vec![0; 2 * ne];
for i in 0..ne {
    ind[2 * i + 0] = i as i32;
    ind[2 * i + 1] = (i + 1) as i32;
}
let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?;
let strides: [i32; 3] = [1, q as i32, q as i32];
let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?;

let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?;

// Operator fields
let op = ceed
    .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?
    .name("mass")?
    .field("dx", &r, &b, VectorOpt::Active)?
    .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)?
    .field("qdata", &rq, BasisOpt::None, VectorOpt::Active)?;

println!("{}", op);
Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for Operator<'a>

§

impl<'a> RefUnwindSafe for Operator<'a>

§

impl<'a> !Send for Operator<'a>

§

impl<'a> !Sync for Operator<'a>

§

impl<'a> Unpin for Operator<'a>

§

impl<'a> UnwindSafe for Operator<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.