19df49d7eSJed Brown // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 29df49d7eSJed Brown // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 39df49d7eSJed Brown // reserved. See files LICENSE and NOTICE for details. 49df49d7eSJed Brown // 59df49d7eSJed Brown // This file is part of CEED, a collection of benchmarks, miniapps, software 69df49d7eSJed Brown // libraries and APIs for efficient high-order finite element and spectral 79df49d7eSJed Brown // element discretizations for exascale applications. For more information and 89df49d7eSJed Brown // source code availability see http://github.com/ceed. 99df49d7eSJed Brown // 109df49d7eSJed Brown // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 119df49d7eSJed Brown // a collaborative effort of two U.S. Department of Energy organizations (Office 129df49d7eSJed Brown // of Science and the National Nuclear Security Administration) responsible for 139df49d7eSJed Brown // the planning and preparation of a capable exascale ecosystem, including 149df49d7eSJed Brown // software, applications, hardware, advanced system engineering and early 159df49d7eSJed Brown // testbed platforms, in support of the nation's exascale computing imperative 169df49d7eSJed Brown 179df49d7eSJed Brown //! A Ceed Operator defines the finite/spectral element operator associated to a 189df49d7eSJed Brown //! Ceed QFunction. A Ceed Operator connects Ceed ElemRestrictions, 199df49d7eSJed Brown //! Ceed Bases, and Ceed QFunctions. 209df49d7eSJed Brown 219df49d7eSJed Brown use crate::prelude::*; 229df49d7eSJed Brown 239df49d7eSJed Brown // ----------------------------------------------------------------------------- 249df49d7eSJed Brown // CeedOperator context wrapper 259df49d7eSJed Brown // ----------------------------------------------------------------------------- 26c68be7a2SJeremy L Thompson #[derive(Debug)] 279df49d7eSJed Brown pub(crate) struct OperatorCore<'a> { 289df49d7eSJed Brown ptr: bind_ceed::CeedOperator, 29*1142270cSJeremy L Thompson _lifeline: PhantomData<&'a ()>, 309df49d7eSJed Brown } 319df49d7eSJed Brown 32c68be7a2SJeremy L Thompson #[derive(Debug)] 339df49d7eSJed Brown pub struct Operator<'a> { 349df49d7eSJed Brown op_core: OperatorCore<'a>, 359df49d7eSJed Brown } 369df49d7eSJed Brown 37c68be7a2SJeremy L Thompson #[derive(Debug)] 389df49d7eSJed Brown pub struct CompositeOperator<'a> { 399df49d7eSJed Brown op_core: OperatorCore<'a>, 409df49d7eSJed Brown } 419df49d7eSJed Brown 429df49d7eSJed Brown // ----------------------------------------------------------------------------- 439df49d7eSJed Brown // Destructor 449df49d7eSJed Brown // ----------------------------------------------------------------------------- 459df49d7eSJed Brown impl<'a> Drop for OperatorCore<'a> { 469df49d7eSJed Brown fn drop(&mut self) { 479df49d7eSJed Brown unsafe { 489df49d7eSJed Brown bind_ceed::CeedOperatorDestroy(&mut self.ptr); 499df49d7eSJed Brown } 509df49d7eSJed Brown } 519df49d7eSJed Brown } 529df49d7eSJed Brown 539df49d7eSJed Brown // ----------------------------------------------------------------------------- 549df49d7eSJed Brown // Display 559df49d7eSJed Brown // ----------------------------------------------------------------------------- 569df49d7eSJed Brown impl<'a> fmt::Display for OperatorCore<'a> { 579df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 589df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 599df49d7eSJed Brown let mut sizeloc = crate::MAX_BUFFER_LENGTH; 609df49d7eSJed Brown let cstring = unsafe { 619df49d7eSJed Brown let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc); 629df49d7eSJed Brown bind_ceed::CeedOperatorView(self.ptr, file); 639df49d7eSJed Brown bind_ceed::fclose(file); 649df49d7eSJed Brown CString::from_raw(ptr) 659df49d7eSJed Brown }; 669df49d7eSJed Brown cstring.to_string_lossy().fmt(f) 679df49d7eSJed Brown } 689df49d7eSJed Brown } 699df49d7eSJed Brown 709df49d7eSJed Brown /// View an Operator 719df49d7eSJed Brown /// 729df49d7eSJed Brown /// ``` 739df49d7eSJed Brown /// # use libceed::prelude::*; 74c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 759df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 76c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 779df49d7eSJed Brown /// 789df49d7eSJed Brown /// // Operator field arguments 799df49d7eSJed Brown /// let ne = 3; 809df49d7eSJed Brown /// let q = 4 as usize; 819df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 829df49d7eSJed Brown /// for i in 0..ne { 839df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 849df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 859df49d7eSJed Brown /// } 86c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 879df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 88c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 899df49d7eSJed Brown /// 90c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 919df49d7eSJed Brown /// 929df49d7eSJed Brown /// // Operator fields 939df49d7eSJed Brown /// let op = ceed 94c68be7a2SJeremy L Thompson /// .operator(&qf, QFunctionOpt::None, QFunctionOpt::None)? 95c68be7a2SJeremy L Thompson /// .field("dx", &r, &b, VectorOpt::Active)? 96c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &b, VectorOpt::None)? 97c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)?; 989df49d7eSJed Brown /// 999df49d7eSJed Brown /// println!("{}", op); 100c68be7a2SJeremy L Thompson /// # Ok(()) 101c68be7a2SJeremy L Thompson /// # } 1029df49d7eSJed Brown /// ``` 1039df49d7eSJed Brown impl<'a> fmt::Display for Operator<'a> { 1049df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1059df49d7eSJed Brown self.op_core.fmt(f) 1069df49d7eSJed Brown } 1079df49d7eSJed Brown } 1089df49d7eSJed Brown 1099df49d7eSJed Brown /// View a composite Operator 1109df49d7eSJed Brown /// 1119df49d7eSJed Brown /// ``` 1129df49d7eSJed Brown /// # use libceed::prelude::*; 113c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 1149df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 1159df49d7eSJed Brown /// 1169df49d7eSJed Brown /// // Sub operator field arguments 1179df49d7eSJed Brown /// let ne = 3; 1189df49d7eSJed Brown /// let q = 4 as usize; 1199df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 1209df49d7eSJed Brown /// for i in 0..ne { 1219df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 1229df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 1239df49d7eSJed Brown /// } 124c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 1259df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 126c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, 2, 1, q * ne, strides)?; 1279df49d7eSJed Brown /// 128c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1299df49d7eSJed Brown /// 130c68be7a2SJeremy L Thompson /// let qdata_mass = ceed.vector(q * ne)?; 131c68be7a2SJeremy L Thompson /// let qdata_diff = ceed.vector(q * ne)?; 1329df49d7eSJed Brown /// 133c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 1349df49d7eSJed Brown /// let op_mass = ceed 135c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 136c68be7a2SJeremy L Thompson /// .field("u", &r, &b, VectorOpt::Active)? 137c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 138c68be7a2SJeremy L Thompson /// .field("v", &r, &b, VectorOpt::Active)?; 1399df49d7eSJed Brown /// 140c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 1419df49d7eSJed Brown /// let op_diff = ceed 142c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 143c68be7a2SJeremy L Thompson /// .field("du", &r, &b, VectorOpt::Active)? 144c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 145c68be7a2SJeremy L Thompson /// .field("dv", &r, &b, VectorOpt::Active)?; 1469df49d7eSJed Brown /// 1479df49d7eSJed Brown /// let op = ceed 148c68be7a2SJeremy L Thompson /// .composite_operator()? 149c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 150c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 1519df49d7eSJed Brown /// 1529df49d7eSJed Brown /// println!("{}", op); 153c68be7a2SJeremy L Thompson /// # Ok(()) 154c68be7a2SJeremy L Thompson /// # } 1559df49d7eSJed Brown /// ``` 1569df49d7eSJed Brown impl<'a> fmt::Display for CompositeOperator<'a> { 1579df49d7eSJed Brown fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1589df49d7eSJed Brown self.op_core.fmt(f) 1599df49d7eSJed Brown } 1609df49d7eSJed Brown } 1619df49d7eSJed Brown 1629df49d7eSJed Brown // ----------------------------------------------------------------------------- 1639df49d7eSJed Brown // Core functionality 1649df49d7eSJed Brown // ----------------------------------------------------------------------------- 1659df49d7eSJed Brown impl<'a> OperatorCore<'a> { 166*1142270cSJeremy L Thompson // Error handling 167*1142270cSJeremy L Thompson #[doc(hidden)] 168*1142270cSJeremy L Thompson fn check_error(&self, ierr: i32) -> crate::Result<i32> { 169*1142270cSJeremy L Thompson let mut ptr = std::ptr::null_mut(); 170*1142270cSJeremy L Thompson unsafe { 171*1142270cSJeremy L Thompson bind_ceed::CeedOperatorGetCeed(self.ptr, &mut ptr); 172*1142270cSJeremy L Thompson } 173*1142270cSJeremy L Thompson crate::check_error(ptr, ierr) 174*1142270cSJeremy L Thompson } 175*1142270cSJeremy L Thompson 1769df49d7eSJed Brown // Common implementations 1779df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 1789df49d7eSJed Brown let ierr = unsafe { 1799df49d7eSJed Brown bind_ceed::CeedOperatorApply( 1809df49d7eSJed Brown self.ptr, 1819df49d7eSJed Brown input.ptr, 1829df49d7eSJed Brown output.ptr, 1839df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 1849df49d7eSJed Brown ) 1859df49d7eSJed Brown }; 186*1142270cSJeremy L Thompson self.check_error(ierr) 1879df49d7eSJed Brown } 1889df49d7eSJed Brown 1899df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 1909df49d7eSJed Brown let ierr = unsafe { 1919df49d7eSJed Brown bind_ceed::CeedOperatorApplyAdd( 1929df49d7eSJed Brown self.ptr, 1939df49d7eSJed Brown input.ptr, 1949df49d7eSJed Brown output.ptr, 1959df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 1969df49d7eSJed Brown ) 1979df49d7eSJed Brown }; 198*1142270cSJeremy L Thompson self.check_error(ierr) 1999df49d7eSJed Brown } 2009df49d7eSJed Brown 2019df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 2029df49d7eSJed Brown let ierr = unsafe { 2039df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleDiagonal( 2049df49d7eSJed Brown self.ptr, 2059df49d7eSJed Brown assembled.ptr, 2069df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 2079df49d7eSJed Brown ) 2089df49d7eSJed Brown }; 209*1142270cSJeremy L Thompson self.check_error(ierr) 2109df49d7eSJed Brown } 2119df49d7eSJed Brown 2129df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 2139df49d7eSJed Brown let ierr = unsafe { 2149df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddDiagonal( 2159df49d7eSJed Brown self.ptr, 2169df49d7eSJed Brown assembled.ptr, 2179df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 2189df49d7eSJed Brown ) 2199df49d7eSJed Brown }; 220*1142270cSJeremy L Thompson self.check_error(ierr) 2219df49d7eSJed Brown } 2229df49d7eSJed Brown 2239df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 2249df49d7eSJed Brown &self, 2259df49d7eSJed Brown assembled: &mut Vector, 2269df49d7eSJed Brown ) -> crate::Result<i32> { 2279df49d7eSJed Brown let ierr = unsafe { 2289df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssemblePointBlockDiagonal( 2299df49d7eSJed Brown self.ptr, 2309df49d7eSJed Brown assembled.ptr, 2319df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 2329df49d7eSJed Brown ) 2339df49d7eSJed Brown }; 234*1142270cSJeremy L Thompson self.check_error(ierr) 2359df49d7eSJed Brown } 2369df49d7eSJed Brown 2379df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 2389df49d7eSJed Brown &self, 2399df49d7eSJed Brown assembled: &mut Vector, 2409df49d7eSJed Brown ) -> crate::Result<i32> { 2419df49d7eSJed Brown let ierr = unsafe { 2429df49d7eSJed Brown bind_ceed::CeedOperatorLinearAssembleAddPointBlockDiagonal( 2439df49d7eSJed Brown self.ptr, 2449df49d7eSJed Brown assembled.ptr, 2459df49d7eSJed Brown bind_ceed::CEED_REQUEST_IMMEDIATE, 2469df49d7eSJed Brown ) 2479df49d7eSJed Brown }; 248*1142270cSJeremy L Thompson self.check_error(ierr) 2499df49d7eSJed Brown } 2509df49d7eSJed Brown } 2519df49d7eSJed Brown 2529df49d7eSJed Brown // ----------------------------------------------------------------------------- 2539df49d7eSJed Brown // Operator 2549df49d7eSJed Brown // ----------------------------------------------------------------------------- 2559df49d7eSJed Brown impl<'a> Operator<'a> { 2569df49d7eSJed Brown // Constructor 2579df49d7eSJed Brown pub fn create<'b>( 2589df49d7eSJed Brown ceed: &'a crate::Ceed, 2599df49d7eSJed Brown qf: impl Into<QFunctionOpt<'b>>, 2609df49d7eSJed Brown dqf: impl Into<QFunctionOpt<'b>>, 2619df49d7eSJed Brown dqfT: impl Into<QFunctionOpt<'b>>, 2629df49d7eSJed Brown ) -> crate::Result<Self> { 2639df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 2649df49d7eSJed Brown let ierr = unsafe { 2659df49d7eSJed Brown bind_ceed::CeedOperatorCreate( 2669df49d7eSJed Brown ceed.ptr, 2679df49d7eSJed Brown qf.into().to_raw(), 2689df49d7eSJed Brown dqf.into().to_raw(), 2699df49d7eSJed Brown dqfT.into().to_raw(), 2709df49d7eSJed Brown &mut ptr, 2719df49d7eSJed Brown ) 2729df49d7eSJed Brown }; 2739df49d7eSJed Brown ceed.check_error(ierr)?; 2749df49d7eSJed Brown Ok(Self { 275*1142270cSJeremy L Thompson op_core: OperatorCore { 276*1142270cSJeremy L Thompson ptr, 277*1142270cSJeremy L Thompson _lifeline: PhantomData, 278*1142270cSJeremy L Thompson }, 2799df49d7eSJed Brown }) 2809df49d7eSJed Brown } 2819df49d7eSJed Brown 282*1142270cSJeremy L Thompson fn from_raw(ptr: bind_ceed::CeedOperator) -> crate::Result<Self> { 2839df49d7eSJed Brown Ok(Self { 284*1142270cSJeremy L Thompson op_core: OperatorCore { 285*1142270cSJeremy L Thompson ptr, 286*1142270cSJeremy L Thompson _lifeline: PhantomData, 287*1142270cSJeremy L Thompson }, 2889df49d7eSJed Brown }) 2899df49d7eSJed Brown } 2909df49d7eSJed Brown 2919df49d7eSJed Brown /// Apply Operator to a vector 2929df49d7eSJed Brown /// 2939df49d7eSJed Brown /// * `input` - Input Vector 2949df49d7eSJed Brown /// * `output` - Output Vector 2959df49d7eSJed Brown /// 2969df49d7eSJed Brown /// ``` 2979df49d7eSJed Brown /// # use libceed::prelude::*; 298c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 2999df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 3009df49d7eSJed Brown /// let ne = 4; 3019df49d7eSJed Brown /// let p = 3; 3029df49d7eSJed Brown /// let q = 4; 3039df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 3049df49d7eSJed Brown /// 3059df49d7eSJed Brown /// // Vectors 306c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 307c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 3089df49d7eSJed Brown /// qdata.set_value(0.0); 309c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 310c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 3119df49d7eSJed Brown /// v.set_value(0.0); 3129df49d7eSJed Brown /// 3139df49d7eSJed Brown /// // Restrictions 3149df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 3159df49d7eSJed Brown /// for i in 0..ne { 3169df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 3179df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 3189df49d7eSJed Brown /// } 319c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 3209df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 3219df49d7eSJed Brown /// for i in 0..ne { 3229df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 3239df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 3249df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 3259df49d7eSJed Brown /// } 326c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 3279df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 328c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 3299df49d7eSJed Brown /// 3309df49d7eSJed Brown /// // Bases 331c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 332c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 3339df49d7eSJed Brown /// 3349df49d7eSJed Brown /// // Build quadrature data 335c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 336c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 337c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 338c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 339c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 340c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 3419df49d7eSJed Brown /// 3429df49d7eSJed Brown /// // Mass operator 343c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 3449df49d7eSJed Brown /// let op_mass = ceed 345c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 346c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 347c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 348c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 3499df49d7eSJed Brown /// 3509df49d7eSJed Brown /// v.set_value(0.0); 351c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 3529df49d7eSJed Brown /// 3539df49d7eSJed Brown /// // Check 35480a9ef05SNatalie Beams /// let sum: Scalar = v.view().iter().sum(); 3559df49d7eSJed Brown /// assert!( 35680a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 3579df49d7eSJed Brown /// "Incorrect interval length computed" 3589df49d7eSJed Brown /// ); 359c68be7a2SJeremy L Thompson /// # Ok(()) 360c68be7a2SJeremy L Thompson /// # } 3619df49d7eSJed Brown /// ``` 3629df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 3639df49d7eSJed Brown self.op_core.apply(input, output) 3649df49d7eSJed Brown } 3659df49d7eSJed Brown 3669df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 3679df49d7eSJed Brown /// 3689df49d7eSJed Brown /// * `input` - Input Vector 3699df49d7eSJed Brown /// * `output` - Output Vector 3709df49d7eSJed Brown /// 3719df49d7eSJed Brown /// ``` 3729df49d7eSJed Brown /// # use libceed::prelude::*; 373c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 3749df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 3759df49d7eSJed Brown /// let ne = 4; 3769df49d7eSJed Brown /// let p = 3; 3779df49d7eSJed Brown /// let q = 4; 3789df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 3799df49d7eSJed Brown /// 3809df49d7eSJed Brown /// // Vectors 381c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 382c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 3839df49d7eSJed Brown /// qdata.set_value(0.0); 384c68be7a2SJeremy L Thompson /// let u = ceed.vector_from_slice(&vec![1.0; ndofs])?; 385c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 3869df49d7eSJed Brown /// 3879df49d7eSJed Brown /// // Restrictions 3889df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 3899df49d7eSJed Brown /// for i in 0..ne { 3909df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 3919df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 3929df49d7eSJed Brown /// } 393c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 3949df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 3959df49d7eSJed Brown /// for i in 0..ne { 3969df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 3979df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 3989df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 3999df49d7eSJed Brown /// } 400c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 4019df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 402c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 4039df49d7eSJed Brown /// 4049df49d7eSJed Brown /// // Bases 405c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 406c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 4079df49d7eSJed Brown /// 4089df49d7eSJed Brown /// // Build quadrature data 409c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 410c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 411c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 412c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 413c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 414c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 4159df49d7eSJed Brown /// 4169df49d7eSJed Brown /// // Mass operator 417c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 4189df49d7eSJed Brown /// let op_mass = ceed 419c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 420c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 421c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 422c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 4239df49d7eSJed Brown /// 4249df49d7eSJed Brown /// v.set_value(1.0); 425c68be7a2SJeremy L Thompson /// op_mass.apply_add(&u, &mut v)?; 4269df49d7eSJed Brown /// 4279df49d7eSJed Brown /// // Check 42880a9ef05SNatalie Beams /// let sum: Scalar = v.view().iter().sum(); 4299df49d7eSJed Brown /// assert!( 43080a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 4319df49d7eSJed Brown /// "Incorrect interval length computed and added" 4329df49d7eSJed Brown /// ); 433c68be7a2SJeremy L Thompson /// # Ok(()) 434c68be7a2SJeremy L Thompson /// # } 4359df49d7eSJed Brown /// ``` 4369df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 4379df49d7eSJed Brown self.op_core.apply_add(input, output) 4389df49d7eSJed Brown } 4399df49d7eSJed Brown 4409df49d7eSJed Brown /// Provide a field to a Operator for use by its QFunction 4419df49d7eSJed Brown /// 4429df49d7eSJed Brown /// * `fieldname` - Name of the field (to be matched with the name used by 4439df49d7eSJed Brown /// the QFunction) 4449df49d7eSJed Brown /// * `r` - ElemRestriction 4459df49d7eSJed Brown /// * `b` - Basis in which the field resides or `BasisCollocated` if 4469df49d7eSJed Brown /// collocated with quadrature points 4479df49d7eSJed Brown /// * `v` - Vector to be used by Operator or `VectorActive` if field 4489df49d7eSJed Brown /// is active or `VectorNone` if using `Weight` with the 4499df49d7eSJed Brown /// QFunction 4509df49d7eSJed Brown /// 4519df49d7eSJed Brown /// 4529df49d7eSJed Brown /// ``` 4539df49d7eSJed Brown /// # use libceed::prelude::*; 454c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 4559df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 456c68be7a2SJeremy L Thompson /// let qf = ceed.q_function_interior_by_name("Mass1DBuild")?; 457c68be7a2SJeremy L Thompson /// let mut op = ceed.operator(&qf, QFunctionOpt::None, QFunctionOpt::None)?; 4589df49d7eSJed Brown /// 4599df49d7eSJed Brown /// // Operator field arguments 4609df49d7eSJed Brown /// let ne = 3; 4619df49d7eSJed Brown /// let q = 4; 4629df49d7eSJed Brown /// let mut ind: Vec<i32> = vec![0; 2 * ne]; 4639df49d7eSJed Brown /// for i in 0..ne { 4649df49d7eSJed Brown /// ind[2 * i + 0] = i as i32; 4659df49d7eSJed Brown /// ind[2 * i + 1] = (i + 1) as i32; 4669df49d7eSJed Brown /// } 467c68be7a2SJeremy L Thompson /// let r = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &ind)?; 4689df49d7eSJed Brown /// 469c68be7a2SJeremy L Thompson /// let b = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 4709df49d7eSJed Brown /// 4719df49d7eSJed Brown /// // Operator field 472c68be7a2SJeremy L Thompson /// op = op.field("dx", &r, &b, VectorOpt::Active)?; 473c68be7a2SJeremy L Thompson /// # Ok(()) 474c68be7a2SJeremy L Thompson /// # } 4759df49d7eSJed Brown /// ``` 4769df49d7eSJed Brown #[allow(unused_mut)] 4779df49d7eSJed Brown pub fn field<'b>( 4789df49d7eSJed Brown mut self, 4799df49d7eSJed Brown fieldname: &str, 4809df49d7eSJed Brown r: impl Into<ElemRestrictionOpt<'b>>, 4819df49d7eSJed Brown b: impl Into<BasisOpt<'b>>, 4829df49d7eSJed Brown v: impl Into<VectorOpt<'b>>, 4839df49d7eSJed Brown ) -> crate::Result<Self> { 4849df49d7eSJed Brown let fieldname = CString::new(fieldname).expect("CString::new failed"); 4859df49d7eSJed Brown let fieldname = fieldname.as_ptr() as *const i8; 4869df49d7eSJed Brown let ierr = unsafe { 4879df49d7eSJed Brown bind_ceed::CeedOperatorSetField( 4889df49d7eSJed Brown self.op_core.ptr, 4899df49d7eSJed Brown fieldname, 4909df49d7eSJed Brown r.into().to_raw(), 4919df49d7eSJed Brown b.into().to_raw(), 4929df49d7eSJed Brown v.into().to_raw(), 4939df49d7eSJed Brown ) 4949df49d7eSJed Brown }; 495*1142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 4969df49d7eSJed Brown Ok(self) 4979df49d7eSJed Brown } 4989df49d7eSJed Brown 4999df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 5009df49d7eSJed Brown /// 5019df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 5029df49d7eSJed Brown /// 5039df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 5049df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 5059df49d7eSJed Brown /// 5069df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 5079df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 5089df49d7eSJed Brown /// 5099df49d7eSJed Brown /// ``` 5109df49d7eSJed Brown /// # use libceed::prelude::*; 511c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 5129df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 5139df49d7eSJed Brown /// let ne = 4; 5149df49d7eSJed Brown /// let p = 3; 5159df49d7eSJed Brown /// let q = 4; 5169df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 5179df49d7eSJed Brown /// 5189df49d7eSJed Brown /// // Vectors 519c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 520c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 5219df49d7eSJed Brown /// qdata.set_value(0.0); 522c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 5239df49d7eSJed Brown /// u.set_value(1.0); 524c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 5259df49d7eSJed Brown /// v.set_value(0.0); 5269df49d7eSJed Brown /// 5279df49d7eSJed Brown /// // Restrictions 5289df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 5299df49d7eSJed Brown /// for i in 0..ne { 5309df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 5319df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 5329df49d7eSJed Brown /// } 533c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 5349df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 5359df49d7eSJed Brown /// for i in 0..ne { 5369df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 5379df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 5389df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 5399df49d7eSJed Brown /// } 540c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 5419df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 542c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 5439df49d7eSJed Brown /// 5449df49d7eSJed Brown /// // Bases 545c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 546c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 5479df49d7eSJed Brown /// 5489df49d7eSJed Brown /// // Build quadrature data 549c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 550c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 551c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 552c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 553c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 554c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 5559df49d7eSJed Brown /// 5569df49d7eSJed Brown /// // Mass operator 557c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 5589df49d7eSJed Brown /// let op_mass = ceed 559c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 560c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 561c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 562c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 5639df49d7eSJed Brown /// 5649df49d7eSJed Brown /// // Diagonal 565c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 5669df49d7eSJed Brown /// diag.set_value(0.0); 567c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_diagonal(&mut diag)?; 5689df49d7eSJed Brown /// 5699df49d7eSJed Brown /// // Manual diagonal computation 570c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 5719df49d7eSJed Brown /// for i in 0..ndofs { 5729df49d7eSJed Brown /// u.set_value(0.0); 5739df49d7eSJed Brown /// { 5749df49d7eSJed Brown /// let mut u_array = u.view_mut(); 5759df49d7eSJed Brown /// u_array[i] = 1.; 5769df49d7eSJed Brown /// } 5779df49d7eSJed Brown /// 578c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 5799df49d7eSJed Brown /// 5809df49d7eSJed Brown /// { 5819df49d7eSJed Brown /// let v_array = v.view_mut(); 5829df49d7eSJed Brown /// let mut true_array = true_diag.view_mut(); 5839df49d7eSJed Brown /// true_array[i] = v_array[i]; 5849df49d7eSJed Brown /// } 5859df49d7eSJed Brown /// } 5869df49d7eSJed Brown /// 5879df49d7eSJed Brown /// // Check 5889df49d7eSJed Brown /// diag.view() 5899df49d7eSJed Brown /// .iter() 5909df49d7eSJed Brown /// .zip(true_diag.view().iter()) 5919df49d7eSJed Brown /// .for_each(|(computed, actual)| { 5929df49d7eSJed Brown /// assert!( 59380a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 5949df49d7eSJed Brown /// "Diagonal entry incorrect" 5959df49d7eSJed Brown /// ); 5969df49d7eSJed Brown /// }); 597c68be7a2SJeremy L Thompson /// # Ok(()) 598c68be7a2SJeremy L Thompson /// # } 5999df49d7eSJed Brown /// ``` 6009df49d7eSJed Brown pub fn linear_assemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 6019df49d7eSJed Brown self.op_core.linear_assemble_diagonal(assembled) 6029df49d7eSJed Brown } 6039df49d7eSJed Brown 6049df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 6059df49d7eSJed Brown /// 6069df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 6079df49d7eSJed Brown /// 6089df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 6099df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 6109df49d7eSJed Brown /// 6119df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 6129df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 6139df49d7eSJed Brown /// 6149df49d7eSJed Brown /// 6159df49d7eSJed Brown /// ``` 6169df49d7eSJed Brown /// # use libceed::prelude::*; 617c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 6189df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 6199df49d7eSJed Brown /// let ne = 4; 6209df49d7eSJed Brown /// let p = 3; 6219df49d7eSJed Brown /// let q = 4; 6229df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 6239df49d7eSJed Brown /// 6249df49d7eSJed Brown /// // Vectors 625c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 626c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 6279df49d7eSJed Brown /// qdata.set_value(0.0); 628c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 6299df49d7eSJed Brown /// u.set_value(1.0); 630c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 6319df49d7eSJed Brown /// v.set_value(0.0); 6329df49d7eSJed Brown /// 6339df49d7eSJed Brown /// // Restrictions 6349df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 6359df49d7eSJed Brown /// for i in 0..ne { 6369df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 6379df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 6389df49d7eSJed Brown /// } 639c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 6409df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 6419df49d7eSJed Brown /// for i in 0..ne { 6429df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 6439df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 6449df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 6459df49d7eSJed Brown /// } 646c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, 1, 1, ndofs, MemType::Host, &indu)?; 6479df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 648c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 6499df49d7eSJed Brown /// 6509df49d7eSJed Brown /// // Bases 651c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 652c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 6539df49d7eSJed Brown /// 6549df49d7eSJed Brown /// // Build quadrature data 655c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 656c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 657c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 658c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 659c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 660c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 6619df49d7eSJed Brown /// 6629df49d7eSJed Brown /// // Mass operator 663c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 6649df49d7eSJed Brown /// let op_mass = ceed 665c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 666c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 667c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 668c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 6699df49d7eSJed Brown /// 6709df49d7eSJed Brown /// // Diagonal 671c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ndofs)?; 6729df49d7eSJed Brown /// diag.set_value(1.0); 673c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_diagonal(&mut diag)?; 6749df49d7eSJed Brown /// 6759df49d7eSJed Brown /// // Manual diagonal computation 676c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ndofs)?; 6779df49d7eSJed Brown /// for i in 0..ndofs { 6789df49d7eSJed Brown /// u.set_value(0.0); 6799df49d7eSJed Brown /// { 6809df49d7eSJed Brown /// let mut u_array = u.view_mut(); 6819df49d7eSJed Brown /// u_array[i] = 1.; 6829df49d7eSJed Brown /// } 6839df49d7eSJed Brown /// 684c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 6859df49d7eSJed Brown /// 6869df49d7eSJed Brown /// { 6879df49d7eSJed Brown /// let v_array = v.view_mut(); 6889df49d7eSJed Brown /// let mut true_array = true_diag.view_mut(); 6899df49d7eSJed Brown /// true_array[i] = v_array[i] + 1.0; 6909df49d7eSJed Brown /// } 6919df49d7eSJed Brown /// } 6929df49d7eSJed Brown /// 6939df49d7eSJed Brown /// // Check 6949df49d7eSJed Brown /// diag.view() 6959df49d7eSJed Brown /// .iter() 6969df49d7eSJed Brown /// .zip(true_diag.view().iter()) 6979df49d7eSJed Brown /// .for_each(|(computed, actual)| { 6989df49d7eSJed Brown /// assert!( 69980a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 7009df49d7eSJed Brown /// "Diagonal entry incorrect" 7019df49d7eSJed Brown /// ); 7029df49d7eSJed Brown /// }); 703c68be7a2SJeremy L Thompson /// # Ok(()) 704c68be7a2SJeremy L Thompson /// # } 7059df49d7eSJed Brown /// ``` 7069df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 7079df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 7089df49d7eSJed Brown } 7099df49d7eSJed Brown 7109df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 7119df49d7eSJed Brown /// 7129df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 7139df49d7eSJed Brown /// Operator. 7149df49d7eSJed Brown /// 7159df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 7169df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 7179df49d7eSJed Brown /// 7189df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 7199df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 7209df49d7eSJed Brown /// diagonal, provided in row-major form with an 7219df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 7229df49d7eSJed Brown /// this vector are derived from the active vector for 7239df49d7eSJed Brown /// the CeedOperator. The array has shape 7249df49d7eSJed Brown /// `[nodes, component out, component in]`. 7259df49d7eSJed Brown /// 7269df49d7eSJed Brown /// ``` 7279df49d7eSJed Brown /// # use libceed::prelude::*; 728c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 7299df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 7309df49d7eSJed Brown /// let ne = 4; 7319df49d7eSJed Brown /// let p = 3; 7329df49d7eSJed Brown /// let q = 4; 7339df49d7eSJed Brown /// let ncomp = 2; 7349df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 7359df49d7eSJed Brown /// 7369df49d7eSJed Brown /// // Vectors 737c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 738c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 7399df49d7eSJed Brown /// qdata.set_value(0.0); 740c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 7419df49d7eSJed Brown /// u.set_value(1.0); 742c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 7439df49d7eSJed Brown /// v.set_value(0.0); 7449df49d7eSJed Brown /// 7459df49d7eSJed Brown /// // Restrictions 7469df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 7479df49d7eSJed Brown /// for i in 0..ne { 7489df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 7499df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 7509df49d7eSJed Brown /// } 751c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 7529df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 7539df49d7eSJed Brown /// for i in 0..ne { 7549df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 7559df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 7569df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 7579df49d7eSJed Brown /// } 758c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 7599df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 760c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 7619df49d7eSJed Brown /// 7629df49d7eSJed Brown /// // Bases 763c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 764c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 7659df49d7eSJed Brown /// 7669df49d7eSJed Brown /// // Build quadrature data 767c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 768c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 769c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 770c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 771c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 772c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 7739df49d7eSJed Brown /// 7749df49d7eSJed Brown /// // Mass operator 7759df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 7769df49d7eSJed Brown /// // Number of quadrature points 7779df49d7eSJed Brown /// let q = qdata.len(); 7789df49d7eSJed Brown /// 7799df49d7eSJed Brown /// // Iterate over quadrature points 7809df49d7eSJed Brown /// for i in 0..q { 7819df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 7829df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 7839df49d7eSJed Brown /// } 7849df49d7eSJed Brown /// 7859df49d7eSJed Brown /// // Return clean error code 7869df49d7eSJed Brown /// 0 7879df49d7eSJed Brown /// }; 7889df49d7eSJed Brown /// 7899df49d7eSJed Brown /// let qf_mass = ceed 790c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 791c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 792c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 793c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 7949df49d7eSJed Brown /// 7959df49d7eSJed Brown /// let op_mass = ceed 796c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 797c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 798c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 799c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 8009df49d7eSJed Brown /// 8019df49d7eSJed Brown /// // Diagonal 802c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 8039df49d7eSJed Brown /// diag.set_value(0.0); 804c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_point_block_diagonal(&mut diag)?; 8059df49d7eSJed Brown /// 8069df49d7eSJed Brown /// // Manual diagonal computation 807c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 8089df49d7eSJed Brown /// for i in 0..ndofs { 8099df49d7eSJed Brown /// for j in 0..ncomp { 8109df49d7eSJed Brown /// u.set_value(0.0); 8119df49d7eSJed Brown /// { 8129df49d7eSJed Brown /// let mut u_array = u.view_mut(); 8139df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 8149df49d7eSJed Brown /// } 8159df49d7eSJed Brown /// 816c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 8179df49d7eSJed Brown /// 8189df49d7eSJed Brown /// { 8199df49d7eSJed Brown /// let v_array = v.view_mut(); 8209df49d7eSJed Brown /// let mut true_array = true_diag.view_mut(); 8219df49d7eSJed Brown /// for k in 0..ncomp { 8229df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 8239df49d7eSJed Brown /// } 8249df49d7eSJed Brown /// } 8259df49d7eSJed Brown /// } 8269df49d7eSJed Brown /// } 8279df49d7eSJed Brown /// 8289df49d7eSJed Brown /// // Check 8299df49d7eSJed Brown /// diag.view() 8309df49d7eSJed Brown /// .iter() 8319df49d7eSJed Brown /// .zip(true_diag.view().iter()) 8329df49d7eSJed Brown /// .for_each(|(computed, actual)| { 8339df49d7eSJed Brown /// assert!( 83480a9ef05SNatalie Beams /// (*computed - *actual).abs() < 10.0 * libceed::EPSILON, 8359df49d7eSJed Brown /// "Diagonal entry incorrect" 8369df49d7eSJed Brown /// ); 8379df49d7eSJed Brown /// }); 838c68be7a2SJeremy L Thompson /// # Ok(()) 839c68be7a2SJeremy L Thompson /// # } 8409df49d7eSJed Brown /// ``` 8419df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 8429df49d7eSJed Brown &self, 8439df49d7eSJed Brown assembled: &mut Vector, 8449df49d7eSJed Brown ) -> crate::Result<i32> { 8459df49d7eSJed Brown self.op_core.linear_assemble_point_block_diagonal(assembled) 8469df49d7eSJed Brown } 8479df49d7eSJed Brown 8489df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 8499df49d7eSJed Brown /// 8509df49d7eSJed Brown /// This sums into a Vector with the point block diagonal of a linear 8519df49d7eSJed Brown /// Operator. 8529df49d7eSJed Brown /// 8539df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 8549df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 8559df49d7eSJed Brown /// 8569df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 8579df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 8589df49d7eSJed Brown /// diagonal, provided in row-major form with an 8599df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 8609df49d7eSJed Brown /// this vector are derived from the active vector for 8619df49d7eSJed Brown /// the CeedOperator. The array has shape 8629df49d7eSJed Brown /// `[nodes, component out, component in]`. 8639df49d7eSJed Brown /// 8649df49d7eSJed Brown /// ``` 8659df49d7eSJed Brown /// # use libceed::prelude::*; 866c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 8679df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 8689df49d7eSJed Brown /// let ne = 4; 8699df49d7eSJed Brown /// let p = 3; 8709df49d7eSJed Brown /// let q = 4; 8719df49d7eSJed Brown /// let ncomp = 2; 8729df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 8739df49d7eSJed Brown /// 8749df49d7eSJed Brown /// // Vectors 875c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 876c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 8779df49d7eSJed Brown /// qdata.set_value(0.0); 878c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ncomp * ndofs)?; 8799df49d7eSJed Brown /// u.set_value(1.0); 880c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ncomp * ndofs)?; 8819df49d7eSJed Brown /// v.set_value(0.0); 8829df49d7eSJed Brown /// 8839df49d7eSJed Brown /// // Restrictions 8849df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 8859df49d7eSJed Brown /// for i in 0..ne { 8869df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 8879df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 8889df49d7eSJed Brown /// } 889c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 8909df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 8919df49d7eSJed Brown /// for i in 0..ne { 8929df49d7eSJed Brown /// indu[p * i + 0] = (2 * i) as i32; 8939df49d7eSJed Brown /// indu[p * i + 1] = (2 * i + 1) as i32; 8949df49d7eSJed Brown /// indu[p * i + 2] = (2 * i + 2) as i32; 8959df49d7eSJed Brown /// } 896c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, p, ncomp, ndofs, ncomp * ndofs, MemType::Host, &indu)?; 8979df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 898c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 8999df49d7eSJed Brown /// 9009df49d7eSJed Brown /// // Bases 901c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 902c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, ncomp, p, q, QuadMode::Gauss)?; 9039df49d7eSJed Brown /// 9049df49d7eSJed Brown /// // Build quadrature data 905c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 906c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 907c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 908c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 909c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 910c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 9119df49d7eSJed Brown /// 9129df49d7eSJed Brown /// // Mass operator 9139df49d7eSJed Brown /// let mut mass_2_comp = |[u, qdata, ..]: QFunctionInputs, [v, ..]: QFunctionOutputs| { 9149df49d7eSJed Brown /// // Number of quadrature points 9159df49d7eSJed Brown /// let q = qdata.len(); 9169df49d7eSJed Brown /// 9179df49d7eSJed Brown /// // Iterate over quadrature points 9189df49d7eSJed Brown /// for i in 0..q { 9199df49d7eSJed Brown /// v[i + 0 * q] = u[i + 1 * q] * qdata[i]; 9209df49d7eSJed Brown /// v[i + 1 * q] = u[i + 0 * q] * qdata[i]; 9219df49d7eSJed Brown /// } 9229df49d7eSJed Brown /// 9239df49d7eSJed Brown /// // Return clean error code 9249df49d7eSJed Brown /// 0 9259df49d7eSJed Brown /// }; 9269df49d7eSJed Brown /// 9279df49d7eSJed Brown /// let qf_mass = ceed 928c68be7a2SJeremy L Thompson /// .q_function_interior(1, Box::new(mass_2_comp))? 929c68be7a2SJeremy L Thompson /// .input("u", 2, EvalMode::Interp)? 930c68be7a2SJeremy L Thompson /// .input("qdata", 1, EvalMode::None)? 931c68be7a2SJeremy L Thompson /// .output("v", 2, EvalMode::Interp)?; 9329df49d7eSJed Brown /// 9339df49d7eSJed Brown /// let op_mass = ceed 934c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 935c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 936c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 937c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 9389df49d7eSJed Brown /// 9399df49d7eSJed Brown /// // Diagonal 940c68be7a2SJeremy L Thompson /// let mut diag = ceed.vector(ncomp * ncomp * ndofs)?; 9419df49d7eSJed Brown /// diag.set_value(1.0); 942c68be7a2SJeremy L Thompson /// op_mass.linear_assemble_add_point_block_diagonal(&mut diag)?; 9439df49d7eSJed Brown /// 9449df49d7eSJed Brown /// // Manual diagonal computation 945c68be7a2SJeremy L Thompson /// let mut true_diag = ceed.vector(ncomp * ncomp * ndofs)?; 9469df49d7eSJed Brown /// for i in 0..ndofs { 9479df49d7eSJed Brown /// for j in 0..ncomp { 9489df49d7eSJed Brown /// u.set_value(0.0); 9499df49d7eSJed Brown /// { 9509df49d7eSJed Brown /// let mut u_array = u.view_mut(); 9519df49d7eSJed Brown /// u_array[i + j * ndofs] = 1.; 9529df49d7eSJed Brown /// } 9539df49d7eSJed Brown /// 954c68be7a2SJeremy L Thompson /// op_mass.apply(&u, &mut v)?; 9559df49d7eSJed Brown /// 9569df49d7eSJed Brown /// { 9579df49d7eSJed Brown /// let v_array = v.view_mut(); 9589df49d7eSJed Brown /// let mut true_array = true_diag.view_mut(); 9599df49d7eSJed Brown /// for k in 0..ncomp { 9609df49d7eSJed Brown /// true_array[i * ncomp * ncomp + k * ncomp + j] = v_array[i + k * ndofs]; 9619df49d7eSJed Brown /// } 9629df49d7eSJed Brown /// } 9639df49d7eSJed Brown /// } 9649df49d7eSJed Brown /// } 9659df49d7eSJed Brown /// 9669df49d7eSJed Brown /// // Check 9679df49d7eSJed Brown /// diag.view() 9689df49d7eSJed Brown /// .iter() 9699df49d7eSJed Brown /// .zip(true_diag.view().iter()) 9709df49d7eSJed Brown /// .for_each(|(computed, actual)| { 9719df49d7eSJed Brown /// assert!( 97280a9ef05SNatalie Beams /// (*computed - 1.0 - *actual).abs() < 10.0 * libceed::EPSILON, 9739df49d7eSJed Brown /// "Diagonal entry incorrect" 9749df49d7eSJed Brown /// ); 9759df49d7eSJed Brown /// }); 976c68be7a2SJeremy L Thompson /// # Ok(()) 977c68be7a2SJeremy L Thompson /// # } 9789df49d7eSJed Brown /// ``` 9799df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 9809df49d7eSJed Brown &self, 9819df49d7eSJed Brown assembled: &mut Vector, 9829df49d7eSJed Brown ) -> crate::Result<i32> { 9839df49d7eSJed Brown self.op_core 9849df49d7eSJed Brown .linear_assemble_add_point_block_diagonal(assembled) 9859df49d7eSJed Brown } 9869df49d7eSJed Brown 9879df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 9889df49d7eSJed Brown /// given Operator, creating the prolongation basis from the fine and 9899df49d7eSJed Brown /// coarse grid interpolation 9909df49d7eSJed Brown /// 9919df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 9929df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 9939df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 9949df49d7eSJed Brown /// 9959df49d7eSJed Brown /// ``` 9969df49d7eSJed Brown /// # use libceed::prelude::*; 997c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 9989df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 9999df49d7eSJed Brown /// let ne = 15; 10009df49d7eSJed Brown /// let p_coarse = 3; 10019df49d7eSJed Brown /// let p_fine = 5; 10029df49d7eSJed Brown /// let q = 6; 10039df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 10049df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 10059df49d7eSJed Brown /// 10069df49d7eSJed Brown /// // Vectors 10079df49d7eSJed Brown /// let x_array = (0..ne + 1) 100880a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 100980a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1010c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1011c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 10129df49d7eSJed Brown /// qdata.set_value(0.0); 1013c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 10149df49d7eSJed Brown /// u_coarse.set_value(1.0); 1015c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 10169df49d7eSJed Brown /// u_fine.set_value(1.0); 1017c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 10189df49d7eSJed Brown /// v_coarse.set_value(0.0); 1019c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 10209df49d7eSJed Brown /// v_fine.set_value(0.0); 1021c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 10229df49d7eSJed Brown /// multiplicity.set_value(1.0); 10239df49d7eSJed Brown /// 10249df49d7eSJed Brown /// // Restrictions 10259df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1026c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 10279df49d7eSJed Brown /// 10289df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 10299df49d7eSJed Brown /// for i in 0..ne { 10309df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 10319df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 10329df49d7eSJed Brown /// } 1033c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 10349df49d7eSJed Brown /// 10359df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 10369df49d7eSJed Brown /// for i in 0..ne { 10379df49d7eSJed Brown /// for j in 0..p_coarse { 10389df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 10399df49d7eSJed Brown /// } 10409df49d7eSJed Brown /// } 1041c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 10429df49d7eSJed Brown /// ne, 10439df49d7eSJed Brown /// p_coarse, 10449df49d7eSJed Brown /// 1, 10459df49d7eSJed Brown /// 1, 10469df49d7eSJed Brown /// ndofs_coarse, 10479df49d7eSJed Brown /// MemType::Host, 10489df49d7eSJed Brown /// &indu_coarse, 1049c68be7a2SJeremy L Thompson /// )?; 10509df49d7eSJed Brown /// 10519df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 10529df49d7eSJed Brown /// for i in 0..ne { 10539df49d7eSJed Brown /// for j in 0..p_fine { 10549df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 10559df49d7eSJed Brown /// } 10569df49d7eSJed Brown /// } 1057c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 10589df49d7eSJed Brown /// 10599df49d7eSJed Brown /// // Bases 1060c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1061c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1062c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 10639df49d7eSJed Brown /// 10649df49d7eSJed Brown /// // Build quadrature data 1065c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1066c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1067c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1068c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1069c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1070c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 10719df49d7eSJed Brown /// 10729df49d7eSJed Brown /// // Mass operator 1073c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 10749df49d7eSJed Brown /// let op_mass_fine = ceed 1075c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1076c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1077c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1078c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 10799df49d7eSJed Brown /// 10809df49d7eSJed Brown /// // Multigrid setup 1081c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = 1082c68be7a2SJeremy L Thompson /// op_mass_fine.create_multigrid_level(&multiplicity, &ru_coarse, &bu_coarse)?; 10839df49d7eSJed Brown /// 10849df49d7eSJed Brown /// // Coarse problem 10859df49d7eSJed Brown /// u_coarse.set_value(1.0); 1086c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 10879df49d7eSJed Brown /// 10889df49d7eSJed Brown /// // Check 108980a9ef05SNatalie Beams /// let sum: Scalar = v_coarse.view().iter().sum(); 10909df49d7eSJed Brown /// assert!( 109180a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 10929df49d7eSJed Brown /// "Incorrect interval length computed" 10939df49d7eSJed Brown /// ); 10949df49d7eSJed Brown /// 10959df49d7eSJed Brown /// // Prolong 1096c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 10979df49d7eSJed Brown /// 10989df49d7eSJed Brown /// // Fine problem 1099c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 11009df49d7eSJed Brown /// 11019df49d7eSJed Brown /// // Check 110280a9ef05SNatalie Beams /// let sum: Scalar = v_fine.view().iter().sum(); 11039df49d7eSJed Brown /// assert!( 110480a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 11059df49d7eSJed Brown /// "Incorrect interval length computed" 11069df49d7eSJed Brown /// ); 11079df49d7eSJed Brown /// 11089df49d7eSJed Brown /// // Restrict 1109c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 11109df49d7eSJed Brown /// 11119df49d7eSJed Brown /// // Check 111280a9ef05SNatalie Beams /// let sum: Scalar = v_coarse.view().iter().sum(); 11139df49d7eSJed Brown /// assert!( 111480a9ef05SNatalie Beams /// (sum - 2.0).abs() < 50.0 * libceed::EPSILON, 11159df49d7eSJed Brown /// "Incorrect interval length computed" 11169df49d7eSJed Brown /// ); 1117c68be7a2SJeremy L Thompson /// # Ok(()) 1118c68be7a2SJeremy L Thompson /// # } 11199df49d7eSJed Brown /// ``` 11209df49d7eSJed Brown pub fn create_multigrid_level( 11219df49d7eSJed Brown &self, 11229df49d7eSJed Brown p_mult_fine: &Vector, 11239df49d7eSJed Brown rstr_coarse: &ElemRestriction, 11249df49d7eSJed Brown basis_coarse: &Basis, 11259df49d7eSJed Brown ) -> crate::Result<(Operator, Operator, Operator)> { 11269df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 11279df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 11289df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 11299df49d7eSJed Brown let ierr = unsafe { 11309df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreate( 11319df49d7eSJed Brown self.op_core.ptr, 11329df49d7eSJed Brown p_mult_fine.ptr, 11339df49d7eSJed Brown rstr_coarse.ptr, 11349df49d7eSJed Brown basis_coarse.ptr, 11359df49d7eSJed Brown &mut ptr_coarse, 11369df49d7eSJed Brown &mut ptr_prolong, 11379df49d7eSJed Brown &mut ptr_restrict, 11389df49d7eSJed Brown ) 11399df49d7eSJed Brown }; 1140*1142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 1141*1142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 1142*1142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 1143*1142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 11449df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 11459df49d7eSJed Brown } 11469df49d7eSJed Brown 11479df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 11489df49d7eSJed Brown /// given Operator with a tensor basis for the active basis 11499df49d7eSJed Brown /// 11509df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 11519df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 11529df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 11539df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 11549df49d7eSJed Brown /// 11559df49d7eSJed Brown /// ``` 11569df49d7eSJed Brown /// # use libceed::prelude::*; 1157c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 11589df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 11599df49d7eSJed Brown /// let ne = 15; 11609df49d7eSJed Brown /// let p_coarse = 3; 11619df49d7eSJed Brown /// let p_fine = 5; 11629df49d7eSJed Brown /// let q = 6; 11639df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 11649df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 11659df49d7eSJed Brown /// 11669df49d7eSJed Brown /// // Vectors 11679df49d7eSJed Brown /// let x_array = (0..ne + 1) 116880a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 116980a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1170c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1171c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 11729df49d7eSJed Brown /// qdata.set_value(0.0); 1173c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 11749df49d7eSJed Brown /// u_coarse.set_value(1.0); 1175c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 11769df49d7eSJed Brown /// u_fine.set_value(1.0); 1177c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 11789df49d7eSJed Brown /// v_coarse.set_value(0.0); 1179c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 11809df49d7eSJed Brown /// v_fine.set_value(0.0); 1181c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 11829df49d7eSJed Brown /// multiplicity.set_value(1.0); 11839df49d7eSJed Brown /// 11849df49d7eSJed Brown /// // Restrictions 11859df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1186c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 11879df49d7eSJed Brown /// 11889df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 11899df49d7eSJed Brown /// for i in 0..ne { 11909df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 11919df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 11929df49d7eSJed Brown /// } 1193c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 11949df49d7eSJed Brown /// 11959df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 11969df49d7eSJed Brown /// for i in 0..ne { 11979df49d7eSJed Brown /// for j in 0..p_coarse { 11989df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 11999df49d7eSJed Brown /// } 12009df49d7eSJed Brown /// } 1201c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 12029df49d7eSJed Brown /// ne, 12039df49d7eSJed Brown /// p_coarse, 12049df49d7eSJed Brown /// 1, 12059df49d7eSJed Brown /// 1, 12069df49d7eSJed Brown /// ndofs_coarse, 12079df49d7eSJed Brown /// MemType::Host, 12089df49d7eSJed Brown /// &indu_coarse, 1209c68be7a2SJeremy L Thompson /// )?; 12109df49d7eSJed Brown /// 12119df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 12129df49d7eSJed Brown /// for i in 0..ne { 12139df49d7eSJed Brown /// for j in 0..p_fine { 12149df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 12159df49d7eSJed Brown /// } 12169df49d7eSJed Brown /// } 1217c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 12189df49d7eSJed Brown /// 12199df49d7eSJed Brown /// // Bases 1220c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1221c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1222c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 12239df49d7eSJed Brown /// 12249df49d7eSJed Brown /// // Build quadrature data 1225c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1226c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1227c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1228c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1229c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1230c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 12319df49d7eSJed Brown /// 12329df49d7eSJed Brown /// // Mass operator 1233c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 12349df49d7eSJed Brown /// let op_mass_fine = ceed 1235c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1236c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1237c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1238c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 12399df49d7eSJed Brown /// 12409df49d7eSJed Brown /// // Multigrid setup 124180a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 12429df49d7eSJed Brown /// { 1243c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 1244c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 1245c68be7a2SJeremy L Thompson /// let basis_c_to_f = 1246c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 12479df49d7eSJed Brown /// for i in 0..p_coarse { 12489df49d7eSJed Brown /// coarse.set_value(0.0); 12499df49d7eSJed Brown /// { 12509df49d7eSJed Brown /// let mut array = coarse.view_mut(); 12519df49d7eSJed Brown /// array[i] = 1.; 12529df49d7eSJed Brown /// } 1253c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 12549df49d7eSJed Brown /// 1, 12559df49d7eSJed Brown /// TransposeMode::NoTranspose, 12569df49d7eSJed Brown /// EvalMode::Interp, 12579df49d7eSJed Brown /// &coarse, 12589df49d7eSJed Brown /// &mut fine, 1259c68be7a2SJeremy L Thompson /// )?; 12609df49d7eSJed Brown /// let array = fine.view(); 12619df49d7eSJed Brown /// for j in 0..p_fine { 12629df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 12639df49d7eSJed Brown /// } 12649df49d7eSJed Brown /// } 12659df49d7eSJed Brown /// } 1266c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_tensor_H1( 1267c68be7a2SJeremy L Thompson /// &multiplicity, 1268c68be7a2SJeremy L Thompson /// &ru_coarse, 1269c68be7a2SJeremy L Thompson /// &bu_coarse, 1270c68be7a2SJeremy L Thompson /// &interp_c_to_f, 1271c68be7a2SJeremy L Thompson /// )?; 12729df49d7eSJed Brown /// 12739df49d7eSJed Brown /// // Coarse problem 12749df49d7eSJed Brown /// u_coarse.set_value(1.0); 1275c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 12769df49d7eSJed Brown /// 12779df49d7eSJed Brown /// // Check 127880a9ef05SNatalie Beams /// let sum: Scalar = v_coarse.view().iter().sum(); 12799df49d7eSJed Brown /// assert!( 128080a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 12819df49d7eSJed Brown /// "Incorrect interval length computed" 12829df49d7eSJed Brown /// ); 12839df49d7eSJed Brown /// 12849df49d7eSJed Brown /// // Prolong 1285c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 12869df49d7eSJed Brown /// 12879df49d7eSJed Brown /// // Fine problem 1288c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 12899df49d7eSJed Brown /// 12909df49d7eSJed Brown /// // Check 129180a9ef05SNatalie Beams /// let sum: Scalar = v_fine.view().iter().sum(); 12929df49d7eSJed Brown /// assert!( 129380a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 12949df49d7eSJed Brown /// "Incorrect interval length computed" 12959df49d7eSJed Brown /// ); 12969df49d7eSJed Brown /// 12979df49d7eSJed Brown /// // Restrict 1298c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 12999df49d7eSJed Brown /// 13009df49d7eSJed Brown /// // Check 130180a9ef05SNatalie Beams /// let sum: Scalar = v_coarse.view().iter().sum(); 13029df49d7eSJed Brown /// assert!( 130380a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 13049df49d7eSJed Brown /// "Incorrect interval length computed" 13059df49d7eSJed Brown /// ); 1306c68be7a2SJeremy L Thompson /// # Ok(()) 1307c68be7a2SJeremy L Thompson /// # } 13089df49d7eSJed Brown /// ``` 13099df49d7eSJed Brown pub fn create_multigrid_level_tensor_H1( 13109df49d7eSJed Brown &self, 13119df49d7eSJed Brown p_mult_fine: &Vector, 13129df49d7eSJed Brown rstr_coarse: &ElemRestriction, 13139df49d7eSJed Brown basis_coarse: &Basis, 131480a9ef05SNatalie Beams interpCtoF: &Vec<Scalar>, 13159df49d7eSJed Brown ) -> crate::Result<(Operator, Operator, Operator)> { 13169df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 13179df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 13189df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 13199df49d7eSJed Brown let ierr = unsafe { 13209df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateTensorH1( 13219df49d7eSJed Brown self.op_core.ptr, 13229df49d7eSJed Brown p_mult_fine.ptr, 13239df49d7eSJed Brown rstr_coarse.ptr, 13249df49d7eSJed Brown basis_coarse.ptr, 13259df49d7eSJed Brown interpCtoF.as_ptr(), 13269df49d7eSJed Brown &mut ptr_coarse, 13279df49d7eSJed Brown &mut ptr_prolong, 13289df49d7eSJed Brown &mut ptr_restrict, 13299df49d7eSJed Brown ) 13309df49d7eSJed Brown }; 1331*1142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 1332*1142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 1333*1142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 1334*1142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 13359df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 13369df49d7eSJed Brown } 13379df49d7eSJed Brown 13389df49d7eSJed Brown /// Create a multigrid coarse Operator and level transfer Operators for a 13399df49d7eSJed Brown /// given Operator with a non-tensor basis for the active basis 13409df49d7eSJed Brown /// 13419df49d7eSJed Brown /// * `p_mult_fine` - Lvector multiplicity in parallel gather/scatter 13429df49d7eSJed Brown /// * `rstr_coarse` - Coarse grid restriction 13439df49d7eSJed Brown /// * `basis_coarse` - Coarse grid active vector basis 13449df49d7eSJed Brown /// * `interp_c_to_f` - Matrix for coarse to fine 13459df49d7eSJed Brown /// 13469df49d7eSJed Brown /// ``` 13479df49d7eSJed Brown /// # use libceed::prelude::*; 1348c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 13499df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 13509df49d7eSJed Brown /// let ne = 15; 13519df49d7eSJed Brown /// let p_coarse = 3; 13529df49d7eSJed Brown /// let p_fine = 5; 13539df49d7eSJed Brown /// let q = 6; 13549df49d7eSJed Brown /// let ndofs_coarse = p_coarse * ne - ne + 1; 13559df49d7eSJed Brown /// let ndofs_fine = p_fine * ne - ne + 1; 13569df49d7eSJed Brown /// 13579df49d7eSJed Brown /// // Vectors 13589df49d7eSJed Brown /// let x_array = (0..ne + 1) 135980a9ef05SNatalie Beams /// .map(|i| 2.0 * i as Scalar / ne as Scalar - 1.0) 136080a9ef05SNatalie Beams /// .collect::<Vec<Scalar>>(); 1361c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&x_array)?; 1362c68be7a2SJeremy L Thompson /// let mut qdata = ceed.vector(ne * q)?; 13639df49d7eSJed Brown /// qdata.set_value(0.0); 1364c68be7a2SJeremy L Thompson /// let mut u_coarse = ceed.vector(ndofs_coarse)?; 13659df49d7eSJed Brown /// u_coarse.set_value(1.0); 1366c68be7a2SJeremy L Thompson /// let mut u_fine = ceed.vector(ndofs_fine)?; 13679df49d7eSJed Brown /// u_fine.set_value(1.0); 1368c68be7a2SJeremy L Thompson /// let mut v_coarse = ceed.vector(ndofs_coarse)?; 13699df49d7eSJed Brown /// v_coarse.set_value(0.0); 1370c68be7a2SJeremy L Thompson /// let mut v_fine = ceed.vector(ndofs_fine)?; 13719df49d7eSJed Brown /// v_fine.set_value(0.0); 1372c68be7a2SJeremy L Thompson /// let mut multiplicity = ceed.vector(ndofs_fine)?; 13739df49d7eSJed Brown /// multiplicity.set_value(1.0); 13749df49d7eSJed Brown /// 13759df49d7eSJed Brown /// // Restrictions 13769df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1377c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 13789df49d7eSJed Brown /// 13799df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 13809df49d7eSJed Brown /// for i in 0..ne { 13819df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 13829df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 13839df49d7eSJed Brown /// } 1384c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 13859df49d7eSJed Brown /// 13869df49d7eSJed Brown /// let mut indu_coarse: Vec<i32> = vec![0; p_coarse * ne]; 13879df49d7eSJed Brown /// for i in 0..ne { 13889df49d7eSJed Brown /// for j in 0..p_coarse { 13899df49d7eSJed Brown /// indu_coarse[p_coarse * i + j] = (i + j) as i32; 13909df49d7eSJed Brown /// } 13919df49d7eSJed Brown /// } 1392c68be7a2SJeremy L Thompson /// let ru_coarse = ceed.elem_restriction( 13939df49d7eSJed Brown /// ne, 13949df49d7eSJed Brown /// p_coarse, 13959df49d7eSJed Brown /// 1, 13969df49d7eSJed Brown /// 1, 13979df49d7eSJed Brown /// ndofs_coarse, 13989df49d7eSJed Brown /// MemType::Host, 13999df49d7eSJed Brown /// &indu_coarse, 1400c68be7a2SJeremy L Thompson /// )?; 14019df49d7eSJed Brown /// 14029df49d7eSJed Brown /// let mut indu_fine: Vec<i32> = vec![0; p_fine * ne]; 14039df49d7eSJed Brown /// for i in 0..ne { 14049df49d7eSJed Brown /// for j in 0..p_fine { 14059df49d7eSJed Brown /// indu_fine[p_fine * i + j] = (i + j) as i32; 14069df49d7eSJed Brown /// } 14079df49d7eSJed Brown /// } 1408c68be7a2SJeremy L Thompson /// let ru_fine = ceed.elem_restriction(ne, p_fine, 1, 1, ndofs_fine, MemType::Host, &indu_fine)?; 14099df49d7eSJed Brown /// 14109df49d7eSJed Brown /// // Bases 1411c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1412c68be7a2SJeremy L Thompson /// let bu_coarse = ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, q, QuadMode::Gauss)?; 1413c68be7a2SJeremy L Thompson /// let bu_fine = ceed.basis_tensor_H1_Lagrange(1, 1, p_fine, q, QuadMode::Gauss)?; 14149df49d7eSJed Brown /// 14159df49d7eSJed Brown /// // Build quadrature data 1416c68be7a2SJeremy L Thompson /// let qf_build = ceed.q_function_interior_by_name("Mass1DBuild")?; 1417c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build, QFunctionOpt::None, QFunctionOpt::None)? 1418c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1419c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1420c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1421c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata)?; 14229df49d7eSJed Brown /// 14239df49d7eSJed Brown /// // Mass operator 1424c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 14259df49d7eSJed Brown /// let op_mass_fine = ceed 1426c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1427c68be7a2SJeremy L Thompson /// .field("u", &ru_fine, &bu_fine, VectorOpt::Active)? 1428c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata)? 1429c68be7a2SJeremy L Thompson /// .field("v", &ru_fine, &bu_fine, VectorOpt::Active)?; 14309df49d7eSJed Brown /// 14319df49d7eSJed Brown /// // Multigrid setup 143280a9ef05SNatalie Beams /// let mut interp_c_to_f: Vec<Scalar> = vec![0.; p_coarse * p_fine]; 14339df49d7eSJed Brown /// { 1434c68be7a2SJeremy L Thompson /// let mut coarse = ceed.vector(p_coarse)?; 1435c68be7a2SJeremy L Thompson /// let mut fine = ceed.vector(p_fine)?; 1436c68be7a2SJeremy L Thompson /// let basis_c_to_f = 1437c68be7a2SJeremy L Thompson /// ceed.basis_tensor_H1_Lagrange(1, 1, p_coarse, p_fine, QuadMode::GaussLobatto)?; 14389df49d7eSJed Brown /// for i in 0..p_coarse { 14399df49d7eSJed Brown /// coarse.set_value(0.0); 14409df49d7eSJed Brown /// { 14419df49d7eSJed Brown /// let mut array = coarse.view_mut(); 14429df49d7eSJed Brown /// array[i] = 1.; 14439df49d7eSJed Brown /// } 1444c68be7a2SJeremy L Thompson /// basis_c_to_f.apply( 14459df49d7eSJed Brown /// 1, 14469df49d7eSJed Brown /// TransposeMode::NoTranspose, 14479df49d7eSJed Brown /// EvalMode::Interp, 14489df49d7eSJed Brown /// &coarse, 14499df49d7eSJed Brown /// &mut fine, 1450c68be7a2SJeremy L Thompson /// )?; 14519df49d7eSJed Brown /// let array = fine.view(); 14529df49d7eSJed Brown /// for j in 0..p_fine { 14539df49d7eSJed Brown /// interp_c_to_f[j * p_coarse + i] = array[j]; 14549df49d7eSJed Brown /// } 14559df49d7eSJed Brown /// } 14569df49d7eSJed Brown /// } 1457c68be7a2SJeremy L Thompson /// let (op_mass_coarse, op_prolong, op_restrict) = op_mass_fine.create_multigrid_level_H1( 1458c68be7a2SJeremy L Thompson /// &multiplicity, 1459c68be7a2SJeremy L Thompson /// &ru_coarse, 1460c68be7a2SJeremy L Thompson /// &bu_coarse, 1461c68be7a2SJeremy L Thompson /// &interp_c_to_f, 1462c68be7a2SJeremy L Thompson /// )?; 14639df49d7eSJed Brown /// 14649df49d7eSJed Brown /// // Coarse problem 14659df49d7eSJed Brown /// u_coarse.set_value(1.0); 1466c68be7a2SJeremy L Thompson /// op_mass_coarse.apply(&u_coarse, &mut v_coarse)?; 14679df49d7eSJed Brown /// 14689df49d7eSJed Brown /// // Check 146980a9ef05SNatalie Beams /// let sum: Scalar = v_coarse.view().iter().sum(); 14709df49d7eSJed Brown /// assert!( 147180a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 14729df49d7eSJed Brown /// "Incorrect interval length computed" 14739df49d7eSJed Brown /// ); 14749df49d7eSJed Brown /// 14759df49d7eSJed Brown /// // Prolong 1476c68be7a2SJeremy L Thompson /// op_prolong.apply(&u_coarse, &mut u_fine)?; 14779df49d7eSJed Brown /// 14789df49d7eSJed Brown /// // Fine problem 1479c68be7a2SJeremy L Thompson /// op_mass_fine.apply(&u_fine, &mut v_fine)?; 14809df49d7eSJed Brown /// 14819df49d7eSJed Brown /// // Check 148280a9ef05SNatalie Beams /// let sum: Scalar = v_fine.view().iter().sum(); 14839df49d7eSJed Brown /// assert!( 148480a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 14859df49d7eSJed Brown /// "Incorrect interval length computed" 14869df49d7eSJed Brown /// ); 14879df49d7eSJed Brown /// 14889df49d7eSJed Brown /// // Restrict 1489c68be7a2SJeremy L Thompson /// op_restrict.apply(&v_fine, &mut v_coarse)?; 14909df49d7eSJed Brown /// 14919df49d7eSJed Brown /// // Check 149280a9ef05SNatalie Beams /// let sum: Scalar = v_coarse.view().iter().sum(); 14939df49d7eSJed Brown /// assert!( 149480a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 14959df49d7eSJed Brown /// "Incorrect interval length computed" 14969df49d7eSJed Brown /// ); 1497c68be7a2SJeremy L Thompson /// # Ok(()) 1498c68be7a2SJeremy L Thompson /// # } 14999df49d7eSJed Brown /// ``` 15009df49d7eSJed Brown pub fn create_multigrid_level_H1( 15019df49d7eSJed Brown &self, 15029df49d7eSJed Brown p_mult_fine: &Vector, 15039df49d7eSJed Brown rstr_coarse: &ElemRestriction, 15049df49d7eSJed Brown basis_coarse: &Basis, 150580a9ef05SNatalie Beams interpCtoF: &[Scalar], 15069df49d7eSJed Brown ) -> crate::Result<(Operator, Operator, Operator)> { 15079df49d7eSJed Brown let mut ptr_coarse = std::ptr::null_mut(); 15089df49d7eSJed Brown let mut ptr_prolong = std::ptr::null_mut(); 15099df49d7eSJed Brown let mut ptr_restrict = std::ptr::null_mut(); 15109df49d7eSJed Brown let ierr = unsafe { 15119df49d7eSJed Brown bind_ceed::CeedOperatorMultigridLevelCreateH1( 15129df49d7eSJed Brown self.op_core.ptr, 15139df49d7eSJed Brown p_mult_fine.ptr, 15149df49d7eSJed Brown rstr_coarse.ptr, 15159df49d7eSJed Brown basis_coarse.ptr, 15169df49d7eSJed Brown interpCtoF.as_ptr(), 15179df49d7eSJed Brown &mut ptr_coarse, 15189df49d7eSJed Brown &mut ptr_prolong, 15199df49d7eSJed Brown &mut ptr_restrict, 15209df49d7eSJed Brown ) 15219df49d7eSJed Brown }; 1522*1142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 1523*1142270cSJeremy L Thompson let op_coarse = Operator::from_raw(ptr_coarse)?; 1524*1142270cSJeremy L Thompson let op_prolong = Operator::from_raw(ptr_prolong)?; 1525*1142270cSJeremy L Thompson let op_restrict = Operator::from_raw(ptr_restrict)?; 15269df49d7eSJed Brown Ok((op_coarse, op_prolong, op_restrict)) 15279df49d7eSJed Brown } 15289df49d7eSJed Brown } 15299df49d7eSJed Brown 15309df49d7eSJed Brown // ----------------------------------------------------------------------------- 15319df49d7eSJed Brown // Composite Operator 15329df49d7eSJed Brown // ----------------------------------------------------------------------------- 15339df49d7eSJed Brown impl<'a> CompositeOperator<'a> { 15349df49d7eSJed Brown // Constructor 15359df49d7eSJed Brown pub fn create(ceed: &'a crate::Ceed) -> crate::Result<Self> { 15369df49d7eSJed Brown let mut ptr = std::ptr::null_mut(); 15379df49d7eSJed Brown let ierr = unsafe { bind_ceed::CeedCompositeOperatorCreate(ceed.ptr, &mut ptr) }; 15389df49d7eSJed Brown ceed.check_error(ierr)?; 15399df49d7eSJed Brown Ok(Self { 1540*1142270cSJeremy L Thompson op_core: OperatorCore { 1541*1142270cSJeremy L Thompson ptr, 1542*1142270cSJeremy L Thompson _lifeline: PhantomData, 1543*1142270cSJeremy L Thompson }, 15449df49d7eSJed Brown }) 15459df49d7eSJed Brown } 15469df49d7eSJed Brown 15479df49d7eSJed Brown /// Apply Operator to a vector 15489df49d7eSJed Brown /// 15499df49d7eSJed Brown /// * `input` - Input Vector 15509df49d7eSJed Brown /// * `output` - Output Vector 15519df49d7eSJed Brown /// 15529df49d7eSJed Brown /// ``` 15539df49d7eSJed Brown /// # use libceed::prelude::*; 1554c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 15559df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 15569df49d7eSJed Brown /// let ne = 4; 15579df49d7eSJed Brown /// let p = 3; 15589df49d7eSJed Brown /// let q = 4; 15599df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 15609df49d7eSJed Brown /// 15619df49d7eSJed Brown /// // Vectors 1562c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1563c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 15649df49d7eSJed Brown /// qdata_mass.set_value(0.0); 1565c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 15669df49d7eSJed Brown /// qdata_diff.set_value(0.0); 1567c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 15689df49d7eSJed Brown /// u.set_value(1.0); 1569c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 15709df49d7eSJed Brown /// v.set_value(0.0); 15719df49d7eSJed Brown /// 15729df49d7eSJed Brown /// // Restrictions 15739df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 15749df49d7eSJed Brown /// for i in 0..ne { 15759df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 15769df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 15779df49d7eSJed Brown /// } 1578c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 15799df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 15809df49d7eSJed Brown /// for i in 0..ne { 15819df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 15829df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 15839df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 15849df49d7eSJed Brown /// } 1585c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 15869df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1587c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 15889df49d7eSJed Brown /// 15899df49d7eSJed Brown /// // Bases 1590c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1591c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 15929df49d7eSJed Brown /// 15939df49d7eSJed Brown /// // Build quadrature data 1594c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 1595c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 1596c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1597c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1598c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1599c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 16009df49d7eSJed Brown /// 1601c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 1602c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 1603c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1604c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1605c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1606c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 16079df49d7eSJed Brown /// 16089df49d7eSJed Brown /// // Application operator 1609c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 16109df49d7eSJed Brown /// let op_mass = ceed 1611c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1612c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1613c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 1614c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 16159df49d7eSJed Brown /// 1616c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 16179df49d7eSJed Brown /// let op_diff = ceed 1618c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 1619c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 1620c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 1621c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 16229df49d7eSJed Brown /// 16239df49d7eSJed Brown /// let op_composite = ceed 1624c68be7a2SJeremy L Thompson /// .composite_operator()? 1625c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 1626c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 16279df49d7eSJed Brown /// 16289df49d7eSJed Brown /// v.set_value(0.0); 1629c68be7a2SJeremy L Thompson /// op_composite.apply(&u, &mut v)?; 16309df49d7eSJed Brown /// 16319df49d7eSJed Brown /// // Check 163280a9ef05SNatalie Beams /// let sum: Scalar = v.view().iter().sum(); 16339df49d7eSJed Brown /// assert!( 163480a9ef05SNatalie Beams /// (sum - 2.0).abs() < 10.0 * libceed::EPSILON, 16359df49d7eSJed Brown /// "Incorrect interval length computed" 16369df49d7eSJed Brown /// ); 1637c68be7a2SJeremy L Thompson /// # Ok(()) 1638c68be7a2SJeremy L Thompson /// # } 16399df49d7eSJed Brown /// ``` 16409df49d7eSJed Brown pub fn apply(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 16419df49d7eSJed Brown self.op_core.apply(input, output) 16429df49d7eSJed Brown } 16439df49d7eSJed Brown 16449df49d7eSJed Brown /// Apply Operator to a vector and add result to output vector 16459df49d7eSJed Brown /// 16469df49d7eSJed Brown /// * `input` - Input Vector 16479df49d7eSJed Brown /// * `output` - Output Vector 16489df49d7eSJed Brown /// 16499df49d7eSJed Brown /// ``` 16509df49d7eSJed Brown /// # use libceed::prelude::*; 1651c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 16529df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 16539df49d7eSJed Brown /// let ne = 4; 16549df49d7eSJed Brown /// let p = 3; 16559df49d7eSJed Brown /// let q = 4; 16569df49d7eSJed Brown /// let ndofs = p * ne - ne + 1; 16579df49d7eSJed Brown /// 16589df49d7eSJed Brown /// // Vectors 1659c68be7a2SJeremy L Thompson /// let x = ceed.vector_from_slice(&[-1., -0.5, 0.0, 0.5, 1.0])?; 1660c68be7a2SJeremy L Thompson /// let mut qdata_mass = ceed.vector(ne * q)?; 16619df49d7eSJed Brown /// qdata_mass.set_value(0.0); 1662c68be7a2SJeremy L Thompson /// let mut qdata_diff = ceed.vector(ne * q)?; 16639df49d7eSJed Brown /// qdata_diff.set_value(0.0); 1664c68be7a2SJeremy L Thompson /// let mut u = ceed.vector(ndofs)?; 16659df49d7eSJed Brown /// u.set_value(1.0); 1666c68be7a2SJeremy L Thompson /// let mut v = ceed.vector(ndofs)?; 16679df49d7eSJed Brown /// v.set_value(0.0); 16689df49d7eSJed Brown /// 16699df49d7eSJed Brown /// // Restrictions 16709df49d7eSJed Brown /// let mut indx: Vec<i32> = vec![0; 2 * ne]; 16719df49d7eSJed Brown /// for i in 0..ne { 16729df49d7eSJed Brown /// indx[2 * i + 0] = i as i32; 16739df49d7eSJed Brown /// indx[2 * i + 1] = (i + 1) as i32; 16749df49d7eSJed Brown /// } 1675c68be7a2SJeremy L Thompson /// let rx = ceed.elem_restriction(ne, 2, 1, 1, ne + 1, MemType::Host, &indx)?; 16769df49d7eSJed Brown /// let mut indu: Vec<i32> = vec![0; p * ne]; 16779df49d7eSJed Brown /// for i in 0..ne { 16789df49d7eSJed Brown /// indu[p * i + 0] = i as i32; 16799df49d7eSJed Brown /// indu[p * i + 1] = (i + 1) as i32; 16809df49d7eSJed Brown /// indu[p * i + 2] = (i + 2) as i32; 16819df49d7eSJed Brown /// } 1682c68be7a2SJeremy L Thompson /// let ru = ceed.elem_restriction(ne, 3, 1, 1, ndofs, MemType::Host, &indu)?; 16839df49d7eSJed Brown /// let strides: [i32; 3] = [1, q as i32, q as i32]; 1684c68be7a2SJeremy L Thompson /// let rq = ceed.strided_elem_restriction(ne, q, 1, q * ne, strides)?; 16859df49d7eSJed Brown /// 16869df49d7eSJed Brown /// // Bases 1687c68be7a2SJeremy L Thompson /// let bx = ceed.basis_tensor_H1_Lagrange(1, 1, 2, q, QuadMode::Gauss)?; 1688c68be7a2SJeremy L Thompson /// let bu = ceed.basis_tensor_H1_Lagrange(1, 1, p, q, QuadMode::Gauss)?; 16899df49d7eSJed Brown /// 16909df49d7eSJed Brown /// // Build quadrature data 1691c68be7a2SJeremy L Thompson /// let qf_build_mass = ceed.q_function_interior_by_name("Mass1DBuild")?; 1692c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_mass, QFunctionOpt::None, QFunctionOpt::None)? 1693c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1694c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1695c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1696c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_mass)?; 16979df49d7eSJed Brown /// 1698c68be7a2SJeremy L Thompson /// let qf_build_diff = ceed.q_function_interior_by_name("Poisson1DBuild")?; 1699c68be7a2SJeremy L Thompson /// ceed.operator(&qf_build_diff, QFunctionOpt::None, QFunctionOpt::None)? 1700c68be7a2SJeremy L Thompson /// .field("dx", &rx, &bx, VectorOpt::Active)? 1701c68be7a2SJeremy L Thompson /// .field("weights", ElemRestrictionOpt::None, &bx, VectorOpt::None)? 1702c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, VectorOpt::Active)? 1703c68be7a2SJeremy L Thompson /// .apply(&x, &mut qdata_diff)?; 17049df49d7eSJed Brown /// 17059df49d7eSJed Brown /// // Application operator 1706c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 17079df49d7eSJed Brown /// let op_mass = ceed 1708c68be7a2SJeremy L Thompson /// .operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)? 1709c68be7a2SJeremy L Thompson /// .field("u", &ru, &bu, VectorOpt::Active)? 1710c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_mass)? 1711c68be7a2SJeremy L Thompson /// .field("v", &ru, &bu, VectorOpt::Active)?; 17129df49d7eSJed Brown /// 1713c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 17149df49d7eSJed Brown /// let op_diff = ceed 1715c68be7a2SJeremy L Thompson /// .operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)? 1716c68be7a2SJeremy L Thompson /// .field("du", &ru, &bu, VectorOpt::Active)? 1717c68be7a2SJeremy L Thompson /// .field("qdata", &rq, BasisOpt::Collocated, &qdata_diff)? 1718c68be7a2SJeremy L Thompson /// .field("dv", &ru, &bu, VectorOpt::Active)?; 17199df49d7eSJed Brown /// 17209df49d7eSJed Brown /// let op_composite = ceed 1721c68be7a2SJeremy L Thompson /// .composite_operator()? 1722c68be7a2SJeremy L Thompson /// .sub_operator(&op_mass)? 1723c68be7a2SJeremy L Thompson /// .sub_operator(&op_diff)?; 17249df49d7eSJed Brown /// 17259df49d7eSJed Brown /// v.set_value(1.0); 1726c68be7a2SJeremy L Thompson /// op_composite.apply_add(&u, &mut v)?; 17279df49d7eSJed Brown /// 17289df49d7eSJed Brown /// // Check 172980a9ef05SNatalie Beams /// let sum: Scalar = v.view().iter().sum(); 17309df49d7eSJed Brown /// assert!( 173180a9ef05SNatalie Beams /// (sum - (2.0 + ndofs as Scalar)).abs() < 10.0 * libceed::EPSILON, 17329df49d7eSJed Brown /// "Incorrect interval length computed" 17339df49d7eSJed Brown /// ); 1734c68be7a2SJeremy L Thompson /// # Ok(()) 1735c68be7a2SJeremy L Thompson /// # } 17369df49d7eSJed Brown /// ``` 17379df49d7eSJed Brown pub fn apply_add(&self, input: &Vector, output: &mut Vector) -> crate::Result<i32> { 17389df49d7eSJed Brown self.op_core.apply_add(input, output) 17399df49d7eSJed Brown } 17409df49d7eSJed Brown 17419df49d7eSJed Brown /// Add a sub-Operator to a Composite Operator 17429df49d7eSJed Brown /// 17439df49d7eSJed Brown /// * `subop` - Sub-Operator 17449df49d7eSJed Brown /// 17459df49d7eSJed Brown /// ``` 17469df49d7eSJed Brown /// # use libceed::prelude::*; 1747c68be7a2SJeremy L Thompson /// # fn main() -> Result<(), libceed::CeedError> { 17489df49d7eSJed Brown /// # let ceed = libceed::Ceed::default_init(); 1749c68be7a2SJeremy L Thompson /// let mut op = ceed.composite_operator()?; 17509df49d7eSJed Brown /// 1751c68be7a2SJeremy L Thompson /// let qf_mass = ceed.q_function_interior_by_name("MassApply")?; 1752c68be7a2SJeremy L Thompson /// let op_mass = ceed.operator(&qf_mass, QFunctionOpt::None, QFunctionOpt::None)?; 1753c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_mass)?; 17549df49d7eSJed Brown /// 1755c68be7a2SJeremy L Thompson /// let qf_diff = ceed.q_function_interior_by_name("Poisson1DApply")?; 1756c68be7a2SJeremy L Thompson /// let op_diff = ceed.operator(&qf_diff, QFunctionOpt::None, QFunctionOpt::None)?; 1757c68be7a2SJeremy L Thompson /// op = op.sub_operator(&op_diff)?; 1758c68be7a2SJeremy L Thompson /// # Ok(()) 1759c68be7a2SJeremy L Thompson /// # } 17609df49d7eSJed Brown /// ``` 17619df49d7eSJed Brown #[allow(unused_mut)] 17629df49d7eSJed Brown pub fn sub_operator(mut self, subop: &Operator) -> crate::Result<Self> { 17639df49d7eSJed Brown let ierr = 17649df49d7eSJed Brown unsafe { bind_ceed::CeedCompositeOperatorAddSub(self.op_core.ptr, subop.op_core.ptr) }; 1765*1142270cSJeremy L Thompson self.op_core.check_error(ierr)?; 17669df49d7eSJed Brown Ok(self) 17679df49d7eSJed Brown } 17689df49d7eSJed Brown 17699df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 17709df49d7eSJed Brown /// 17719df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 17729df49d7eSJed Brown /// 17739df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 17749df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 17759df49d7eSJed Brown /// 17769df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 17779df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 17789df49d7eSJed Brown pub fn linear_asssemble_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 17799df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 17809df49d7eSJed Brown } 17819df49d7eSJed Brown 17829df49d7eSJed Brown /// Assemble the point block diagonal of a square linear Operator 17839df49d7eSJed Brown /// 17849df49d7eSJed Brown /// This overwrites a Vector with the point block diagonal of a linear 17859df49d7eSJed Brown /// Operator. 17869df49d7eSJed Brown /// 17879df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 17889df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 17899df49d7eSJed Brown /// 17909df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 17919df49d7eSJed Brown /// * `assembled` - Vector to store assembled Operator diagonal 17929df49d7eSJed Brown pub fn linear_assemble_add_diagonal(&self, assembled: &mut Vector) -> crate::Result<i32> { 17939df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 17949df49d7eSJed Brown } 17959df49d7eSJed Brown 17969df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 17979df49d7eSJed Brown /// 17989df49d7eSJed Brown /// This overwrites a Vector with the diagonal of a linear Operator. 17999df49d7eSJed Brown /// 18009df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 18019df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 18029df49d7eSJed Brown /// 18039df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 18049df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 18059df49d7eSJed Brown /// diagonal, provided in row-major form with an 18069df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 18079df49d7eSJed Brown /// this vector are derived from the active vector for 18089df49d7eSJed Brown /// the CeedOperator. The array has shape 18099df49d7eSJed Brown /// `[nodes, component out, component in]`. 18109df49d7eSJed Brown pub fn linear_assemble_point_block_diagonal( 18119df49d7eSJed Brown &self, 18129df49d7eSJed Brown assembled: &mut Vector, 18139df49d7eSJed Brown ) -> crate::Result<i32> { 18149df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 18159df49d7eSJed Brown } 18169df49d7eSJed Brown 18179df49d7eSJed Brown /// Assemble the diagonal of a square linear Operator 18189df49d7eSJed Brown /// 18199df49d7eSJed Brown /// This sums into a Vector with the diagonal of a linear Operator. 18209df49d7eSJed Brown /// 18219df49d7eSJed Brown /// Note: Currently only non-composite Operators with a single field and 18229df49d7eSJed Brown /// composite Operators with single field sub-operators are supported. 18239df49d7eSJed Brown /// 18249df49d7eSJed Brown /// * `op` - Operator to assemble QFunction 18259df49d7eSJed Brown /// * `assembled` - Vector to store assembled CeedOperator point block 18269df49d7eSJed Brown /// diagonal, provided in row-major form with an 18279df49d7eSJed Brown /// `ncomp * ncomp` block at each node. The dimensions of 18289df49d7eSJed Brown /// this vector are derived from the active vector for 18299df49d7eSJed Brown /// the CeedOperator. The array has shape 18309df49d7eSJed Brown /// `[nodes, component out, component in]`. 18319df49d7eSJed Brown pub fn linear_assemble_add_point_block_diagonal( 18329df49d7eSJed Brown &self, 18339df49d7eSJed Brown assembled: &mut Vector, 18349df49d7eSJed Brown ) -> crate::Result<i32> { 18359df49d7eSJed Brown self.op_core.linear_assemble_add_diagonal(assembled) 18369df49d7eSJed Brown } 18379df49d7eSJed Brown } 18389df49d7eSJed Brown 18399df49d7eSJed Brown // ----------------------------------------------------------------------------- 1840