1 // Copyright (c) 2017-2024, 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::*; 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::*; 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::*; 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::*; 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 pub fn create( 157 ceed: &crate::Ceed, 158 nelem: usize, 159 elemsize: usize, 160 ncomp: usize, 161 compstride: usize, 162 lsize: usize, 163 mtype: crate::MemType, 164 offsets: &[i32], 165 ) -> crate::Result<Self> { 166 let mut ptr = std::ptr::null_mut(); 167 let (nelem, elemsize, ncomp, compstride, lsize, mtype) = ( 168 i32::try_from(nelem).unwrap(), 169 i32::try_from(elemsize).unwrap(), 170 i32::try_from(ncomp).unwrap(), 171 i32::try_from(compstride).unwrap(), 172 isize::try_from(lsize).unwrap(), 173 mtype as bind_ceed::CeedMemType, 174 ); 175 ceed.check_error(unsafe { 176 bind_ceed::CeedElemRestrictionCreate( 177 ceed.ptr, 178 nelem, 179 elemsize, 180 ncomp, 181 compstride, 182 lsize, 183 mtype, 184 crate::CopyMode::CopyValues as bind_ceed::CeedCopyMode, 185 offsets.as_ptr(), 186 &mut ptr, 187 ) 188 })?; 189 Ok(Self { 190 ptr, 191 _lifeline: PhantomData, 192 }) 193 } 194 195 pub(crate) unsafe fn from_raw(ptr: bind_ceed::CeedElemRestriction) -> crate::Result<Self> { 196 Ok(Self { 197 ptr, 198 _lifeline: PhantomData, 199 }) 200 } 201 202 pub fn create_oriented( 203 ceed: &crate::Ceed, 204 nelem: usize, 205 elemsize: usize, 206 ncomp: usize, 207 compstride: usize, 208 lsize: usize, 209 mtype: crate::MemType, 210 offsets: &[i32], 211 orients: &[bool], 212 ) -> crate::Result<Self> { 213 let mut ptr = std::ptr::null_mut(); 214 let (nelem, elemsize, ncomp, compstride, lsize, mtype) = ( 215 i32::try_from(nelem).unwrap(), 216 i32::try_from(elemsize).unwrap(), 217 i32::try_from(ncomp).unwrap(), 218 i32::try_from(compstride).unwrap(), 219 isize::try_from(lsize).unwrap(), 220 mtype as bind_ceed::CeedMemType, 221 ); 222 ceed.check_error(unsafe { 223 bind_ceed::CeedElemRestrictionCreateOriented( 224 ceed.ptr, 225 nelem, 226 elemsize, 227 ncomp, 228 compstride, 229 lsize, 230 mtype, 231 crate::CopyMode::CopyValues as bind_ceed::CeedCopyMode, 232 offsets.as_ptr(), 233 orients.as_ptr(), 234 &mut ptr, 235 ) 236 })?; 237 Ok(Self { 238 ptr, 239 _lifeline: PhantomData, 240 }) 241 } 242 243 pub fn create_curl_oriented( 244 ceed: &crate::Ceed, 245 nelem: usize, 246 elemsize: usize, 247 ncomp: usize, 248 compstride: usize, 249 lsize: usize, 250 mtype: crate::MemType, 251 offsets: &[i32], 252 curlorients: &[i8], 253 ) -> crate::Result<Self> { 254 let mut ptr = std::ptr::null_mut(); 255 let (nelem, elemsize, ncomp, compstride, lsize, mtype) = ( 256 i32::try_from(nelem).unwrap(), 257 i32::try_from(elemsize).unwrap(), 258 i32::try_from(ncomp).unwrap(), 259 i32::try_from(compstride).unwrap(), 260 isize::try_from(lsize).unwrap(), 261 mtype as bind_ceed::CeedMemType, 262 ); 263 ceed.check_error(unsafe { 264 bind_ceed::CeedElemRestrictionCreateCurlOriented( 265 ceed.ptr, 266 nelem, 267 elemsize, 268 ncomp, 269 compstride, 270 lsize, 271 mtype, 272 crate::CopyMode::CopyValues as bind_ceed::CeedCopyMode, 273 offsets.as_ptr(), 274 curlorients.as_ptr(), 275 &mut ptr, 276 ) 277 })?; 278 Ok(Self { 279 ptr, 280 _lifeline: PhantomData, 281 }) 282 } 283 284 pub fn create_strided( 285 ceed: &crate::Ceed, 286 nelem: usize, 287 elemsize: usize, 288 ncomp: usize, 289 lsize: usize, 290 strides: [i32; 3], 291 ) -> crate::Result<Self> { 292 let mut ptr = std::ptr::null_mut(); 293 let (nelem, elemsize, ncomp, lsize) = ( 294 i32::try_from(nelem).unwrap(), 295 i32::try_from(elemsize).unwrap(), 296 i32::try_from(ncomp).unwrap(), 297 isize::try_from(lsize).unwrap(), 298 ); 299 ceed.check_error(unsafe { 300 bind_ceed::CeedElemRestrictionCreateStrided( 301 ceed.ptr, 302 nelem, 303 elemsize, 304 ncomp, 305 lsize, 306 strides.as_ptr(), 307 &mut ptr, 308 ) 309 })?; 310 Ok(Self { 311 ptr, 312 _lifeline: PhantomData, 313 }) 314 } 315 316 // Raw Ceed for error handling 317 #[doc(hidden)] 318 fn ceed(&self) -> bind_ceed::Ceed { 319 unsafe { bind_ceed::CeedElemRestrictionReturnCeed(self.ptr) } 320 } 321 322 // Error handling 323 #[doc(hidden)] 324 fn check_error(&self, ierr: i32) -> crate::Result<i32> { 325 crate::check_error(|| self.ceed(), ierr) 326 } 327 328 /// Create an Lvector for an ElemRestriction 329 /// 330 /// ``` 331 /// # use libceed::prelude::*; 332 /// # fn main() -> libceed::Result<()> { 333 /// # let ceed = libceed::Ceed::default_init(); 334 /// let nelem = 3; 335 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 336 /// for i in 0..nelem { 337 /// ind[2 * i + 0] = i as i32; 338 /// ind[2 * i + 1] = (i + 1) as i32; 339 /// } 340 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 341 /// 342 /// let lvector = r.create_lvector()?; 343 /// 344 /// assert_eq!(lvector.length(), nelem + 1, "Incorrect Lvector size"); 345 /// # Ok(()) 346 /// # } 347 /// ``` 348 pub fn create_lvector<'b>(&self) -> crate::Result<Vector<'b>> { 349 let mut ptr_lvector = std::ptr::null_mut(); 350 let null = std::ptr::null_mut() as *mut _; 351 self.check_error(unsafe { 352 bind_ceed::CeedElemRestrictionCreateVector(self.ptr, &mut ptr_lvector, null) 353 })?; 354 unsafe { Vector::from_raw(ptr_lvector) } 355 } 356 357 /// Create an Evector for an ElemRestriction 358 /// 359 /// ``` 360 /// # use libceed::prelude::*; 361 /// # fn main() -> libceed::Result<()> { 362 /// # let ceed = libceed::Ceed::default_init(); 363 /// let nelem = 3; 364 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 365 /// for i in 0..nelem { 366 /// ind[2 * i + 0] = i as i32; 367 /// ind[2 * i + 1] = (i + 1) as i32; 368 /// } 369 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 370 /// 371 /// let evector = r.create_evector()?; 372 /// 373 /// assert_eq!(evector.length(), nelem * 2, "Incorrect Evector size"); 374 /// # Ok(()) 375 /// # } 376 /// ``` 377 pub fn create_evector<'b>(&self) -> crate::Result<Vector<'b>> { 378 let mut ptr_evector = std::ptr::null_mut(); 379 let null = std::ptr::null_mut() as *mut _; 380 self.check_error(unsafe { 381 bind_ceed::CeedElemRestrictionCreateVector(self.ptr, null, &mut ptr_evector) 382 })?; 383 unsafe { Vector::from_raw(ptr_evector) } 384 } 385 386 /// Create Vectors for an ElemRestriction 387 /// 388 /// ``` 389 /// # use libceed::prelude::*; 390 /// # fn main() -> libceed::Result<()> { 391 /// # let ceed = libceed::Ceed::default_init(); 392 /// let nelem = 3; 393 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 394 /// for i in 0..nelem { 395 /// ind[2 * i + 0] = i as i32; 396 /// ind[2 * i + 1] = (i + 1) as i32; 397 /// } 398 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 399 /// 400 /// let (lvector, evector) = r.create_vectors()?; 401 /// 402 /// assert_eq!(lvector.length(), nelem + 1, "Incorrect Lvector size"); 403 /// assert_eq!(evector.length(), nelem * 2, "Incorrect Evector size"); 404 /// # Ok(()) 405 /// # } 406 /// ``` 407 pub fn create_vectors<'b, 'c>(&self) -> crate::Result<(Vector<'b>, Vector<'c>)> { 408 let mut ptr_lvector = std::ptr::null_mut(); 409 let mut ptr_evector = std::ptr::null_mut(); 410 self.check_error(unsafe { 411 bind_ceed::CeedElemRestrictionCreateVector(self.ptr, &mut ptr_lvector, &mut ptr_evector) 412 })?; 413 let lvector = unsafe { Vector::from_raw(ptr_lvector)? }; 414 let evector = unsafe { Vector::from_raw(ptr_evector)? }; 415 Ok((lvector, evector)) 416 } 417 418 /// Restrict an Lvector to an Evector or apply its transpose 419 /// 420 /// # arguments 421 /// 422 /// * `tmode` - Apply restriction or transpose 423 /// * `u` - Input vector (of size `lsize` when `TransposeMode::NoTranspose`) 424 /// * `ru` - Output vector (of shape `[nelem * elemsize]` when 425 /// `TransposeMode::NoTranspose`). Ordering of the Evector is 426 /// decided by the backend. 427 /// 428 /// ``` 429 /// # use libceed::prelude::*; 430 /// # fn main() -> libceed::Result<()> { 431 /// # let ceed = libceed::Ceed::default_init(); 432 /// let nelem = 3; 433 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 434 /// for i in 0..nelem { 435 /// ind[2 * i + 0] = i as i32; 436 /// ind[2 * i + 1] = (i + 1) as i32; 437 /// } 438 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 439 /// 440 /// let x = ceed.vector_from_slice(&[0., 1., 2., 3.])?; 441 /// let mut y = ceed.vector(nelem * 2)?; 442 /// y.set_value(0.0); 443 /// 444 /// r.apply(TransposeMode::NoTranspose, &x, &mut y)?; 445 /// 446 /// for (i, y) in y.view()?.iter().enumerate() { 447 /// assert_eq!( 448 /// *y, 449 /// ((i + 1) / 2) as Scalar, 450 /// "Incorrect value in restricted vector" 451 /// ); 452 /// } 453 /// # Ok(()) 454 /// # } 455 /// ``` 456 pub fn apply(&self, tmode: TransposeMode, u: &Vector, ru: &mut Vector) -> crate::Result<i32> { 457 let tmode = tmode as bind_ceed::CeedTransposeMode; 458 self.check_error(unsafe { 459 bind_ceed::CeedElemRestrictionApply( 460 self.ptr, 461 tmode, 462 u.ptr, 463 ru.ptr, 464 bind_ceed::CEED_REQUEST_IMMEDIATE, 465 ) 466 }) 467 } 468 469 /// Returns the Lvector component stride 470 /// 471 /// ``` 472 /// # use libceed::prelude::*; 473 /// # fn main() -> libceed::Result<()> { 474 /// # let ceed = libceed::Ceed::default_init(); 475 /// let nelem = 3; 476 /// let compstride = 1; 477 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 478 /// for i in 0..nelem { 479 /// ind[2 * i + 0] = i as i32; 480 /// ind[2 * i + 1] = (i + 1) as i32; 481 /// } 482 /// let r = ceed.elem_restriction(nelem, 2, 1, compstride, nelem + 1, MemType::Host, &ind)?; 483 /// 484 /// let c = r.comp_stride(); 485 /// assert_eq!(c, compstride, "Incorrect component stride"); 486 /// # Ok(()) 487 /// # } 488 /// ``` 489 pub fn comp_stride(&self) -> usize { 490 let mut compstride = 0; 491 unsafe { bind_ceed::CeedElemRestrictionGetCompStride(self.ptr, &mut compstride) }; 492 usize::try_from(compstride).unwrap() 493 } 494 495 /// Returns the total number of elements in the range of a ElemRestriction 496 /// 497 /// ``` 498 /// # use libceed::prelude::*; 499 /// # fn main() -> libceed::Result<()> { 500 /// # let ceed = libceed::Ceed::default_init(); 501 /// let nelem = 3; 502 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 503 /// for i in 0..nelem { 504 /// ind[2 * i + 0] = i as i32; 505 /// ind[2 * i + 1] = (i + 1) as i32; 506 /// } 507 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 508 /// 509 /// let n = r.num_elements(); 510 /// assert_eq!(n, nelem, "Incorrect number of elements"); 511 /// # Ok(()) 512 /// # } 513 /// ``` 514 pub fn num_elements(&self) -> usize { 515 let mut numelem = 0; 516 unsafe { bind_ceed::CeedElemRestrictionGetNumElements(self.ptr, &mut numelem) }; 517 usize::try_from(numelem).unwrap() 518 } 519 520 /// Returns the size of elements in the ElemRestriction 521 /// 522 /// ``` 523 /// # use libceed::prelude::*; 524 /// # fn main() -> libceed::Result<()> { 525 /// # let ceed = libceed::Ceed::default_init(); 526 /// let nelem = 3; 527 /// let elem_size = 2; 528 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 529 /// for i in 0..nelem { 530 /// ind[2 * i + 0] = i as i32; 531 /// ind[2 * i + 1] = (i + 1) as i32; 532 /// } 533 /// let r = ceed.elem_restriction(nelem, elem_size, 1, 1, nelem + 1, MemType::Host, &ind)?; 534 /// 535 /// let e = r.elem_size(); 536 /// assert_eq!(e, elem_size, "Incorrect element size"); 537 /// # Ok(()) 538 /// # } 539 /// ``` 540 pub fn elem_size(&self) -> usize { 541 let mut elemsize = 0; 542 unsafe { bind_ceed::CeedElemRestrictionGetElementSize(self.ptr, &mut elemsize) }; 543 usize::try_from(elemsize).unwrap() 544 } 545 546 /// Returns the size of the Lvector for an ElemRestriction 547 /// 548 /// ``` 549 /// # use libceed::prelude::*; 550 /// # fn main() -> libceed::Result<()> { 551 /// # let ceed = libceed::Ceed::default_init(); 552 /// let nelem = 3; 553 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 554 /// for i in 0..nelem { 555 /// ind[2 * i + 0] = i as i32; 556 /// ind[2 * i + 1] = (i + 1) as i32; 557 /// } 558 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 559 /// 560 /// let lsize = r.lvector_size(); 561 /// assert_eq!(lsize, nelem + 1); 562 /// # Ok(()) 563 /// # } 564 /// ``` 565 pub fn lvector_size(&self) -> usize { 566 let mut lsize = 0; 567 unsafe { bind_ceed::CeedElemRestrictionGetLVectorSize(self.ptr, &mut lsize) }; 568 usize::try_from(lsize).unwrap() 569 } 570 571 /// Returns the number of components in the elements of an ElemRestriction 572 /// 573 /// ``` 574 /// # use libceed::prelude::*; 575 /// # fn main() -> libceed::Result<()> { 576 /// # let ceed = libceed::Ceed::default_init(); 577 /// let nelem = 3; 578 /// let ncomp = 42; 579 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 580 /// for i in 0..nelem { 581 /// ind[2 * i + 0] = i as i32; 582 /// ind[2 * i + 1] = (i + 1) as i32; 583 /// } 584 /// let r = ceed.elem_restriction(nelem, 2, 42, 1, ncomp * (nelem + 1), MemType::Host, &ind)?; 585 /// 586 /// let n = r.num_components(); 587 /// assert_eq!(n, ncomp, "Incorrect number of components"); 588 /// # Ok(()) 589 /// # } 590 /// ``` 591 pub fn num_components(&self) -> usize { 592 let mut ncomp = 0; 593 unsafe { bind_ceed::CeedElemRestrictionGetNumComponents(self.ptr, &mut ncomp) }; 594 usize::try_from(ncomp).unwrap() 595 } 596 597 /// Returns the multiplicity of nodes in an ElemRestriction 598 /// 599 /// ``` 600 /// # use libceed::prelude::*; 601 /// # fn main() -> libceed::Result<()> { 602 /// # let ceed = libceed::Ceed::default_init(); 603 /// let nelem = 3; 604 /// let mut ind: Vec<i32> = vec![0; 2 * nelem]; 605 /// for i in 0..nelem { 606 /// ind[2 * i + 0] = i as i32; 607 /// ind[2 * i + 1] = (i + 1) as i32; 608 /// } 609 /// let r = ceed.elem_restriction(nelem, 2, 1, 1, nelem + 1, MemType::Host, &ind)?; 610 /// 611 /// let mut mult = ceed.vector(nelem + 1)?; 612 /// mult.set_value(0.0); 613 /// 614 /// r.multiplicity(&mut mult)?; 615 /// 616 /// for (i, m) in mult.view()?.iter().enumerate() { 617 /// assert_eq!( 618 /// *m, 619 /// if (i == 0 || i == nelem) { 1. } else { 2. }, 620 /// "Incorrect multiplicity value" 621 /// ); 622 /// } 623 /// # Ok(()) 624 /// # } 625 /// ``` 626 pub fn multiplicity(&self, mult: &mut Vector) -> crate::Result<i32> { 627 self.check_error(unsafe { 628 bind_ceed::CeedElemRestrictionGetMultiplicity(self.ptr, mult.ptr) 629 }) 630 } 631 } 632 633 // ----------------------------------------------------------------------------- 634