1 // Copyright (c) 2017-2025, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 8 //! A Ceed ElemRestriction decomposes elements and groups the degrees of freedom 9 //! (dofs) according to the different elements they belong to. 10 11 use crate::{prelude::*, vector::Vector, TransposeMode}; 12 13 // ----------------------------------------------------------------------------- 14 // ElemRestriction option 15 // ----------------------------------------------------------------------------- 16 #[derive(Debug)] 17 pub enum ElemRestrictionOpt<'a> { 18 Some(&'a ElemRestriction<'a>), 19 None, 20 } 21 /// Construct a ElemRestrictionOpt reference from a ElemRestriction reference 22 impl<'a> From<&'a ElemRestriction<'_>> for ElemRestrictionOpt<'a> { 23 fn from(rstr: &'a ElemRestriction) -> Self { 24 debug_assert!(rstr.ptr != unsafe { bind_ceed::CEED_ELEMRESTRICTION_NONE }); 25 Self::Some(rstr) 26 } 27 } 28 impl<'a> ElemRestrictionOpt<'a> { 29 /// Transform a Rust libCEED ElemRestrictionOpt into C libCEED 30 /// CeedElemRestriction 31 pub(crate) fn to_raw(&self) -> bind_ceed::CeedElemRestriction { 32 match self { 33 Self::Some(rstr) => rstr.ptr, 34 Self::None => unsafe { bind_ceed::CEED_ELEMRESTRICTION_NONE }, 35 } 36 } 37 38 /// Check if an ElemRestrictionOpt is Some 39 /// 40 /// ``` 41 /// # use libceed::{prelude::*, ElemRestrictionOpt, MemType}; 42 /// # fn main() -> libceed::Result<()> { 43 /// # let ceed = libceed::Ceed::default_init(); 44 /// let nelem = 3; 45 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 46 /// for i in 0..nelem { 47 /// ind[2 * i + 0] = i as i32; 48 /// ind[2 * i + 1] = (i + 1) as i32; 49 /// } 50 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 51 /// let r_opt = ElemRestrictionOpt::from(&r); 52 /// assert!(r_opt.is_some(), "Incorrect ElemRestrictionOpt"); 53 /// 54 /// let r_opt = ElemRestrictionOpt::None; 55 /// assert!(!r_opt.is_some(), "Incorrect ElemRestrictionOpt"); 56 /// # Ok(()) 57 /// # } 58 /// ``` 59 pub fn is_some(&self) -> bool { 60 match self { 61 Self::Some(_) => true, 62 Self::None => false, 63 } 64 } 65 66 /// Check if an ElemRestrictionOpt is None 67 /// 68 /// ``` 69 /// # use libceed::{prelude::*, ElemRestrictionOpt, MemType}; 70 /// # fn main() -> libceed::Result<()> { 71 /// # let ceed = libceed::Ceed::default_init(); 72 /// let nelem = 3; 73 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 74 /// for i in 0..nelem { 75 /// ind[2 * i + 0] = i as i32; 76 /// ind[2 * i + 1] = (i + 1) as i32; 77 /// } 78 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 79 /// let r_opt = ElemRestrictionOpt::from(&r); 80 /// assert!(!r_opt.is_none(), "Incorrect ElemRestrictionOpt"); 81 /// 82 /// let r_opt = ElemRestrictionOpt::None; 83 /// assert!(r_opt.is_none(), "Incorrect ElemRestrictionOpt"); 84 /// # Ok(()) 85 /// # } 86 /// ``` 87 pub fn is_none(&self) -> bool { 88 match self { 89 Self::Some(_) => false, 90 Self::None => true, 91 } 92 } 93 } 94 95 // ----------------------------------------------------------------------------- 96 // ElemRestriction context wrapper 97 // ----------------------------------------------------------------------------- 98 #[derive(Debug)] 99 pub struct ElemRestriction<'a> { 100 pub(crate) ptr: bind_ceed::CeedElemRestriction, 101 _lifeline: PhantomData<&'a ()>, 102 } 103 104 // ----------------------------------------------------------------------------- 105 // Destructor 106 // ----------------------------------------------------------------------------- 107 impl<'a> Drop for ElemRestriction<'a> { 108 fn drop(&mut self) { 109 unsafe { 110 if self.ptr != bind_ceed::CEED_ELEMRESTRICTION_NONE { 111 bind_ceed::CeedElemRestrictionDestroy(&mut self.ptr); 112 } 113 } 114 } 115 } 116 117 // ----------------------------------------------------------------------------- 118 // Display 119 // ----------------------------------------------------------------------------- 120 impl<'a> fmt::Display for ElemRestriction<'a> { 121 /// View an ElemRestriction 122 /// 123 /// ``` 124 /// # use libceed::{prelude::*, MemType}; 125 /// # fn main() -> libceed::Result<()> { 126 /// # let ceed = libceed::Ceed::default_init(); 127 /// let nelem = 3; 128 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 129 /// for i in 0..nelem { 130 /// ind[2 * i + 0] = i as i32; 131 /// ind[2 * i + 1] = (i + 1) as i32; 132 /// } 133 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 134 /// println!("{}", r); 135 /// # Ok(()) 136 /// # } 137 /// ``` 138 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 139 let mut ptr = std::ptr::null_mut(); 140 let mut sizeloc = crate::MAX_BUFFER_LENGTH; 141 let cstring = unsafe { 142 let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc); 143 bind_ceed::CeedElemRestrictionView(self.ptr, file); 144 bind_ceed::fclose(file); 145 CString::from_raw(ptr) 146 }; 147 cstring.to_string_lossy().fmt(f) 148 } 149 } 150 151 // ----------------------------------------------------------------------------- 152 // Implementations 153 // ----------------------------------------------------------------------------- 154 impl<'a> ElemRestriction<'a> { 155 // Constructors 156 #[allow(clippy::too_many_arguments)] 157 pub fn create( 158 ceed: &crate::Ceed, 159 nelem: usize, 160 elemsize: usize, 161 ncomp: usize, 162 compstride: usize, 163 lsize: usize, 164 mtype: crate::MemType, 165 offsets: &[i32], 166 ) -> crate::Result<Self> { 167 let mut ptr = std::ptr::null_mut(); 168 let (nelem, elemsize, ncomp, compstride, lsize, mtype) = ( 169 i32::try_from(nelem).unwrap(), 170 i32::try_from(elemsize).unwrap(), 171 i32::try_from(ncomp).unwrap(), 172 i32::try_from(compstride).unwrap(), 173 isize::try_from(lsize).unwrap(), 174 mtype as bind_ceed::CeedMemType, 175 ); 176 ceed.check_error(unsafe { 177 bind_ceed::CeedElemRestrictionCreate( 178 ceed.ptr, 179 nelem, 180 elemsize, 181 ncomp, 182 compstride, 183 lsize, 184 mtype, 185 crate::CopyMode::CopyValues as bind_ceed::CeedCopyMode, 186 offsets.as_ptr(), 187 &mut ptr, 188 ) 189 })?; 190 Ok(Self { 191 ptr, 192 _lifeline: PhantomData, 193 }) 194 } 195 196 pub(crate) unsafe fn from_raw(ptr: bind_ceed::CeedElemRestriction) -> crate::Result<Self> { 197 Ok(Self { 198 ptr, 199 _lifeline: PhantomData, 200 }) 201 } 202 203 #[allow(clippy::too_many_arguments)] 204 pub fn create_oriented( 205 ceed: &crate::Ceed, 206 nelem: usize, 207 elemsize: usize, 208 ncomp: usize, 209 compstride: usize, 210 lsize: usize, 211 mtype: crate::MemType, 212 offsets: &[i32], 213 orients: &[bool], 214 ) -> crate::Result<Self> { 215 let mut ptr = std::ptr::null_mut(); 216 let (nelem, elemsize, ncomp, compstride, lsize, mtype) = ( 217 i32::try_from(nelem).unwrap(), 218 i32::try_from(elemsize).unwrap(), 219 i32::try_from(ncomp).unwrap(), 220 i32::try_from(compstride).unwrap(), 221 isize::try_from(lsize).unwrap(), 222 mtype as bind_ceed::CeedMemType, 223 ); 224 ceed.check_error(unsafe { 225 bind_ceed::CeedElemRestrictionCreateOriented( 226 ceed.ptr, 227 nelem, 228 elemsize, 229 ncomp, 230 compstride, 231 lsize, 232 mtype, 233 crate::CopyMode::CopyValues as bind_ceed::CeedCopyMode, 234 offsets.as_ptr(), 235 orients.as_ptr(), 236 &mut ptr, 237 ) 238 })?; 239 Ok(Self { 240 ptr, 241 _lifeline: PhantomData, 242 }) 243 } 244 245 #[allow(clippy::too_many_arguments)] 246 pub fn create_curl_oriented( 247 ceed: &crate::Ceed, 248 nelem: usize, 249 elemsize: usize, 250 ncomp: usize, 251 compstride: usize, 252 lsize: usize, 253 mtype: crate::MemType, 254 offsets: &[i32], 255 curlorients: &[i8], 256 ) -> crate::Result<Self> { 257 let mut ptr = std::ptr::null_mut(); 258 let (nelem, elemsize, ncomp, compstride, lsize, mtype) = ( 259 i32::try_from(nelem).unwrap(), 260 i32::try_from(elemsize).unwrap(), 261 i32::try_from(ncomp).unwrap(), 262 i32::try_from(compstride).unwrap(), 263 isize::try_from(lsize).unwrap(), 264 mtype as bind_ceed::CeedMemType, 265 ); 266 ceed.check_error(unsafe { 267 bind_ceed::CeedElemRestrictionCreateCurlOriented( 268 ceed.ptr, 269 nelem, 270 elemsize, 271 ncomp, 272 compstride, 273 lsize, 274 mtype, 275 crate::CopyMode::CopyValues as bind_ceed::CeedCopyMode, 276 offsets.as_ptr(), 277 curlorients.as_ptr(), 278 &mut ptr, 279 ) 280 })?; 281 Ok(Self { 282 ptr, 283 _lifeline: PhantomData, 284 }) 285 } 286 287 pub fn create_strided( 288 ceed: &crate::Ceed, 289 nelem: usize, 290 elemsize: usize, 291 ncomp: usize, 292 lsize: usize, 293 strides: [i32; 3], 294 ) -> crate::Result<Self> { 295 let mut ptr = std::ptr::null_mut(); 296 let (nelem, elemsize, ncomp, lsize) = ( 297 i32::try_from(nelem).unwrap(), 298 i32::try_from(elemsize).unwrap(), 299 i32::try_from(ncomp).unwrap(), 300 isize::try_from(lsize).unwrap(), 301 ); 302 ceed.check_error(unsafe { 303 bind_ceed::CeedElemRestrictionCreateStrided( 304 ceed.ptr, 305 nelem, 306 elemsize, 307 ncomp, 308 lsize, 309 strides.as_ptr(), 310 &mut ptr, 311 ) 312 })?; 313 Ok(Self { 314 ptr, 315 _lifeline: PhantomData, 316 }) 317 } 318 319 // Raw Ceed for error handling 320 #[doc(hidden)] 321 fn ceed(&self) -> bind_ceed::Ceed { 322 unsafe { bind_ceed::CeedElemRestrictionReturnCeed(self.ptr) } 323 } 324 325 // Error handling 326 #[doc(hidden)] 327 fn check_error(&self, ierr: i32) -> crate::Result<i32> { 328 crate::check_error(|| self.ceed(), ierr) 329 } 330 331 /// Create an Lvector for an ElemRestriction 332 /// 333 /// ``` 334 /// # use libceed::{prelude::*, MemType}; 335 /// # fn main() -> libceed::Result<()> { 336 /// # let ceed = libceed::Ceed::default_init(); 337 /// let nelem = 3; 338 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 339 /// for i in 0..nelem { 340 /// ind[2 * i + 0] = i as i32; 341 /// ind[2 * i + 1] = (i + 1) as i32; 342 /// } 343 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 344 /// 345 /// let lvector = r.create_lvector()?; 346 /// 347 /// assert_eq!(lvector.length(), nelem + 1, "Incorrect Lvector size"); 348 /// # Ok(()) 349 /// # } 350 /// ``` 351 pub fn create_lvector<'b>(&self) -> crate::Result<Vector<'b>> { 352 let mut ptr_lvector = std::ptr::null_mut(); 353 let null = std::ptr::null_mut() as *mut _; 354 self.check_error(unsafe { 355 bind_ceed::CeedElemRestrictionCreateVector(self.ptr, &mut ptr_lvector, null) 356 })?; 357 unsafe { Vector::from_raw(ptr_lvector) } 358 } 359 360 /// Create an Evector for an ElemRestriction 361 /// 362 /// ``` 363 /// # use libceed::{prelude::*, MemType}; 364 /// # fn main() -> libceed::Result<()> { 365 /// # let ceed = libceed::Ceed::default_init(); 366 /// let nelem = 3; 367 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 368 /// for i in 0..nelem { 369 /// ind[2 * i + 0] = i as i32; 370 /// ind[2 * i + 1] = (i + 1) as i32; 371 /// } 372 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 373 /// 374 /// let evector = r.create_evector()?; 375 /// 376 /// assert_eq!(evector.length(), nelem * 2, "Incorrect Evector size"); 377 /// # Ok(()) 378 /// # } 379 /// ``` 380 pub fn create_evector<'b>(&self) -> crate::Result<Vector<'b>> { 381 let mut ptr_evector = std::ptr::null_mut(); 382 let null = std::ptr::null_mut() as *mut _; 383 self.check_error(unsafe { 384 bind_ceed::CeedElemRestrictionCreateVector(self.ptr, null, &mut ptr_evector) 385 })?; 386 unsafe { Vector::from_raw(ptr_evector) } 387 } 388 389 /// Create Vectors for an ElemRestriction 390 /// 391 /// ``` 392 /// # use libceed::{prelude::*, MemType}; 393 /// # fn main() -> libceed::Result<()> { 394 /// # let ceed = libceed::Ceed::default_init(); 395 /// let nelem = 3; 396 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 397 /// for i in 0..nelem { 398 /// ind[2 * i + 0] = i as i32; 399 /// ind[2 * i + 1] = (i + 1) as i32; 400 /// } 401 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 402 /// 403 /// let (lvector, evector) = r.create_vectors()?; 404 /// 405 /// assert_eq!(lvector.length(), nelem + 1, "Incorrect Lvector size"); 406 /// assert_eq!(evector.length(), nelem * 2, "Incorrect Evector size"); 407 /// # Ok(()) 408 /// # } 409 /// ``` 410 pub fn create_vectors<'b, 'c>(&self) -> crate::Result<(Vector<'b>, Vector<'c>)> { 411 let mut ptr_lvector = std::ptr::null_mut(); 412 let mut ptr_evector = std::ptr::null_mut(); 413 self.check_error(unsafe { 414 bind_ceed::CeedElemRestrictionCreateVector(self.ptr, &mut ptr_lvector, &mut ptr_evector) 415 })?; 416 let lvector = unsafe { Vector::from_raw(ptr_lvector)? }; 417 let evector = unsafe { Vector::from_raw(ptr_evector)? }; 418 Ok((lvector, evector)) 419 } 420 421 /// Restrict an Lvector to an Evector or apply its transpose 422 /// 423 /// # arguments 424 /// 425 /// * `tmode` - Apply restriction or transpose 426 /// * `u` - Input vector (of size `lsize` when `TransposeMode::NoTranspose`) 427 /// * `ru` - Output vector (of shape `[nelem * elemsize]` when 428 /// `TransposeMode::NoTranspose`). Ordering of the Evector is 429 /// decided by the backend. 430 /// 431 /// ``` 432 /// # use libceed::{prelude::*, MemType, Scalar, TransposeMode}; 433 /// # fn main() -> libceed::Result<()> { 434 /// # let ceed = libceed::Ceed::default_init(); 435 /// let nelem = 3; 436 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 437 /// for i in 0..nelem { 438 /// ind[2 * i + 0] = i as i32; 439 /// ind[2 * i + 1] = (i + 1) as i32; 440 /// } 441 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 442 /// 443 /// let x = ceed.vector_from_slice(&[0., 1., 2., 3.])?; 444 /// let mut y = ceed.vector(nelem * 2)?; 445 /// y.set_value(0.0); 446 /// 447 /// r.apply(TransposeMode::NoTranspose, &x, &mut y)?; 448 /// 449 /// for (i, y) in y.view()?.iter().enumerate() { 450 /// assert_eq!( 451 /// *y, 452 /// ((i + 1) / 2) as Scalar, 453 /// "Incorrect value in restricted vector" 454 /// ); 455 /// } 456 /// # Ok(()) 457 /// # } 458 /// ``` 459 pub fn apply(&self, tmode: TransposeMode, u: &Vector, ru: &mut Vector) -> crate::Result<i32> { 460 let tmode = tmode as bind_ceed::CeedTransposeMode; 461 self.check_error(unsafe { 462 bind_ceed::CeedElemRestrictionApply( 463 self.ptr, 464 tmode, 465 u.ptr, 466 ru.ptr, 467 bind_ceed::CEED_REQUEST_IMMEDIATE, 468 ) 469 }) 470 } 471 472 /// Returns the Lvector component stride 473 /// 474 /// ``` 475 /// # use libceed::{prelude::*, MemType}; 476 /// # fn main() -> libceed::Result<()> { 477 /// # let ceed = libceed::Ceed::default_init(); 478 /// let nelem = 3; 479 /// let compstride = 1; 480 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 481 /// for i in 0..nelem { 482 /// ind[2 * i + 0] = i as i32; 483 /// ind[2 * i + 1] = (i + 1) as i32; 484 /// } 485 /// let r = ceed.elem_restriction(nelem, 2, 1, compstride, nelem + 1, MemType::Host, &ind)?; 486 /// 487 /// let c = r.comp_stride(); 488 /// assert_eq!(c, compstride, "Incorrect component stride"); 489 /// # Ok(()) 490 /// # } 491 /// ``` 492 pub fn comp_stride(&self) -> usize { 493 let mut compstride = 0; 494 unsafe { bind_ceed::CeedElemRestrictionGetCompStride(self.ptr, &mut compstride) }; 495 usize::try_from(compstride).unwrap() 496 } 497 498 /// Returns the total number of elements in the range of a ElemRestriction 499 /// 500 /// ``` 501 /// # use libceed::{prelude::*, MemType}; 502 /// # fn main() -> libceed::Result<()> { 503 /// # let ceed = libceed::Ceed::default_init(); 504 /// let nelem = 3; 505 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 506 /// for i in 0..nelem { 507 /// ind[2 * i + 0] = i as i32; 508 /// ind[2 * i + 1] = (i + 1) as i32; 509 /// } 510 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 511 /// 512 /// let n = r.num_elements(); 513 /// assert_eq!(n, nelem, "Incorrect number of elements"); 514 /// # Ok(()) 515 /// # } 516 /// ``` 517 pub fn num_elements(&self) -> usize { 518 let mut numelem = 0; 519 unsafe { bind_ceed::CeedElemRestrictionGetNumElements(self.ptr, &mut numelem) }; 520 usize::try_from(numelem).unwrap() 521 } 522 523 /// Returns the size of elements in the ElemRestriction 524 /// 525 /// ``` 526 /// # use libceed::{prelude::*, MemType}; 527 /// # fn main() -> libceed::Result<()> { 528 /// # let ceed = libceed::Ceed::default_init(); 529 /// let nelem = 3; 530 /// let elem_size = 2; 531 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 532 /// for i in 0..nelem { 533 /// ind[2 * i + 0] = i as i32; 534 /// ind[2 * i + 1] = (i + 1) as i32; 535 /// } 536 /// let r = ceed.elem_restriction(nelem, elem_size, 1, 1, nelem + 1, MemType::Host, &ind)?; 537 /// 538 /// let e = r.elem_size(); 539 /// assert_eq!(e, elem_size, "Incorrect element size"); 540 /// # Ok(()) 541 /// # } 542 /// ``` 543 pub fn elem_size(&self) -> usize { 544 let mut elemsize = 0; 545 unsafe { bind_ceed::CeedElemRestrictionGetElementSize(self.ptr, &mut elemsize) }; 546 usize::try_from(elemsize).unwrap() 547 } 548 549 /// Returns the size of the Lvector for an ElemRestriction 550 /// 551 /// ``` 552 /// # use libceed::{prelude::*, MemType}; 553 /// # fn main() -> libceed::Result<()> { 554 /// # let ceed = libceed::Ceed::default_init(); 555 /// let nelem = 3; 556 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 557 /// for i in 0..nelem { 558 /// ind[2 * i + 0] = i as i32; 559 /// ind[2 * i + 1] = (i + 1) as i32; 560 /// } 561 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 562 /// 563 /// let lsize = r.lvector_size(); 564 /// assert_eq!(lsize, nelem + 1); 565 /// # Ok(()) 566 /// # } 567 /// ``` 568 pub fn lvector_size(&self) -> usize { 569 let mut lsize = 0; 570 unsafe { bind_ceed::CeedElemRestrictionGetLVectorSize(self.ptr, &mut lsize) }; 571 usize::try_from(lsize).unwrap() 572 } 573 574 /// Returns the number of components in the elements of an ElemRestriction 575 /// 576 /// ``` 577 /// # use libceed::{prelude::*, MemType}; 578 /// # fn main() -> libceed::Result<()> { 579 /// # let ceed = libceed::Ceed::default_init(); 580 /// let nelem = 3; 581 /// let ncomp = 42; 582 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 583 /// for i in 0..nelem { 584 /// ind[2 * i + 0] = i as i32; 585 /// ind[2 * i + 1] = (i + 1) as i32; 586 /// } 587 /// let r = ceed.elem_restriction(nelem, 2, 42, 1, ncomp * (nelem + 1), MemType::Host, &ind)?; 588 /// 589 /// let n = r.num_components(); 590 /// assert_eq!(n, ncomp, "Incorrect number of components"); 591 /// # Ok(()) 592 /// # } 593 /// ``` 594 pub fn num_components(&self) -> usize { 595 let mut ncomp = 0; 596 unsafe { bind_ceed::CeedElemRestrictionGetNumComponents(self.ptr, &mut ncomp) }; 597 usize::try_from(ncomp).unwrap() 598 } 599 600 /// Returns the multiplicity of nodes in an ElemRestriction 601 /// 602 /// ``` 603 /// # use libceed::{prelude::*, MemType}; 604 /// # fn main() -> libceed::Result<()> { 605 /// # let ceed = libceed::Ceed::default_init(); 606 /// let nelem = 3; 607 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 608 /// for i in 0..nelem { 609 /// ind[2 * i + 0] = i as i32; 610 /// ind[2 * i + 1] = (i + 1) as i32; 611 /// } 612 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 613 /// 614 /// let mut mult = ceed.vector(nelem + 1)?; 615 /// mult.set_value(0.0); 616 /// 617 /// r.multiplicity(&mut mult)?; 618 /// 619 /// for (i, m) in mult.view()?.iter().enumerate() { 620 /// assert_eq!( 621 /// *m, 622 /// if (i == 0 || i == nelem) { 1. } else { 2. }, 623 /// "Incorrect multiplicity value" 624 /// ); 625 /// } 626 /// # Ok(()) 627 /// # } 628 /// ``` 629 pub fn multiplicity(&self, mult: &mut Vector) -> crate::Result<i32> { 630 self.check_error(unsafe { 631 bind_ceed::CeedElemRestrictionGetMultiplicity(self.ptr, mult.ptr) 632 }) 633 } 634 } 635 636 // ----------------------------------------------------------------------------- 637