PRISMS-PF  v2.1
userInputParameters.cc
Go to the documentation of this file.
1 // Methods for the userInputParameters class
2 #include "../../include/userInputParameters.h"
3 #include <deal.II/base/mpi.h>
4 #include <deal.II/base/utilities.h>
5 
6 template <int dim>
7 userInputParameters<dim>::userInputParameters(inputFileReader & input_file_reader, dealii::ParameterHandler & parameter_handler, variableAttributeLoader variable_attributes){
8 
9  loadVariableAttributes(variable_attributes);
10 
11  // Load the inputs into the class member variables
12 
13  // Meshing parameters
14  domain_size.push_back(parameter_handler.get_double("Domain size X"));
15  if (dim > 1){
16  domain_size.push_back(parameter_handler.get_double("Domain size Y"));
17  if (dim > 2){
18  domain_size.push_back(parameter_handler.get_double("Domain size Z"));
19  }
20  }
21 
22  subdivisions.push_back(parameter_handler.get_integer("Subdivisions X"));
23  if (dim > 1){
24  subdivisions.push_back(parameter_handler.get_integer("Subdivisions Y"));
25  if (dim > 2){
26  subdivisions.push_back(parameter_handler.get_integer("Subdivisions Z"));
27  }
28  }
29 
30  refine_factor = parameter_handler.get_integer("Refine factor");
31 
32  degree = parameter_handler.get_integer("Element degree");
33 
34  // Adaptive meshing parameters
35  h_adaptivity = parameter_handler.get_bool("Mesh adaptivity");
36  max_refinement_level = parameter_handler.get_integer("Max refinement level");
37  min_refinement_level = parameter_handler.get_integer("Min refinement level");
38 
39  // Enforce that the initial refinement level must be between the max and min level
40  if (h_adaptivity && ((refine_factor < min_refinement_level) || (refine_factor > max_refinement_level))){
41  std::cerr << "PRISMS-PF Error: The initial refinement factor must be between the maximum and minimum refinement levels when adaptive meshing is enabled." << std::endl;
42  std::cerr << "Initial refinement level: " << refine_factor << " Maximum and minimum refinement levels: " << max_refinement_level << ", " << min_refinement_level << std::endl;
43  abort();
44  }
45 
46  // Use built-in deal.II utilities to split up a string and convert it to a vector of doubles or ints
47  std::vector<std::string> refine_criterion_fields_str = dealii::Utilities::split_string_list(parameter_handler.get("Refinement criteria fields"));
48  for (unsigned int ref_field=0; ref_field<refine_criterion_fields_str.size(); ref_field++){
49  bool field_found = false;
50  for (unsigned int i=0; i<number_of_variables; i++ ){
51  if (boost::iequals(refine_criterion_fields_str[ref_field], variable_attributes.var_name_list[i].second)){
52  refine_criterion_fields.push_back(variable_attributes.var_name_list[i].first);
53  field_found = true;
54  break;
55  }
56  }
57  if (field_found == false && h_adaptivity == true){
58  std::cerr << "PRISMS-PF Error: Entries in the list of fields used for refinement must match the variable names in equations.h." << std::endl;
59  std::cerr << refine_criterion_fields_str[ref_field] << std::endl;
60  abort();
61  }
62  }
63  refine_window_max = dealii::Utilities::string_to_double(dealii::Utilities::split_string_list(parameter_handler.get("Refinement window max")));
64  refine_window_min = dealii::Utilities::string_to_double(dealii::Utilities::split_string_list(parameter_handler.get("Refinement window min")));
65 
66  skip_remeshing_steps = parameter_handler.get_integer("Steps between remeshing operations");
67 
68  // Time stepping parameters
69  dtValue = parameter_handler.get_double("Time step");
70  int totalIncrements_temp = parameter_handler.get_integer("Number of time steps");
71  finalTime = parameter_handler.get_double("Simulation end time");
72 
73  // Linear solver parameters
74  for (unsigned int i=0; i<number_of_variables; i++){
75  if (input_file_reader.var_eq_types.at(i) == TIME_INDEPENDENT || input_file_reader.var_eq_types.at(i) == IMPLICIT_TIME_DEPENDENT){
76  std::string subsection_text = "Linear solver parameters: ";
77  subsection_text.append(input_file_reader.var_names.at(i));
78 
79  parameter_handler.enter_subsection(subsection_text);
80  {
81  // Set the tolerance type
82  SolverToleranceType temp_type;
83  std::string type_string = parameter_handler.get("Tolerance type");
84  if (boost::iequals(type_string,"ABSOLUTE_RESIDUAL")){
85  temp_type = ABSOLUTE_RESIDUAL;
86  }
87  else if (boost::iequals(type_string,"RELATIVE_RESIDUAL_CHANGE")){
88  temp_type = RELATIVE_RESIDUAL_CHANGE;
89  }
90  else if (boost::iequals(type_string,"ABSOLUTE_SOLUTION_CHANGE")){
91  temp_type = ABSOLUTE_SOLUTION_CHANGE;
92  std::cerr << "PRISMS-PF Error: Linear solver tolerance type " << type_string << " is not currently implemented, please use either ABSOLUTE_RESIDUAL or RELATIVE_RESIDUAL_CHANGE" << std::endl;
93  abort();
94  }
95  else {
96  std::cerr << "PRISMS-PF Error: Linear solver tolerance type " << type_string << " is not one of the allowed values (ABSOLUTE_RESIDUAL, RELATIVE_RESIDUAL_CHANGE, ABSOLUTE_SOLUTION_CHANGE)" << std::endl;
97  abort();
98  }
99 
100  // Set the tolerance value
101  double temp_value = parameter_handler.get_double("Tolerance value");
102 
103  // Set the maximum number of iterations
104  unsigned int temp_max_iterations = parameter_handler.get_integer("Maximum linear solver iterations");
105 
106  linear_solver_parameters.loadParameters(i,temp_type,temp_value,temp_max_iterations);
107  }
108  parameter_handler.leave_subsection();
109  }
110  }
111 
112 
113  // Non-linear solver parameters
114  std::vector<bool> var_nonlinear = variable_attributes.var_nonlinear;
115 
116  nonlinear_solver_parameters.setMaxIterations(parameter_handler.get_integer("Maximum nonlinear solver iterations"));
117 
118  for (unsigned int i=0; i<var_nonlinear.size(); i++){
119  if (var_nonlinear.at(i)){
120  std::string subsection_text = "Nonlinear solver parameters: ";
121  subsection_text.append(input_file_reader.var_names.at(i));
122 
123  parameter_handler.enter_subsection(subsection_text);
124  {
125  // Set the tolerance type
126  SolverToleranceType temp_type;
127  std::string type_string = parameter_handler.get("Tolerance type");
128  if (boost::iequals(type_string,"ABSOLUTE_RESIDUAL")){
129  temp_type = ABSOLUTE_RESIDUAL;
130  }
131  else if (boost::iequals(type_string,"RELATIVE_RESIDUAL_CHANGE")){
132  temp_type = RELATIVE_RESIDUAL_CHANGE;
133  }
134  else if (boost::iequals(type_string,"ABSOLUTE_SOLUTION_CHANGE")){
135  temp_type = ABSOLUTE_SOLUTION_CHANGE;
136  }
137  else {
138  std::cerr << "PRISMS-PF Error: Nonlinear solver tolerance type " << type_string << " is not one of the allowed values (ABSOLUTE_RESIDUAL, RELATIVE_RESIDUAL_CHANGE, ABSOLUTE_SOLUTION_CHANGE)" << std::endl;
139  abort();
140  }
141 
142  // Set the tolerance value
143  double temp_value = parameter_handler.get_double("Tolerance value");
144 
145  // Set the backtrace damping flag
146  bool temp_backtrack_damping = parameter_handler.get_bool("Use backtracking line search damping");
147 
148  // Set the backtracking step size modifier
149  double temp_step_modifier = parameter_handler.get_double("Backtracking step size modifier");
150 
151  // Set the constant that determines how much the residual must decrease to be accepted as sufficient
152  double temp_residual_decrease_coeff = parameter_handler.get_double("Backtracking residual decrease coefficient");
153 
154  // Set the default damping coefficient (used if backtracking isn't used)
155  double temp_damping_coefficient = parameter_handler.get_double("Constant damping value");
156 
157  // Set whether to use the solution of Laplace's equation instead of the IC in ICs_and_BCs.h as the initial guess for nonlinear, time independent equations
158  bool temp_laplace_for_initial_guess;
159  if (var_eq_type[i] == TIME_INDEPENDENT){
160  temp_laplace_for_initial_guess = parameter_handler.get_bool("Use Laplace's equation to determine the initial guess");
161  }
162  else {
163  temp_laplace_for_initial_guess = false;
164  if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0){
165  std::cout << "PRISMS-PF Warning: Laplace's equation is only used to generate the initial guess for time independent equations. The equation for variable " << var_name[i] << " is not a time independent equation. No initial guess is needed for this equation." << std::endl;
166  }
167  }
168 
169  nonlinear_solver_parameters.loadParameters(i,temp_type,temp_value,temp_backtrack_damping,temp_step_modifier,temp_residual_decrease_coeff,temp_damping_coefficient,temp_laplace_for_initial_guess);
170  }
171  parameter_handler.leave_subsection();
172  }
173  }
174 
175  // Set the max number of nonlinear iterations
176  if (var_nonlinear.size() == 0){
177  nonlinear_solver_parameters.setMaxIterations(0);
178  }
179 
180  // Output parameters
181  std::string output_condition = parameter_handler.get("Output condition");
182  unsigned int num_outputs = parameter_handler.get_integer("Number of outputs");
183  std::vector<int> user_given_time_step_list_temp = dealii::Utilities::string_to_int(dealii::Utilities::split_string_list(parameter_handler.get("List of time steps to output")));
184  std::vector<unsigned int> user_given_time_step_list;
185  for (unsigned int i=0; i<user_given_time_step_list_temp.size(); i++) user_given_time_step_list.push_back(user_given_time_step_list_temp[i]);
186 
187  skip_print_steps = parameter_handler.get_integer("Skip print steps");
188  output_file_type = parameter_handler.get("Output file type");
189  output_file_name = parameter_handler.get("Output file name (base)");
190 
191  output_vtu_per_process = parameter_handler.get_bool("Output separate files per process");
192  if ((output_file_type == "vtk") && (!output_vtu_per_process)){
193  output_vtu_per_process = true;
194  if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0){
195  std::cout << "PRISMS-PF Warning: 'Output file type' given as 'vtk' and 'Output separate files per process' given as 'false'. Shared output files are not supported for the vtk output format. Separate files per process will be created." << std::endl;
196  }
197  }
198 
199  // Field variable definitions
200 
201  // If all of the variables are ELLIPTIC, then totalIncrements should be 1 and finalTime should be 0
202  bool only_time_independent_pdes = true;
203  for (unsigned int i=0; i<var_eq_type.size(); i++){
204  if (var_eq_type.at(i) == EXPLICIT_TIME_DEPENDENT || var_eq_type.at(i) == IMPLICIT_TIME_DEPENDENT){
205  only_time_independent_pdes = false;
206  break;
207  }
208  }
209 
210  // Determine the maximum number of time steps
211  if (only_time_independent_pdes){
212  totalIncrements = 1;
213  finalTime = 0.0;
214  }
215  else{
216  if ((totalIncrements_temp >= 0) && (finalTime >= 0.0)) {
217  if (std::ceil(finalTime/dtValue) > totalIncrements_temp) {
218  totalIncrements = totalIncrements_temp;
219  finalTime = totalIncrements*dtValue;
220  }
221  else {
222  totalIncrements = std::ceil(finalTime/dtValue);
223  }
224  }
225  else if ((totalIncrements_temp >= 0) && (finalTime < 0.0)) {
226  totalIncrements = totalIncrements_temp;
227  finalTime = totalIncrements*dtValue;
228  }
229  else if ((totalIncrements_temp < 0) && (finalTime >= 0.0)) {
230  totalIncrements = std::ceil(finalTime/dtValue);
231  }
232  else {
233  // Should change to an exception
234  std::cerr << "Invalid selections for the final time and the number of increments. At least one should be given in the input file and should be positive." << std::endl;
235  std::cout << finalTime << " " << totalIncrements_temp << std::endl;
236  abort();
237  }
238  }
239 
240 
241  // Use these inputs to create a list of time steps where the code should output, stored in the member
242  outputTimeStepList = setTimeStepList(output_condition, num_outputs,user_given_time_step_list);
243 
244  // Variables for loading in PField ICs
245  std::vector<std::string> load_ICs_temp = dealii::Utilities::split_string_list(parameter_handler.get("Load initial conditions"));
246  std::vector<std::string> load_parallel_file_temp = dealii::Utilities::split_string_list(parameter_handler.get("Load parallel file"));
247 
248  if (boost::iequals(load_ICs_temp.at(0),"void")){
249  for (unsigned int var=0; var<number_of_variables; var++){
250  load_ICs.push_back(false);
251  load_parallel_file.push_back(false);
252  }
253  }
254  else {
255  for (unsigned int var=0; var<number_of_variables; var++){
256  if (boost::iequals(load_ICs_temp.at(var),"true")){
257  load_ICs.push_back(true);
258  }
259  else {
260  load_ICs.push_back(false);
261  }
262  if (boost::iequals(load_parallel_file_temp.at(var),"true")){
263  load_parallel_file.push_back(true);
264  }
265  else {
266  load_parallel_file.push_back(false);
267  }
268  }
269  }
270 
271  load_file_name = dealii::Utilities::split_string_list(parameter_handler.get("File names"));
272  load_field_name = dealii::Utilities::split_string_list(parameter_handler.get("Variable names in the files"));
273 
274  // Parameters for checkpoint/restart
275  resume_from_checkpoint = parameter_handler.get_bool("Load from a checkpoint");
276  std::string checkpoint_condition = parameter_handler.get("Checkpoint condition");
277  unsigned int num_checkpoints = parameter_handler.get_integer("Number of checkpoints");
278 
279  std::vector<int> user_given_checkpoint_time_step_list_temp = dealii::Utilities::string_to_int(dealii::Utilities::split_string_list(parameter_handler.get("List of time steps to save checkpoints")));
280  std::vector<unsigned int> user_given_checkpoint_time_step_list;
281  for (unsigned int i=0; i<user_given_checkpoint_time_step_list_temp.size(); i++) user_given_checkpoint_time_step_list.push_back(user_given_checkpoint_time_step_list_temp[i]);
282 
283  checkpointTimeStepList = setTimeStepList(checkpoint_condition, num_checkpoints,user_given_checkpoint_time_step_list);
284 
285  // Parameters for nucleation
286 
287  for (unsigned int i=0; i<input_file_reader.var_types.size(); i++){
288  if (input_file_reader.var_nucleates.at(i)){
289  std::string nucleation_text = "Nucleation parameters: ";
290  nucleation_text.append(input_file_reader.var_names.at(i));
291 
292  parameter_handler.enter_subsection(nucleation_text);
293  {
294  unsigned int var_index = i;
295  std::vector<double> semiaxes = dealii::Utilities::string_to_double(dealii::Utilities::split_string_list(parameter_handler.get("Nucleus semiaxes (x, y, z)")));
296  std::vector<double> ellipsoid_rotation = dealii::Utilities::string_to_double(dealii::Utilities::split_string_list(parameter_handler.get("Nucleus rotation in degrees (x, y, z)")));
297  std::vector<double> freeze_semiaxes = dealii::Utilities::string_to_double(dealii::Utilities::split_string_list(parameter_handler.get("Freeze zone semiaxes (x, y, z)")));
298  double hold_time = parameter_handler.get_double("Freeze time following nucleation");
299  double no_nucleation_border_thickness = parameter_handler.get_double("Nucleation-free border thickness");
300 
301  nucleationParameters<dim> temp(var_index,semiaxes,freeze_semiaxes,ellipsoid_rotation,hold_time,no_nucleation_border_thickness);
302  nucleation_parameters_list.push_back(temp);
303 
304  // Validate nucleation input
305  if (semiaxes.size() < dim || semiaxes.size() > 3){
306  std::cerr << "PRISMS-PF Error: The number of nucleus semiaxes given in the 'parameters.in' file must be at least the number of dimensions and no more than 3." << std::endl;
307  abort();
308  }
309  if (freeze_semiaxes.size() < dim || freeze_semiaxes.size() > 3){
310  std::cerr << "PRISMS-PF Error: The number of nucleation freeze zone semiaxes given in the 'parameters.in' file must be at least the number of dimensions and no more than 3." << std::endl;
311  abort();
312  }
313  if (ellipsoid_rotation.size() != 3){
314  std::cerr << "PRISMS-PF Error: Exactly three nucleus rotation angles must be given in the 'parameters.in' file." << std::endl;
315  abort();
316  }
317  }
318  parameter_handler.leave_subsection();
319 
320  }
321  }
322  for (unsigned int i=0; i<nucleation_parameters_list.size(); i++){
323  nucleation_parameters_list_index[nucleation_parameters_list.at(i).var_index] = i;
324  }
325 
326 
327  if (parameter_handler.get("Minimum allowed distance between nuclei") != "-1"){
328  min_distance_between_nuclei = parameter_handler.get_double("Minimum allowed distance between nuclei");
329  }
330  else if (nucleation_parameters_list.size() > 1) {
331  min_distance_between_nuclei = 2.0 * (*(max_element(nucleation_parameters_list[0].semiaxes.begin(),nucleation_parameters_list[0].semiaxes.end())));
332  }
333  nucleation_order_parameter_cutoff = parameter_handler.get_double("Order parameter cutoff value");
334  steps_between_nucleation_attempts = parameter_handler.get_integer("Time steps between nucleation attempts");
335 
336  // Load the grain remapping parameters
337  grain_remapping_activated = parameter_handler.get_bool("Activate grain reassignment");
338 
339  skip_grain_reassignment_steps = parameter_handler.get_integer("Time steps between grain reassignments");
340 
341  order_parameter_threshold = parameter_handler.get_double("Order parameter cutoff for grain identification");
342 
343  buffer_between_grains = parameter_handler.get_double("Buffer between grains before reassignment");
344  if (buffer_between_grains < 0.0 && grain_remapping_activated == true){
345  std::cerr << "PRISMS-PF Error: If grain reassignment is activated, a non-negative buffer distance must be given. See the 'Buffer between grains before reassignment' entry in parameters.in." << std::endl;
346  abort();
347  }
348 
349  std::vector<std::string> variables_for_remapping_str = dealii::Utilities::split_string_list(parameter_handler.get("Order parameter fields for grain reassignment"));
350  for (unsigned int field=0; field<variables_for_remapping_str.size(); field++){
351  bool field_found = false;
352  for (unsigned int i=0; i<number_of_variables; i++ ){
353  if (boost::iequals(variables_for_remapping_str[field], variable_attributes.var_name_list[i].second)){
354  variables_for_remapping.push_back(variable_attributes.var_name_list[i].first);
355  field_found = true;
356  break;
357  }
358  }
359  if (field_found == false && grain_remapping_activated == true){
360  std::cerr << "PRISMS-PF Error: Entries in the list of order parameter fields used for grain reassignment must match the variable names in equations.h." << std::endl;
361  std::cerr << variables_for_remapping_str[field] << std::endl;
362  abort();
363  }
364  }
365 
366  load_grain_structure = parameter_handler.get_bool("Load grain structure");
367  grain_structure_filename = parameter_handler.get("Grain structure filename");
368  grain_structure_variable_name = parameter_handler.get("Grain structure variable name");
369  num_grain_smoothing_cycles = parameter_handler.get_integer("Number of smoothing cycles after grain structure loading");
370  min_radius_for_loading_grains = parameter_handler.get_double("Minimum radius for loaded grains");
371 
372  // Load the boundary condition variables into list of BCs (where each element of the vector is one component of one variable)
373  std::vector<std::string> list_of_BCs;
374  for (unsigned int i=0; i<number_of_variables; i++){
375  if (var_type[i] == SCALAR){
376  std::string bc_text = "Boundary condition for variable ";
377  bc_text.append(var_name.at(i));
378  list_of_BCs.push_back(parameter_handler.get(bc_text));
379  }
380  else {
381  std::string bc_text = "Boundary condition for variable ";
382  bc_text.append(var_name.at(i));
383  bc_text.append(", x component");
384  list_of_BCs.push_back(parameter_handler.get(bc_text));
385 
386  bc_text = "Boundary condition for variable ";
387  bc_text.append(var_name.at(i));
388  bc_text.append(", y component");
389  list_of_BCs.push_back(parameter_handler.get(bc_text));
390 
391  bc_text = "Boundary condition for variable ";
392  bc_text.append(var_name.at(i));
393  bc_text.append(", z component");
394  list_of_BCs.push_back(parameter_handler.get(bc_text));
395  }
396  }
397 
398  // Load the BC information from the strings into a varBCs object
399  load_BC_list(list_of_BCs);
400 
401  // Load the user-defined constants
402  load_user_constants(input_file_reader,parameter_handler);
403 }
404 
405 
406 // Template instantiations
407 #include "../../include/userInputParameters_template_instantiations.h"
std::vector< std::pair< unsigned int, std::string > > var_name_list
std::vector< PDEType > var_eq_types
std::vector< fieldType > var_types
std::vector< bool > var_nonlinear
userInputParameters(inputFileReader &input_file_reader, dealii::ParameterHandler &parameter_handler, variableAttributeLoader variable_attributes)
SolverToleranceType
std::vector< std::string > var_names
std::vector< bool > var_nucleates