xref: /libCEED/rust/libceed/src/elem_restriction.rs (revision a71faab149de599cd7784196409e851b67144f0a)
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(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 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