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