1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2009 - 2020 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_fe_component_mask_h
17 #define dealii_fe_component_mask_h
18 
19 #include <deal.II/base/config.h>
20 
21 #include <deal.II/base/exceptions.h>
22 #include <deal.II/base/memory_consumption.h>
23 
24 #include <algorithm>
25 #include <iosfwd>
26 #include <vector>
27 
28 DEAL_II_NAMESPACE_OPEN
29 
30 
31 
32 /**
33  * This class represents a mask that can be used to select individual vector
34  * components of a finite element (see also
35  * @ref GlossComponentMask "this glossary entry").
36  * It will typically have as many elements as the finite element has vector
37  * components, and one can use <code>operator[]</code> to query whether a
38  * particular component has been selected.
39  *
40  * @note A "mask" represents a data structure with @p true and @p false
41  *   entries that is generally used to enable or disable an operation
42  *   for a particular vector component. By this definition, disabled
43  *   vector components still exist -- they are simply not touched. As
44  *   a consequence, when you apply a component mask for interpolating
45  *   boundary values (to choose just one example) of a problem with
46  *   $C$ vector components, the input argument that describes the
47  *   boundary values will still have to provide $C$ components even
48  *   if the mask says that we only want to interpolate a subset of
49  *   these components onto the finite element space. In other words,
50  *   a component mask does not represent a <i>reduction</i> operation;
51  *   it represents a <i>selection</i>.
52  *
53  * Objects of this kind are used in many places where one wants to restrict
54  * operations to a certain subset of components, e.g. in
55  * DoFTools::make_zero_boundary_values() or
56  * VectorTools::interpolate_boundary_values(). These objects can either be
57  * created by hand, or, simpler, by asking the finite element to generate a
58  * component mask from certain selected components using code such as this
59  * where we create a mask that only denotes the velocity components of a
60  * Stokes element (see
61  * @ref vector_valued):
62  * @code
63  *   // Q2 element for the velocities, Q1 element for the pressure
64  *   FESystem<dim> stokes_fe (FE_Q<dim>(2), dim,
65  *                            FE_Q<dim>(1), 1);
66  *   FEValuesExtractors::Scalar pressure(dim);
67  *   ComponentMask pressure_mask = stokes_fe.component_mask (pressure);
68  * @endcode
69  * The result is a component mask that, in 2d, would have values <code>[false,
70  * false, true]</code>. Similarly, using
71  * @code
72  *   FEValuesExtractors::Vector velocities(0);
73  *   ComponentMask velocity_mask = stokes_fe.component_mask (velocities);
74  * @endcode
75  * would result in a mask <code>[true, true, false]</code> in 2d. Of course,
76  * in 3d, the result would be <code>[true, true, true, false]</code>.
77  *
78  * @ingroup fe
79  * @ingroup vector_valued
80  */
81 class ComponentMask
82 {
83 public:
84   /**
85    * Initialize a component mask. The default is that a component mask
86    * represents a set of components that are <i>all</i> selected, i.e.,
87    * calling this constructor results in a component mask that always returns
88    * <code>true</code> whenever asked whether a component is selected.
89    */
90   ComponentMask() = default;
91 
92   /**
93    * Initialize an object of this type with a set of selected components
94    * specified by the argument.
95    *
96    * @param component_mask A vector of <code>true/false</code> entries that
97    * determine which components of a finite element are selected. If the
98    * length of the given vector is zero, then this interpreted as the case
99    * where <i>every</i> component is selected.
100    */
101   ComponentMask(const std::vector<bool> &component_mask);
102 
103   /**
104    * Initialize the component mask with a number of elements that are either
105    * all true or false.
106    *
107    * @param n_components The number of elements of this mask
108    * @param initializer The value each of these elements is supposed to have:
109    * either true or false.
110    */
111   ComponentMask(const unsigned int n_components, const bool initializer);
112 
113   /**
114    * Set a particular entry in the mask to a value.
115    */
116   void
117   set(const unsigned int index, const bool value);
118 
119   /**
120    * If this component mask has been initialized with a mask of size greater
121    * than zero, then return the size of the mask represented by this object.
122    * On the other hand, if this mask has been initialized as an empty object
123    * that represents a mask that is true for every element (i.e., if this
124    * object would return true when calling represents_the_all_selected_mask())
125    * then return zero since no definite size is known.
126    */
127   unsigned int
128   size() const;
129 
130   /**
131    * Return whether a particular component is selected by this mask. If this
132    * mask represents the case of an object that selects <i>all components</i>
133    * (e.g. if it is created using the default constructor or is converted from
134    * an empty vector of type bool) then this function returns true regardless
135    * of the given argument.
136    *
137    * @param component_index The index for which the function should return
138    * whether the component is selected. If this object represents a mask in
139    * which all components are always selected then any index is allowed here.
140    * Otherwise, the given index needs to be between zero and the number of
141    * components that this mask represents.
142    */
143   bool operator[](const unsigned int component_index) const;
144 
145   /**
146    * Return whether this component mask represents a mask with exactly
147    * <code>n</code> components. This is true if either it was initialized with
148    * a vector with exactly <code>n</code> entries of type <code>bool</code>
149    * (in this case, @p n must equal the result of size()) or if it was
150    * initialized with an empty vector (or using the default constructor) in
151    * which case it can represent a mask with an arbitrary number of components
152    * and will always say that a component is selected.
153    */
154   bool
155   represents_n_components(const unsigned int n) const;
156 
157   /**
158    * Return the number of components that are selected by this mask.
159    *
160    * Since empty component masks represent a component mask that would return
161    * <code>true</code> for every component, this function may not know the
162    * true size of the component mask and it therefore requires an argument
163    * that denotes the overall number of components.
164    *
165    * If the object has been initialized with a non-empty mask (i.e., if the
166    * size() function returns something greater than zero, or equivalently if
167    * represents_the_all_selected_mask() returns false) then the argument can
168    * be omitted and the result of size() is taken.
169    */
170   unsigned int
171   n_selected_components(const unsigned int overall_number_of_components =
172                           numbers::invalid_unsigned_int) const;
173 
174   /**
175    * Return the index of the first selected component. The argument is there
176    * for the same reason it exists with the n_selected_components() function.
177    *
178    * The function throws an exception if no component is selected at all.
179    */
180   unsigned int
181   first_selected_component(const unsigned int overall_number_of_components =
182                              numbers::invalid_unsigned_int) const;
183 
184   /**
185    * Return true if this mask represents a default constructed mask that
186    * corresponds to one in which all components are selected. If true, then
187    * the size() function will return zero.
188    */
189   bool
190   represents_the_all_selected_mask() const;
191 
192   /**
193    * Return a component mask that contains the union of the components
194    * selected by the current object and the one passed as an argument.
195    */
196   ComponentMask
197   operator|(const ComponentMask &mask) const;
198 
199   /**
200    * Return a component mask that has only those elements set that are set
201    * both in the current object as well as the one passed as an argument.
202    */
203   ComponentMask operator&(const ComponentMask &mask) const;
204 
205   /**
206    * Return whether this object and the argument are identical.
207    */
208   bool
209   operator==(const ComponentMask &mask) const;
210 
211   /**
212    * Return whether this object and the argument are not identical.
213    */
214   bool
215   operator!=(const ComponentMask &mask) const;
216 
217   /**
218    * Determine an estimate for the memory consumption (in bytes) of this
219    * object.
220    */
221   std::size_t
222   memory_consumption() const;
223 
224   /**
225    * Exception
226    */
227   DeclExceptionMsg(ExcNoComponentSelected,
228                    "The number of selected components in a mask "
229                    "must be greater than zero.");
230 
231 private:
232   /**
233    * The actual component mask.
234    */
235   std::vector<bool> component_mask;
236 
237   // make the output operator a friend so it can access
238   // the component_mask array
239   friend std::ostream &
240   operator<<(std::ostream &out, const ComponentMask &mask);
241 };
242 
243 
244 /**
245  * Write a component mask to an output stream. If the component mask
246  * represents one where all components are selected without specifying a
247  * particular size of the mask, then it writes the string <code>[all
248  * components selected]</code> to the stream. Otherwise, it prints the
249  * component mask in a form like <code>[true,true,true,false]</code>.
250  *
251  * @param out The stream to write to.
252  * @param mask The mask to write. @return A reference to the first argument.
253  */
254 std::ostream &
255 operator<<(std::ostream &out, const ComponentMask &mask);
256 
257 #ifndef DOXYGEN
258 // -------------------- inline functions ---------------------
259 
ComponentMask(const std::vector<bool> & component_mask)260 inline ComponentMask::ComponentMask(const std::vector<bool> &component_mask)
261   : component_mask(component_mask)
262 {}
263 
264 
ComponentMask(const unsigned int n_components,const bool initializer)265 inline ComponentMask::ComponentMask(const unsigned int n_components,
266                                     const bool         initializer)
267   : component_mask(n_components, initializer)
268 {}
269 
270 
271 inline unsigned int
size()272 ComponentMask::size() const
273 {
274   return component_mask.size();
275 }
276 
277 
278 inline void
set(const unsigned int index,const bool value)279 ComponentMask::set(const unsigned int index, const bool value)
280 {
281   AssertIndexRange(index, component_mask.size());
282   component_mask[index] = value;
283 }
284 
285 
286 inline bool ComponentMask::operator[](const unsigned int component_index) const
287 {
288   // if the mask represents the all-component mask
289   // then always return true
290   if (component_mask.size() == 0)
291     return true;
292   else
293     {
294       // otherwise check the validity of the index and
295       // return whatever is appropriate
296       AssertIndexRange(component_index, component_mask.size());
297       return component_mask[component_index];
298     }
299 }
300 
301 
302 inline bool
represents_n_components(const unsigned int n)303 ComponentMask::represents_n_components(const unsigned int n) const
304 {
305   return ((component_mask.size() == 0) || (component_mask.size() == n));
306 }
307 
308 
309 inline unsigned int
n_selected_components(const unsigned int n)310 ComponentMask::n_selected_components(const unsigned int n) const
311 {
312   if ((n != numbers::invalid_unsigned_int) && (size() > 0))
313     AssertDimension(n, size());
314 
315   const unsigned int real_n = (n != numbers::invalid_unsigned_int ? n : size());
316   if (component_mask.size() == 0)
317     return real_n;
318   else
319     {
320       AssertDimension(real_n, component_mask.size());
321       return std::count_if(component_mask.begin(),
322                            component_mask.end(),
323                            [](const bool selected) { return selected; });
324     }
325 }
326 
327 
328 inline unsigned int
first_selected_component(const unsigned int n)329 ComponentMask::first_selected_component(const unsigned int n) const
330 {
331   if ((n != numbers::invalid_unsigned_int) && (size() > 0))
332     AssertDimension(n, size());
333 
334   if (component_mask.size() == 0)
335     return 0;
336   else
337     {
338       for (unsigned int c = 0; c < component_mask.size(); ++c)
339         if (component_mask[c] == true)
340           return c;
341 
342       Assert(false, ExcMessage("No component is selected at all!"));
343       return numbers::invalid_unsigned_int;
344     }
345 }
346 
347 
348 
349 inline bool
represents_the_all_selected_mask()350 ComponentMask::represents_the_all_selected_mask() const
351 {
352   return (component_mask.size() == 0);
353 }
354 
355 
356 
357 inline ComponentMask
358 ComponentMask::operator|(const ComponentMask &mask) const
359 {
360   // if one of the two masks denotes the all-component mask,
361   // then return the other one
362   if (component_mask.size() == 0)
363     return mask;
364   else if (mask.component_mask.size() == 0)
365     return *this;
366   else
367     {
368       // if both masks have individual entries set, form
369       // the combination of the two
370       AssertDimension(component_mask.size(), mask.component_mask.size());
371       std::vector<bool> new_mask(component_mask.size());
372       for (unsigned int i = 0; i < component_mask.size(); ++i)
373         new_mask[i] = (component_mask[i] || mask.component_mask[i]);
374 
375       return new_mask;
376     }
377 }
378 
379 
380 inline ComponentMask ComponentMask::operator&(const ComponentMask &mask) const
381 {
382   // if one of the two masks denotes the all-component mask,
383   // then return the other one
384   if (component_mask.size() == 0)
385     return mask;
386   else if (mask.component_mask.size() == 0)
387     return *this;
388   else
389     {
390       // if both masks have individual entries set, form
391       // the combination of the two
392       AssertDimension(component_mask.size(), mask.component_mask.size());
393       std::vector<bool> new_mask(component_mask.size());
394       for (unsigned int i = 0; i < component_mask.size(); ++i)
395         new_mask[i] = (component_mask[i] && mask.component_mask[i]);
396 
397       return new_mask;
398     }
399 }
400 
401 
402 inline bool
403 ComponentMask::operator==(const ComponentMask &mask) const
404 {
405   return component_mask == mask.component_mask;
406 }
407 
408 
409 inline bool
410 ComponentMask::operator!=(const ComponentMask &mask) const
411 {
412   return component_mask != mask.component_mask;
413 }
414 #endif // DOXYGEN
415 
416 
417 DEAL_II_NAMESPACE_CLOSE
418 
419 #endif
420