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