1 
2 #include "femparameters.h"
3 
4 #include "libmesh/parsed_function.h"
5 #include "libmesh/zero_function.h"
6 #include "libmesh/auto_ptr.h" // libmesh_make_unique
7 
8 #include <unordered_set>
9 
10 using namespace libMesh;
11 
12 #define GETPOT_INPUT(A) { A = input(#A, A);                             \
13     variable_names.insert(#A);                                          \
14     const std::string stringval = input(#A, std::string());             \
15     variable_assignments.push_back(std::string(#A "=") + stringval); }
16 #define GETPOT_INT_INPUT(A) { A = input(#A, (int)A);                    \
17     variable_names.insert(#A);                                          \
18     const std::string stringval = input(#A, std::string());             \
19     variable_assignments.push_back(std::string(#A "=") + stringval); }
20 
21 #define GETPOT_REGISTER(A) {                                            \
22     variable_names.insert(#A);                                          \
23     std::string stringval = input(#A, std::string());                   \
24     variable_assignments.push_back(std::string(#A "=") + stringval); }
25 
FEMParameters(const Parallel::Communicator & comm_in)26 FEMParameters::FEMParameters(const Parallel::Communicator & comm_in) :
27   ParallelObject(comm_in),
28   initial_timestep(0), n_timesteps(100),
29   transient(true),
30   deltat_reductions(0),
31   timesolver_core("euler"),
32   solution_history_type("memory"),
33   end_time(std::numeric_limits<Real>::max()),
34   deltat(0.0001), timesolver_theta(0.5),
35   timesolver_maxgrowth(0.), timesolver_tolerance(0.),
36   timesolver_upper_tolerance(0.),
37   steadystate_tolerance(0.),
38   timesolver_norm(0, L2),
39 
40   dimension(2),
41   domaintype("square"), domainfile("mesh.xda"), elementtype("quad"),
42   elementorder(2),
43   domain_xmin(0.0), domain_ymin(0.0), domain_zmin(0.0),
44   domain_edge_width(1.0), domain_edge_length(1.0), domain_edge_height(1.0),
45   coarsegridx(1), coarsegridy(1), coarsegridz(1),
46   coarserefinements(0), extrarefinements(0),
47   mesh_redistribute_func("0"),
48 
49   mesh_partitioner_type("Default"),
50 
51   nelem_target(8000), global_tolerance(0.0),
52   refine_fraction(0.3), coarsen_fraction(0.3), coarsen_threshold(10),
53   max_adaptivesteps(1),
54   initial_adaptivesteps(0),
55 
56   write_interval(10),
57   write_gmv_error(false), write_tecplot_error(false),
58   write_exodus_error(false),
59   output_xda(false), output_xdr(false),
60   output_bz2(true), output_gz(true),
61   output_gmv(false), output_tecplot(false),
62   output_exodus(false), output_nemesis(false),
63 
64   system_types(0),
65 
66 #ifdef LIBMESH_ENABLE_PERIODIC
67   periodic_boundaries(0),
68 #endif
69 
70   run_simulation(true), run_postprocess(false),
71 
72   fe_family(1, "LAGRANGE"), fe_order(1, 1),
73   extra_quadrature_order(0),
74 
75   analytic_jacobians(true), verify_analytic_jacobians(0.0),
76   numerical_jacobian_h(TOLERANCE),
77   print_solution_norms(false), print_solutions(false),
78   print_residual_norms(false), print_residuals(false),
79   print_jacobian_norms(false), print_jacobians(false),
80   print_element_solutions(false),
81   print_element_residuals(false),
82   print_element_jacobians(false),
83 
84   use_petsc_snes(false),
85   time_solver_quiet(true), solver_quiet(true), solver_verbose(false),
86   reuse_preconditioner(true),
87   require_residual_reduction(true),
88   min_step_length(1e-5),
89   max_linear_iterations(200000), max_nonlinear_iterations(20),
90   relative_step_tolerance(1.e-7), relative_residual_tolerance(1.e-10),
91   absolute_residual_tolerance(1.e-10),
92   initial_linear_tolerance(1.e-3), minimum_linear_tolerance(TOLERANCE*TOLERANCE),
93   linear_tolerance_multiplier(1.e-3),
94 
95   initial_sobolev_order(1),
96   initial_extra_quadrature(0),
97   refine_uniformly(false),
98   indicator_type("kelly"), patch_reuse(true), sobolev_order(1)
99 {
100 }
101 
~FEMParameters()102 FEMParameters::~FEMParameters()
103 {
104   for (std::map<subdomain_id_type, FunctionBase<Number> *>::iterator
105          i = initial_conditions.begin(); i != initial_conditions.end();
106        ++i)
107     delete i->second;
108 
109   for (std::map<boundary_id_type, FunctionBase<Number> *>::iterator
110          i = dirichlet_conditions.begin(); i != dirichlet_conditions.end();
111        ++i)
112     delete i->second;
113 
114   for (std::map<boundary_id_type, FunctionBase<Number> *>::iterator
115          i = neumann_conditions.begin(); i != neumann_conditions.end();
116        ++i)
117     delete i->second;
118 
119   for (std::map<int,
120          std::map<boundary_id_type, FunctionBase<Number> *>
121          >::iterator
122          i = other_boundary_functions.begin(); i != other_boundary_functions.end();
123        ++i)
124     for (std::map<boundary_id_type, FunctionBase<Number> *>::iterator
125            j = i->second.begin(); j != i->second.end();
126          ++j)
127       delete j->second;
128 
129   for (std::map<int,
130          std::map<subdomain_id_type, FunctionBase<Number> *>
131          >::iterator
132          i = other_interior_functions.begin(); i != other_interior_functions.end();
133        ++i)
134     for (std::map<subdomain_id_type, FunctionBase<Number> *>::iterator
135            j = i->second.begin(); j != i->second.end();
136          ++j)
137       delete j->second;
138 }
139 
140 
new_function_base(const std::string & func_type,const std::string & func_value)141 std::unique_ptr<FunctionBase<Number>> new_function_base(const std::string & func_type,
142                                                         const std::string & func_value)
143 {
144   if (func_type == "parsed")
145     return libmesh_make_unique<ParsedFunction<Number>>(func_value);
146   else if (func_type == "zero")
147     return libmesh_make_unique<ZeroFunction<Number>>();
148   else
149     libmesh_not_implemented();
150 
151   return std::unique_ptr<FunctionBase<Number>>();
152 }
153 
154 
read(GetPot & input,const std::vector<std::string> * other_variable_names)155 void FEMParameters::read(GetPot & input,
156                          const std::vector<std::string> * other_variable_names)
157 {
158   std::vector<std::string> variable_assignments;
159   std::unordered_set<std::string> variable_names;
160   if (other_variable_names)
161     for (std::size_t i=0; i != other_variable_names->size(); ++i)
162       {
163         const std::string & name = (*other_variable_names)[i];
164         const std::string stringval = input(name, std::string());
165         variable_assignments.push_back(name + "=" + stringval);
166       }
167 
168   GETPOT_INT_INPUT(initial_timestep);
169   GETPOT_INT_INPUT(n_timesteps);
170   GETPOT_INPUT(transient);
171   GETPOT_INT_INPUT(deltat_reductions);
172   GETPOT_INPUT(timesolver_core);
173   GETPOT_INPUT(solution_history_type);
174   GETPOT_INPUT(end_time);
175   GETPOT_INPUT(deltat);
176   GETPOT_INPUT(timesolver_theta);
177   GETPOT_INPUT(timesolver_maxgrowth);
178   GETPOT_INPUT(timesolver_tolerance);
179   GETPOT_INPUT(timesolver_upper_tolerance);
180   GETPOT_INPUT(steadystate_tolerance);
181 
182   GETPOT_REGISTER(timesolver_norm);
183   const unsigned int n_timesolver_norm = input.vector_variable_size("timesolver_norm");
184   timesolver_norm.resize(n_timesolver_norm, L2);
185   for (unsigned int i=0; i != n_timesolver_norm; ++i)
186     {
187       int current_norm = 0; // L2
188       if (timesolver_norm[i] == H1)
189         current_norm = 1;
190       if (timesolver_norm[i] == H2)
191         current_norm = 2;
192       current_norm = input("timesolver_norm", current_norm, i);
193       if (current_norm == 0)
194         timesolver_norm[i] = L2;
195       else if (current_norm == 1)
196         timesolver_norm[i] = H1;
197       else if (current_norm == 2)
198         timesolver_norm[i] = H2;
199       else
200         timesolver_norm[i] = DISCRETE_L2;
201     }
202 
203 
204   GETPOT_INT_INPUT(dimension);
205   GETPOT_INPUT(domaintype);
206   GETPOT_INPUT(domainfile);
207   GETPOT_INPUT(elementtype);
208   GETPOT_INPUT(elementorder);
209   GETPOT_INPUT(domain_xmin);
210   GETPOT_INPUT(domain_ymin);
211   GETPOT_INPUT(domain_zmin);
212   GETPOT_INPUT(domain_edge_width);
213   GETPOT_INPUT(domain_edge_length);
214   GETPOT_INPUT(domain_edge_height);
215   GETPOT_INT_INPUT(coarsegridx);
216   GETPOT_INT_INPUT(coarsegridy);
217   GETPOT_INT_INPUT(coarsegridz);
218   GETPOT_INT_INPUT(coarserefinements);
219   GETPOT_INT_INPUT(extrarefinements);
220   GETPOT_INPUT(mesh_redistribute_func);
221 
222 
223   GETPOT_INPUT(mesh_partitioner_type);
224 
225 
226   GETPOT_INT_INPUT(nelem_target);
227   GETPOT_INPUT(global_tolerance);
228   GETPOT_INPUT(refine_fraction);
229   GETPOT_INPUT(coarsen_fraction);
230   GETPOT_INPUT(coarsen_threshold);
231   GETPOT_INT_INPUT(max_adaptivesteps);
232   GETPOT_INT_INPUT(initial_adaptivesteps);
233 
234 
235   GETPOT_INT_INPUT(write_interval);
236   GETPOT_INPUT(output_xda);
237   GETPOT_INPUT(output_xdr);
238   GETPOT_INPUT(output_gz);
239 #ifndef LIBMESH_HAVE_GZSTREAM
240   output_gz                   = false;
241 #endif
242   GETPOT_INPUT(output_bz2);
243 #ifndef LIBMESH_HAVE_BZ2
244   output_bz2                  = false;
245 #endif
246   GETPOT_INPUT(output_gmv);
247   GETPOT_INPUT(write_gmv_error);
248 #ifndef LIBMESH_HAVE_GMV
249   output_gmv                  = false;
250   write_gmv_error             = false;
251 #endif
252   GETPOT_INPUT(output_tecplot);
253   GETPOT_INPUT(write_tecplot_error);
254 #ifndef LIBMESH_HAVE_TECPLOT_API
255   output_tecplot              = false;
256   write_tecplot_error         = false;
257 #endif
258   GETPOT_INPUT(output_exodus);
259   GETPOT_INPUT(write_exodus_error);
260 #ifndef LIBMESH_HAVE_EXODUS_API
261   output_exodus                  = false;
262   write_exodus_error             = false;
263 #endif
264   GETPOT_INPUT(output_nemesis);
265 #ifndef LIBMESH_HAVE_NEMESIS_API
266   output_nemesis                  = false;
267 #endif
268 
269 
270   GETPOT_REGISTER(system_types);
271   const unsigned int n_system_types =
272     input.vector_variable_size("system_types");
273   if (n_system_types)
274     {
275       system_types.resize(n_system_types, "");
276       for (unsigned int i=0; i != n_system_types; ++i)
277         {
278           system_types[i] = input("system_types", system_types[i], i);
279         }
280     }
281 
282 
283 #ifdef LIBMESH_ENABLE_PERIODIC
284   GETPOT_REGISTER(periodic_boundaries);
285   const unsigned int n_periodic_bcs =
286     input.vector_variable_size("periodic_boundaries");
287 
288   if (n_periodic_bcs)
289     {
290       if (domaintype != "square" &&
291           domaintype != "cylinder" &&
292           domaintype != "file" &&
293           domaintype != "od2")
294         {
295           libMesh::out << "Periodic boundaries need rectilinear domains" << std::endl;;
296           libmesh_error();
297         }
298       for (unsigned int i=0; i != n_periodic_bcs; ++i)
299         {
300           const unsigned int myboundary =
301             input("periodic_boundaries", -1, i);
302           boundary_id_type pairedboundary = 0;
303           RealVectorValue translation_vector;
304           if (dimension == 2)
305             switch (myboundary)
306               {
307               case 0:
308                 pairedboundary = 2;
309                 translation_vector = RealVectorValue(0., domain_edge_length);
310                 break;
311               case 1:
312                 pairedboundary = 3;
313                 translation_vector = RealVectorValue(-domain_edge_width, 0);
314                 break;
315               default:
316                 libMesh::out << "Unrecognized periodic boundary id " <<
317                   myboundary << std::endl;;
318                 libmesh_error();
319               }
320           else if (dimension == 3)
321             switch (myboundary)
322               {
323               case 0:
324                 pairedboundary = 5;
325                 translation_vector = RealVectorValue(Real(0), Real(0), domain_edge_height);
326                 break;
327               case 1:
328                 pairedboundary = 3;
329                 translation_vector = RealVectorValue(Real(0), domain_edge_length, Real(0));
330                 break;
331               case 2:
332                 pairedboundary = 4;
333                 translation_vector = RealVectorValue(-domain_edge_width, Real(0), Real(0));
334                 break;
335               default:
336                 libMesh::out << "Unrecognized periodic boundary id " <<
337                   myboundary << std::endl;;
338                 libmesh_error();
339               }
340           periodic_boundaries.push_back(PeriodicBoundary(translation_vector));
341           periodic_boundaries[i].myboundary = cast_int<boundary_id_type>(myboundary);
342           periodic_boundaries[i].pairedboundary = pairedboundary;
343         }
344     }
345 #endif // LIBMESH_ENABLE_PERIODIC
346 
347   // Use std::string inputs so GetPot doesn't have to make a bunch
348   // of internal C string copies
349   std::string zero_string = "zero";
350   std::string empty_string = "";
351 
352   GETPOT_REGISTER(dirichlet_condition_types);
353   GETPOT_REGISTER(dirichlet_condition_values);
354   GETPOT_REGISTER(dirichlet_condition_boundaries);
355   GETPOT_REGISTER(dirichlet_condition_variables);
356 
357   const unsigned int n_dirichlet_conditions=
358     input.vector_variable_size("dirichlet_condition_types");
359 
360   if (n_dirichlet_conditions !=
361       input.vector_variable_size("dirichlet_condition_values"))
362     {
363       libMesh::out << "Error: " << n_dirichlet_conditions
364                    << " Dirichlet condition types does not match "
365                    << input.vector_variable_size("dirichlet_condition_values")
366                    << " Dirichlet condition values." << std::endl;
367 
368       libmesh_error();
369     }
370 
371   if (n_dirichlet_conditions !=
372       input.vector_variable_size("dirichlet_condition_boundaries"))
373     {
374       libMesh::out << "Error: " << n_dirichlet_conditions
375                    << " Dirichlet condition types does not match "
376                    << input.vector_variable_size("dirichlet_condition_boundaries")
377                    << " Dirichlet condition boundaries." << std::endl;
378 
379       libmesh_error();
380     }
381 
382   if (n_dirichlet_conditions !=
383       input.vector_variable_size("dirichlet_condition_variables"))
384     {
385       libMesh::out << "Error: " << n_dirichlet_conditions
386                    << " Dirichlet condition types does not match "
387                    << input.vector_variable_size("dirichlet_condition_variables")
388                    << " Dirichlet condition variables sets." << std::endl;
389 
390       libmesh_error();
391     }
392 
393   for (unsigned int dc=0; dc != n_dirichlet_conditions; ++dc)
394     {
395       const std::string func_type =
396         input("dirichlet_condition_types", zero_string, dc);
397 
398       const std::string func_value =
399         input("dirichlet_condition_values", empty_string, dc);
400 
401       const boundary_id_type func_boundary =
402         input("dirichlet_condition_boundaries", boundary_id_type(0), dc);
403 
404       dirichlet_conditions[func_boundary] =
405         (new_function_base(func_type, func_value).release());
406 
407       const std::string variable_set =
408         input("dirichlet_condition_variables", empty_string, dc);
409 
410       for (unsigned int i=0; i != variable_set.size(); ++i)
411         {
412           if (variable_set[i] == '1')
413             dirichlet_condition_variables[func_boundary].push_back(i);
414           else if (variable_set[i] != '0')
415             {
416               libMesh::out << "Unable to understand Dirichlet variable set"
417                            << variable_set << std::endl;
418               libmesh_error();
419             }
420         }
421     }
422 
423   GETPOT_REGISTER(neumann_condition_types);
424   GETPOT_REGISTER(neumann_condition_values);
425   GETPOT_REGISTER(neumann_condition_boundaries);
426   GETPOT_REGISTER(neumann_condition_variables);
427 
428   const unsigned int n_neumann_conditions=
429     input.vector_variable_size("neumann_condition_types");
430 
431   if (n_neumann_conditions !=
432       input.vector_variable_size("neumann_condition_values"))
433     {
434       libMesh::out << "Error: " << n_neumann_conditions
435                    << " Neumann condition types does not match "
436                    << input.vector_variable_size("neumann_condition_values")
437                    << " Neumann condition values." << std::endl;
438 
439       libmesh_error();
440     }
441 
442   if (n_neumann_conditions !=
443       input.vector_variable_size("neumann_condition_boundaries"))
444     {
445       libMesh::out << "Error: " << n_neumann_conditions
446                    << " Neumann condition types does not match "
447                    << input.vector_variable_size("neumann_condition_boundaries")
448                    << " Neumann condition boundaries." << std::endl;
449 
450       libmesh_error();
451     }
452 
453   if (n_neumann_conditions !=
454       input.vector_variable_size("neumann_condition_variables"))
455     {
456       libMesh::out << "Error: " << n_neumann_conditions
457                    << " Neumann condition types does not match "
458                    << input.vector_variable_size("neumann_condition_variables")
459                    << " Neumann condition variables sets." << std::endl;
460 
461       libmesh_error();
462     }
463 
464   for (unsigned int nc=0; nc != n_neumann_conditions; ++nc)
465     {
466       const std::string func_type =
467         input("neumann_condition_types", zero_string, nc);
468 
469       const std::string func_value =
470         input("neumann_condition_values", empty_string, nc);
471 
472       const boundary_id_type func_boundary =
473         input("neumann_condition_boundaries", boundary_id_type(0), nc);
474 
475       neumann_conditions[func_boundary] =
476         (new_function_base(func_type, func_value).release());
477 
478       const std::string variable_set =
479         input("neumann_condition_variables", empty_string, nc);
480 
481       for (unsigned int i=0; i != variable_set.size(); ++i)
482         {
483           if (variable_set[i] == '1')
484             neumann_condition_variables[func_boundary].push_back(i);
485           else if (variable_set[i] != '0')
486             {
487               libMesh::out << "Unable to understand Neumann variable set"
488                            << variable_set << std::endl;
489               libmesh_error();
490             }
491         }
492     }
493 
494   GETPOT_REGISTER(initial_condition_types);
495   GETPOT_REGISTER(initial_condition_values);
496   GETPOT_REGISTER(initial_condition_subdomains);
497 
498   const unsigned int n_initial_conditions=
499     input.vector_variable_size("initial_condition_types");
500 
501   if (n_initial_conditions !=
502       input.vector_variable_size("initial_condition_values"))
503     {
504       libMesh::out << "Error: " << n_initial_conditions
505                    << " initial condition types does not match "
506                    << input.vector_variable_size("initial_condition_values")
507                    << " initial condition values." << std::endl;
508 
509       libmesh_error();
510     }
511 
512   if (n_initial_conditions !=
513       input.vector_variable_size("initial_condition_subdomains"))
514     {
515       libMesh::out << "Error: " << n_initial_conditions
516                    << " initial condition types does not match "
517                    << input.vector_variable_size("initial_condition_subdomains")
518                    << " initial condition subdomains." << std::endl;
519 
520       libmesh_error();
521     }
522 
523   for (unsigned int i=0; i != n_initial_conditions; ++i)
524     {
525       const std::string func_type =
526         input("initial_condition_types", zero_string, i);
527 
528       const std::string func_value =
529         input("initial_condition_values", empty_string, i);
530 
531       const subdomain_id_type func_subdomain =
532         input("initial_condition_subdomains", subdomain_id_type(0), i);
533 
534       initial_conditions[func_subdomain] =
535         (new_function_base(func_type, func_value).release());
536     }
537 
538   GETPOT_REGISTER(other_interior_function_types);
539   GETPOT_REGISTER(other_interior_function_values);
540   GETPOT_REGISTER(other_interior_function_subdomains);
541   GETPOT_REGISTER(other_interior_function_ids);
542 
543   const unsigned int n_other_interior_functions =
544     input.vector_variable_size("other_interior_function_types");
545 
546   if (n_other_interior_functions !=
547       input.vector_variable_size("other_interior_function_values"))
548     {
549       libMesh::out << "Error: " << n_other_interior_functions
550                    << " other interior function types does not match "
551                    << input.vector_variable_size("other_interior_function_values")
552                    << " other interior function values." << std::endl;
553 
554       libmesh_error();
555     }
556 
557   if (n_other_interior_functions !=
558       input.vector_variable_size("other_interior_function_subdomains"))
559     {
560       libMesh::out << "Error: " << n_other_interior_functions
561                    << " other interior function types does not match "
562                    << input.vector_variable_size("other_interior_function_subdomains")
563                    << " other interior function subdomains." << std::endl;
564 
565       libmesh_error();
566     }
567 
568   if (n_other_interior_functions !=
569       input.vector_variable_size("other_interior_function_ids"))
570     {
571       libMesh::out << "Error: " << n_other_interior_functions
572                    << " other interior function types does not match "
573                    << input.vector_variable_size("other_interior_function_ids")
574                    << " other interior function ids." << std::endl;
575 
576       libmesh_error();
577     }
578 
579   for (unsigned int i=0; i != n_other_interior_functions; ++i)
580     {
581       const std::string func_type =
582         input("other_interior_function_types", zero_string, i);
583 
584       const std::string func_value =
585         input("other_interior_function_values", empty_string, i);
586 
587       const subdomain_id_type func_subdomain =
588         input("other_interior_condition_subdomains", subdomain_id_type(0), i);
589 
590       const int func_id =
591         input("other_interior_condition_ids", int(0), i);
592 
593       other_interior_functions[func_id][func_subdomain] =
594         (new_function_base(func_type, func_value).release());
595     }
596 
597   GETPOT_REGISTER(other_boundary_function_types);
598   GETPOT_REGISTER(other_boundary_function_values);
599   GETPOT_REGISTER(other_boundary_function_boundaries);
600   GETPOT_REGISTER(other_boundary_function_ids);
601 
602   const unsigned int n_other_boundary_functions =
603     input.vector_variable_size("other_boundary_function_types");
604 
605   if (n_other_boundary_functions !=
606       input.vector_variable_size("other_boundary_function_values"))
607     {
608       libMesh::out << "Error: " << n_other_boundary_functions
609                    << " other boundary function types does not match "
610                    << input.vector_variable_size("other_boundary_function_values")
611                    << " other boundary function values." << std::endl;
612 
613       libmesh_error();
614     }
615 
616   if (n_other_boundary_functions !=
617       input.vector_variable_size("other_boundary_function_boundaries"))
618     {
619       libMesh::out << "Error: " << n_other_boundary_functions
620                    << " other boundary function types does not match "
621                    << input.vector_variable_size("other_boundary_function_boundaries")
622                    << " other boundary function boundaries." << std::endl;
623 
624       libmesh_error();
625     }
626 
627   if (n_other_boundary_functions !=
628       input.vector_variable_size("other_boundary_function_ids"))
629     {
630       libMesh::out << "Error: " << n_other_boundary_functions
631                    << " other boundary function types does not match "
632                    << input.vector_variable_size("other_boundary_function_ids")
633                    << " other boundary function ids." << std::endl;
634 
635       libmesh_error();
636     }
637 
638   for (unsigned int i=0; i != n_other_boundary_functions; ++i)
639     {
640       const std::string func_type =
641         input("other_boundary_function_types", zero_string, i);
642 
643       const std::string func_value =
644         input("other_boundary_function_values", empty_string, i);
645 
646       const boundary_id_type func_boundary =
647         input("other_boundary_function_boundaries", boundary_id_type(0), i);
648 
649       const int func_id =
650         input("other_boundary_function_ids", int(0), i);
651 
652       other_boundary_functions[func_id][func_boundary] =
653         (new_function_base(func_type, func_value).release());
654     }
655 
656   GETPOT_INPUT(run_simulation);
657   GETPOT_INPUT(run_postprocess);
658 
659 
660   GETPOT_REGISTER(fe_family);
661   const unsigned int n_fe_family =
662     std::max(1u, input.vector_variable_size("fe_family"));
663   fe_family.resize(n_fe_family, "LAGRANGE");
664   for (unsigned int i=0; i != n_fe_family; ++i)
665     fe_family[i]              = input("fe_family", fe_family[i].c_str(), i);
666   GETPOT_REGISTER(fe_order);
667   const unsigned int n_fe_order =
668     input.vector_variable_size("fe_order");
669   fe_order.resize(n_fe_order, 1);
670   for (unsigned int i=0; i != n_fe_order; ++i)
671     fe_order[i]               = input("fe_order", (int)fe_order[i], i);
672   GETPOT_INPUT(extra_quadrature_order);
673 
674 
675   GETPOT_INPUT(analytic_jacobians);
676   GETPOT_INPUT(verify_analytic_jacobians);
677   GETPOT_INPUT(numerical_jacobian_h);
678   GETPOT_INPUT(print_solution_norms);
679   GETPOT_INPUT(print_solutions);
680   GETPOT_INPUT(print_residual_norms);
681   GETPOT_INPUT(print_residuals);
682   GETPOT_INPUT(print_jacobian_norms);
683   GETPOT_INPUT(print_jacobians);
684   GETPOT_INPUT(print_element_solutions);
685   GETPOT_INPUT(print_element_residuals);
686   GETPOT_INPUT(print_element_jacobians);
687 
688 
689   GETPOT_INPUT(use_petsc_snes);
690   GETPOT_INPUT(time_solver_quiet);
691   GETPOT_INPUT(solver_quiet);
692   GETPOT_INPUT(solver_verbose);
693   GETPOT_INPUT(reuse_preconditioner);
694   GETPOT_INPUT(require_residual_reduction);
695   GETPOT_INPUT(min_step_length);
696   GETPOT_INT_INPUT(max_linear_iterations);
697   GETPOT_INT_INPUT(max_nonlinear_iterations);
698   GETPOT_INPUT(relative_step_tolerance);
699   GETPOT_INPUT(relative_residual_tolerance);
700   GETPOT_INPUT(absolute_residual_tolerance);
701   GETPOT_INPUT(initial_linear_tolerance);
702   GETPOT_INPUT(minimum_linear_tolerance);
703   GETPOT_INPUT(linear_tolerance_multiplier);
704 
705 
706   GETPOT_INT_INPUT(initial_sobolev_order);
707   GETPOT_INT_INPUT(initial_extra_quadrature);
708   GETPOT_INPUT(refine_uniformly);
709   GETPOT_INPUT(indicator_type);
710   GETPOT_INPUT(patch_reuse);
711   GETPOT_INT_INPUT(sobolev_order);
712 
713   GETPOT_INPUT(system_config_file);
714 
715   std::vector<std::string> bad_variables =
716     input.unidentified_arguments(variable_assignments);
717 
718   // The way unidentified_arguments() works can give us false
719   // positives from repeated (overridden) variable assignments or from
720   // other (e.g. PETSc) command line arguments.
721   std::vector<std::string> actually_bad_variables;
722   for (std::size_t i = 0; i < bad_variables.size(); ++i)
723     {
724       // If any of our ufo arguments start with a -, that's a false
725       // positive from an unrelated command line argument.
726       if (bad_variables[i].empty() || bad_variables[i][0] != '-')
727         {
728           std::string bad_variable_name =
729             bad_variables[i].substr(0, bad_variables[i].find('='));
730           if (!variable_names.count(bad_variable_name))
731             actually_bad_variables.push_back(bad_variables[i]);
732         }
733       // Skip any option variable and (to be safe from false
734       // positives, though it can create false negatives) any
735       // subsequent potential argument
736       else
737         if (bad_variables.size() > (i+1) &&
738             !bad_variables[i+1].empty() &&
739             bad_variables[i+1][0] != '-')
740           ++i;
741     }
742 
743   if (this->comm().rank() == 0 && !actually_bad_variables.empty())
744     {
745       libMesh::err << "ERROR: Unrecognized variables:" << std::endl;
746       for (auto var : actually_bad_variables)
747         libMesh::err << var << std::endl;
748       libMesh::err << "Not found among recognized variables:" << std::endl;
749       for (std::size_t i = 0; i != variable_names.size(); ++i)
750         libMesh::err << variable_assignments[i] << std::endl;
751       libmesh_error();
752     }
753 }
754