ExaDG
Loading...
Searching...
No Matches
hypercube_resolution_parameters.h
1/* ______________________________________________________________________
2 *
3 * ExaDG - High-Order Discontinuous Galerkin for the Exa-Scale
4 *
5 * Copyright (C) 2021 by the ExaDG authors
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * ______________________________________________________________________
20 */
21
22#ifndef EXADG_OPERATORS_HYPERCUBE_RESOLUTION_PARAMETERS_H_
23#define EXADG_OPERATORS_HYPERCUBE_RESOLUTION_PARAMETERS_H_
24
25// deal.II
26#include <deal.II/base/parameter_handler.h>
27
28// ExaDG
29#include <exadg/grid/grid_data.h>
30#include <exadg/utilities/enum_patterns.h>
31
32namespace ExaDG
33{
34/*
35 * study throughput as a function of polynomial degree or problem size
36 */
37enum class RunType
38{
39 RefineHAndP, // run simulation for a specified range of mesh refinements and polynomial degrees
40 FixedProblemSize, // increase polynomial degree and keep problem size approximately constant
41 IncreasingProblemSize // run at fixed polynomial degree
42};
43
44/*
45 * Determines mesh refinement level l and number of subdivisions in 1d of hyper_cube mesh for a
46 * given number of minimal and maximal number of unknowns and a given RunType.
47 */
48inline void
49fill_resolutions_vector(
50 std::vector<
51 std::tuple<unsigned int /*k*/, unsigned int /*l*/, unsigned int /*subdivisions hypercube*/>> &
52 resolutions,
53 unsigned int const dim,
54 unsigned int const degree,
55 double const dofs_per_element,
56 dealii::types::global_dof_index const n_dofs_min,
57 dealii::types::global_dof_index const n_dofs_max,
58 RunType const & run_type,
59 ElementType const & element_type)
60{
61 unsigned int const resolutions_initial_size = resolutions.size();
62
63 double dofs_per_cube = dofs_per_element;
64
65 // in case of simplex elements, we create a mesh of hypercube elements that gets later subdivided
66 // into simplex elements using dealii::GridTools::subdivided_hyper_cube_with_simplices()
67 if(element_type == ElementType::Simplex)
68 {
69 unsigned int n_cells_per_cube = 1;
70
71 // Determine the number of simplex cells per hypercube cell
72 if(dim == 2)
73 n_cells_per_cube = 2;
74 else if(dim == 3)
75 n_cells_per_cube = 5;
76 else
77 AssertThrow(false, dealii::ExcMessage("not implemented."));
78
79 // From now on, we think of a hyerpcube mesh that gets later subdivided into simplex elements
80 // with n_cells_per_cube simplices per hypercube cell
81 dofs_per_cube *= n_cells_per_cube;
82 }
83
84 dealii::types::global_dof_index const n_cells_min =
85 static_cast<dealii::types::global_dof_index>((n_dofs_min + dofs_per_cube - 1) / dofs_per_cube);
86 dealii::types::global_dof_index const n_cells_max =
87 static_cast<dealii::types::global_dof_index>(n_dofs_max / dofs_per_cube);
88
89 // From the maximum number of cells, we derive a maximum refinement level for a uniformly refined
90 // mesh with one coarse-grid cells
91 unsigned int const refine_level_max =
92 int(std::log((double)n_cells_max) / std::log((double)dealii::Utilities::pow(2ULL, dim))) + 1;
93
94 // we start with the coarsest possible mesh and then increase the refine level by 1
95 // until we hit the maximum refinement level
96 unsigned int refine_level = 0;
97
98 // This loop is for a uniformly refined hypercube mesh. Inside the
99 // loop, we test whether additional combinations of coarse-grid cells and mesh refinement levels
100 // are suitable in terms of n_cells_min/n_cells_max. The reason behind is that we want to have
101 // more data points than just data points differing by a factor of 2^dim in the number of cells.
102 while(refine_level <= refine_level_max)
103 {
104 // To obtain additional data points, we test coarse grids with {3,4}^dim elements in 2D and
105 // {3,4,5}^dim elements in 3D. The cases with 3 and 5 subdivisions per coordinate direction are
106 // only relevant for refine_level >= 2.
107
108 // coarse grid with 3^dim cells, and refine_level-2 uniform refinements
109 if(refine_level >= 2)
110 {
111 unsigned int const n_subdivisions_1d = 3;
112 unsigned int const l = refine_level - 2;
113
114 unsigned int const n_cells =
115 dealii::Utilities::pow(n_subdivisions_1d, dim) * dealii::Utilities::pow(2ULL, l * dim);
116
117 if(n_cells >= n_cells_min and n_cells <= n_cells_max)
118 {
119 resolutions.push_back(
120 std::tuple<unsigned int, unsigned int, unsigned int>(degree, l, n_subdivisions_1d));
121
122 if(run_type == RunType::FixedProblemSize)
123 {
124 break;
125 }
126 }
127 }
128
129 // coarse grid with one cell and refine_level uniform refinements
130 {
131 unsigned int const n_subdivisions_1d = 1;
132 unsigned int const l = refine_level;
133
134 unsigned int const n_cells = dealii::Utilities::pow(2ULL, l * dim);
135
136 if(n_cells >= n_cells_min and n_cells <= n_cells_max)
137 {
138 resolutions.push_back(
139 std::tuple<unsigned int, unsigned int, unsigned int>(degree, l, n_subdivisions_1d));
140
141 if(run_type == RunType::FixedProblemSize)
142 {
143 break;
144 }
145 }
146 }
147
148 // coarse grid with 5^dim cells, and refine_level-2 uniform refinements
149 if(dim == 3 and refine_level >= 2)
150 {
151 unsigned int const n_subdivisions_1d = 5;
152 unsigned int const l = refine_level - 2;
153
154 unsigned int const n_cells =
155 dealii::Utilities::pow(n_subdivisions_1d, dim) * dealii::Utilities::pow(2ULL, l * dim);
156
157 if(n_cells >= n_cells_min and n_cells <= n_cells_max)
158 {
159 resolutions.push_back(
160 std::tuple<unsigned int, unsigned int, unsigned int>(degree, l, n_subdivisions_1d));
161
162 if(run_type == RunType::FixedProblemSize)
163 {
164 break;
165 }
166 }
167 }
168
169 // perform one global refinement
170 ++refine_level;
171 }
172
173 if(run_type == RunType::FixedProblemSize)
174 {
175 AssertThrow(resolutions.size() > resolutions_initial_size,
176 dealii::ExcMessage(
177 "No mesh found that meets the requirements regarding problem size. "
178 "Make sure that maximum number of dofs is sufficiently larger than "
179 "minimum number of dofs."));
180 }
181}
182
183struct HypercubeResolutionParameters
184{
185 HypercubeResolutionParameters()
186 {
187 }
188
189 HypercubeResolutionParameters(std::string const & input_file, unsigned int const dim) : dim(dim)
190 {
191 dealii::ParameterHandler prm;
192 add_parameters(prm);
193 prm.parse_input(input_file, "", true, true);
194
195 verify_parameters();
196 }
197
198 void
199 add_parameters(dealii::ParameterHandler & prm)
200 {
201 prm.enter_subsection("Resolution");
202 {
203 prm.add_parameter(
204 "RunType", run_type, "Type of throughput study.", Patterns::Enum<RunType>(), true);
205 prm.add_parameter(
206 "ElementType", element_type, "Type of elements.", Patterns::Enum<ElementType>(), true);
207 prm.add_parameter("DegreeMin",
208 degree_min,
209 "Minimal polynomial degree of shape functions.",
210 dealii::Patterns::Integer(1),
211 true);
212 prm.add_parameter("DegreeMax",
213 degree_max,
214 "Maximal polynomial degree of shape functions.",
215 dealii::Patterns::Integer(1),
216 true);
217 prm.add_parameter("RefineSpaceMin",
218 refine_space_min,
219 "Minimal number of mesh refinements.",
220 dealii::Patterns::Integer(0, 20),
221 true);
222 prm.add_parameter("RefineSpaceMax",
223 refine_space_max,
224 "Maximal number of mesh refinements.",
225 dealii::Patterns::Integer(0, 20),
226 true);
227 prm.add_parameter("DofsMin",
228 n_dofs_min,
229 "Minimal number of degrees of freedom.",
230 dealii::Patterns::Integer(1),
231 true);
232 prm.add_parameter("DofsMax",
233 n_dofs_max,
234 "Maximal number of degrees of freedom.",
235 dealii::Patterns::Integer(1),
236 true);
237 }
238 prm.leave_subsection();
239 }
240
241 void
242 verify_parameters()
243 {
244 if(run_type == RunType::RefineHAndP)
245 {
246 AssertThrow(degree_max >= degree_min, dealii::ExcMessage("Invalid parameters."));
247 AssertThrow(refine_space_max >= refine_space_min, dealii::ExcMessage("Invalid parameters."));
248 }
249 else if(run_type == RunType::FixedProblemSize)
250 {
251 AssertThrow(degree_max >= degree_min, dealii::ExcMessage("Invalid parameters."));
252 AssertThrow(n_dofs_max >= n_dofs_min, dealii::ExcMessage("Invalid parameters."));
253 }
254 else if(run_type == RunType::IncreasingProblemSize)
255 {
256 AssertThrow(
257 degree_min == degree_max,
258 dealii::ExcMessage(
259 "Only a single polynomial degree can be considered for RunType::IncreasingProblemSize"));
260
261 AssertThrow(n_dofs_max >= n_dofs_min, dealii::ExcMessage("Invalid parameters."));
262 }
263 else
264 {
265 AssertThrow(false, dealii::ExcMessage("not implemented."));
266 }
267 }
268
269 void
270 fill_resolution_vector(
271 std::function<double(unsigned int, unsigned int, ElementType)> const & get_dofs_per_element)
272 {
273 if(run_type == RunType::RefineHAndP)
274 {
275 unsigned int const n_cells_1d = 1;
276
277 // k-refinement
278 for(unsigned int degree = degree_min; degree <= degree_max; ++degree)
279 {
280 // h-refinement
281 for(unsigned int refine_space = refine_space_min; refine_space <= refine_space_max;
282 ++refine_space)
283 {
284 resolutions.push_back(
285 std::tuple<unsigned int, unsigned int, unsigned int>(degree, refine_space, n_cells_1d));
286 }
287 }
288 }
289 else if(run_type == RunType::FixedProblemSize or run_type == RunType::IncreasingProblemSize)
290 {
291 for(unsigned int degree = degree_min; degree <= degree_max; ++degree)
292 {
293 double dofs_per_element = get_dofs_per_element(dim, degree, element_type);
294 fill_resolutions_vector(resolutions,
295 dim,
296 degree,
297 dofs_per_element,
298 n_dofs_min,
299 n_dofs_max,
300 run_type,
301 element_type);
302 }
303 }
304 else
305 {
306 AssertThrow(false, dealii::ExcMessage("Not implemented."));
307 }
308 }
309
310 unsigned int dim = 2; // number of space dimensions
311
312 RunType run_type = RunType::RefineHAndP;
313
314 ElementType element_type = ElementType::Hypercube;
315
316 unsigned int degree_min = 3; // minimal polynomial degree
317 unsigned int degree_max = 3; // maximal polynomial degree
318
319 unsigned int refine_space_min = 0; // minimal number of global refinements
320 unsigned int refine_space_max = 0; // maximal number of global refinements
321
322 dealii::types::global_dof_index n_dofs_min = 1e4; // minimal number of unknowns
323 dealii::types::global_dof_index n_dofs_max = 3e4; // maximal number of unknowns
324
325 // a vector storing tuples of the form (degree k, refine level l, n_subdivisions_1d)
326 std::vector<std::tuple<unsigned int, unsigned int, unsigned int>> resolutions;
327};
328} // namespace ExaDG
329
330#endif /* EXADG_OPERATORS_HYPERCUBE_RESOLUTION_PARAMETERS_H_ */
Definition driver.cpp:33