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