pub struct Operator<'a> { /* private fields */ }
Implementations§
Source§impl<'a> Operator<'a>
impl<'a> Operator<'a>
pub fn create<'b>( ceed: &Ceed, qf: impl Into<QFunctionOpt<'b>>, dqf: impl Into<QFunctionOpt<'b>>, dqfT: impl Into<QFunctionOpt<'b>>, ) -> Result<Self>
Sourcepub fn name(self, name: &str) -> Result<Self>
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)?;
Sourcepub fn apply(&self, input: &Vector<'_>, output: &mut Vector<'_>) -> Result<i32>
pub fn apply(&self, input: &Vector<'_>, output: &mut Vector<'_>) -> Result<i32>
Apply Operator to a vector
input
- Input Vectoroutput
- 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
);
Sourcepub fn apply_add(
&self,
input: &Vector<'_>,
output: &mut Vector<'_>,
) -> Result<i32>
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 Vectoroutput
- 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"
);
Sourcepub fn field<'b>(
self,
fieldname: &str,
r: impl Into<ElemRestrictionOpt<'b>>,
b: impl Into<BasisOpt<'b>>,
v: impl Into<VectorOpt<'b>>,
) -> Result<Self>
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
- ElemRestrictionb
- Basis in which the field resides orBasisOpt::None
v
- Vector to be used by Operator orVectorOpt::Active
if field is active orVectorOpt::None
if usingWeight
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)?;
Sourcepub fn inputs(&self) -> Result<&[OperatorField<'_>]>
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");
Sourcepub fn outputs(&self) -> Result<&[OperatorField<'_>]>
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");
Sourcepub fn check(self) -> Result<Self>
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");
Sourcepub fn num_elements(&self) -> usize
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");
Sourcepub fn num_quadrature_points(&self) -> usize
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"
);
Sourcepub fn linear_assemble_diagonal(
&self,
assembled: &mut Vector<'_>,
) -> Result<i32>
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 QFunctionassembled
- 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"
);
});
Sourcepub fn linear_assemble_add_diagonal(
&self,
assembled: &mut Vector<'_>,
) -> Result<i32>
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 QFunctionassembled
- 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"
);
});
Sourcepub fn linear_assemble_point_block_diagonal(
&self,
assembled: &mut Vector<'_>,
) -> Result<i32>
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 QFunctionassembled
- Vector to store assembled CeedOperator point block diagonal, provided in row-major form with anncomp * 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"
);
});
Sourcepub fn linear_assemble_add_point_block_diagonal(
&self,
assembled: &mut Vector<'_>,
) -> Result<i32>
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 QFunctionassembled
- Vector to store assembled CeedOperator point block diagonal, provided in row-major form with anncomp * 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"
);
});
Sourcepub fn create_multigrid_level<'b>(
&self,
p_mult_fine: &Vector<'_>,
rstr_coarse: &ElemRestriction<'_>,
basis_coarse: &Basis<'_>,
) -> Result<(Operator<'b>, Operator<'b>, Operator<'b>)>
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/scatterrstr_coarse
- Coarse grid restrictionbasis_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"
);
Sourcepub 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>)>
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/scatterrstr_coarse
- Coarse grid restrictionbasis_coarse
- Coarse grid active vector basisinterp_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"
);
Sourcepub 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>)>
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/scatterrstr_coarse
- Coarse grid restrictionbasis_coarse
- Coarse grid active vector basisinterp_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> Display for Operator<'a>
View an Operator
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);