+++ /dev/null
-<a name="Intro"></a>
-<h1>Introduction</h1>
-
-
-In step-18, we saw a need to write
-output files in an intermediate format: in a %parallel program, it doesn't scale
-well if all processors participate in computing a result, and then only a
-single processor generates the graphical output. Rather, each of them should
-generate output for its share of the domain, and later on merge all these
-output files into a single one.
-
-
-
-Thus was the beginning of step-19: it is the program that reads a number of
-files written in intermediate format, and merges and converts them into the
-final format that one would like to use for visualization. It can also be used
-for the following purpose: if you are unsure at the time of a computation what
-graphics program you would like to use, write your results in intermediate
-format; it can later be converted, using the present program, to any other
-format you may want.
-
-
-
-While this in itself was not interesting enough to make a tutorial program, we
-have used the opportunity to introduce one class that has proven to be
-extremely help- and useful in real application programs, but had not been
-covered by any of the previous tutorial programs: the
-<code>ParameterHandler</code> class. This class is used in applications that
-want to have some of their behavior determined at run time, using input
-files. For example, one may want to specify the geometry, or specifics of the
-equation to be solved, at run time. Other typical parameters are the number of
-nonlinear iterations, the name of output files, or the names of input files
-specifying material properties or boundary conditions.
-
-
-
-Working with such parameter files is not rocket science. However, it is rather
-tedious to write the parsers for such files, in particular if they should be
-extensible, be able to group parameters into subsections, perform some error
-checks such as that parameters can have only certain kinds of values (for
-example, it should only be allowed to have integer values in an input file for
-parameters that denote a number of iteration), and similar requirements. The
-<code>ParameterHandler</code> class allows for all this: an application program
-will declare the parameters it expects (or call a function in the library that
-declares a number of parameters for you), the <code>ParameterHandler</code>
-class then reads an input file with all these parameters, and the application
-program can then get their values back from this class.
-
-
-
-In order to perform these three steps, the <code>ParameterHandler</code> offers
-three sets of functions: first, the
-<code>ParameterHandler::declare_entry</code> function is used to declare the
-existence of a named parameter in the present section of the input file (one
-can enter and leave subsections in a parameter file just like you would
-navigate through a directory tree in a file system, with the functions
-<code>ParameterHandler::enter_subsection</code> and
-<code>ParameterHandler::leave_subsection</code> taking on the roles of the
-commands <code>cd dir</code> and <code>cd ..</code>; the only difference being
-that if you enter a subsection that has never been visited before, it is
-created: it isn't necessary to "create" subsections explicitly). When declaring
-a parameter, one has to specify its name and default value, in case the
-parameter isn't later listed explicitly in the parameter file. In addition to
-that, there are optional arguments indicating a pattern that a parameter has to
-satisfy, such as being an integer (see the discussion above), and a help text
-that might later give an explanation of what the parameter stands for.
-
-
-
-Once all parameters have been declared, parameters can be read, using the
-<code>ParameterHandler::parse_input</code> family of functions. There are
-versions of this function that can read from a file stream, that take a file
-name, or that simply take a string and parse it. When reading parameters, the
-class makes sure that only parameters are listed in the input that have been
-declared before, and that the values of parameters satisfy the pattern that has
-been given to describe the kind of values a parameter can have. Input that uses
-undeclared parameters or values for parameters that do not conform to the
-pattern are rejected by raising an exception.
-
-
-
-A typical input file will look like this:
-@code
-set Output format = dx
-set Output file = my_output_file.dx
-
-set Maximal number of iterations = 13
-
-subsection Application
- set Color of output = blue
- set Generate output = false
-end
-@endcode
-Note that subsections can be nested.
-
-
-
-Finally, the application program can get the values of declared parameters back
-by traversing the subsections of the parameter tree and using the
-<code>ParameterHandler::get</code> and related functions. The
-<code>ParameterHandler::get</code> simply returns the value of a parameter as a
-string, whereas <code>ParameterHandler::get_integer</code>,
-<code>ParameterHandler::get_double</code>, and
-<code>ParameterHandler::get_bool</code> already convert them to the indicated
-type.
-
-
-
-Using the <code>ParameterHandler</code> class therefore provides for a pretty
-flexible mechanism to handle all sorts of moderately complex input files without
-much effort on the side of the application programmer. We will use this to
-provide all sorts of options to the step-19 program in order to convert from
-intermediate file format to any other graphical file format.
-
-
-
-The rest of the story is probably best told by looking at the source of step-19
-itself. Let us, however, end this introduction by pointing the reader at the
-extensive class documentation of the <code>ParameterHandler</code> class for
-more information on specific details of that class.
+++ /dev/null
-<h1>Results</h1>
-
-
-With all that above, here is first what we get if we just run the program
-without any parameters at all:
-@code
-examples/\step-19> ./\step-19
-
-Converter from deal.II intermediate format to other graphics formats.
-
-Usage:
- ./\step-19 [-p parameter_file] list_of_input_files
- [-x output_format] [-o output_file]
-
-Parameter sequences in brackets can be omitted if a parameter file is
-specified on the command line and if it provides values for these
-missing parameters.
-
-The parameter file has the following format and allows the following
-values (you can cut and paste this and use it for your own parameter
-file):
-
-# Listing of Parameters
-# ---------------------
-# A dummy parameter asking for an integer
-set Dummy iterations = 42
-
-# The name of the output file to be generated
-set Output file =
-
-# A name for the output format to be used
-set Output format = gnuplot
-
-
-subsection DX output parameters
- # A Boolean field indicating whether neighborship information between cells
- # is to be written to the OpenDX output file
- set Write neighbors = true
-end
-
-
-subsection Dummy subsection
- # A dummy parameter that shows how one can define a parameter that can be
- # assigned values from a finite set of values
- set Dummy color of output = red
-
- # A dummy parameter that can be fed with either 'true' or 'false'
- set Dummy generate output = true
-end
-
-
-subsection Eps output parameters
- # Angle of the viewing position against the vertical axis
- set Azimut angle = 60
-
- # Name of a color function used to colorize mesh lines and/or cell
- # interiors
- set Color function = default
-
- # Whether the interior of cells shall be shaded
- set Color shading of interior of cells = true
-
- # Whether the mesh lines, or only the surface should be drawn
- set Draw mesh lines = true
-
- # Whether only the mesh lines, or also the interior of cells should be
- # plotted. If this flag is false, then one can see through the mesh
- set Fill interior of cells = true
-
- # Number of the input vector that is to be used to generate color
- # information
- set Index of vector for color = 0
-
- # Number of the input vector that is to be used to generate height
- # information
- set Index of vector for height = 0
-
- # The width in which the postscript renderer is to plot lines
- set Line widths in eps units = 0.5
-
- # Whether width or height should be scaled to match the given size
- set Scale to width or height = width
-
- # Scaling for the z-direction relative to the scaling used in x- and
- # y-directions
- set Scaling for z-axis = 1
-
- # The size (width or height) to which the eps output file is to be scaled
- set Size (width or height) in eps units = 300
-
- # Angle of the viewing direction against the y-axis
- set Turn angle = 30
-end
-
-subsection Povray output parameters
- # Whether camera and lighting information should be put into an external
- # file "data.inc" or into the POVRAY input file
- set Include external file = true
-
- # Whether POVRAY should use bicubic patches
- set Use bicubic patches = false
-
- # A flag indicating whether POVRAY should use smoothed triangles instead of
- # the usual ones
- set Use smooth triangles = false
-end
-
-
-subsection UCD output parameters
- # A flag indicating whether a comment should be written to the beginning of
- # the output file indicating date and time of creation as well as the
- # creating program
- set Write preamble = true
-end
-@endcode
-
-That's a lot of output for such a little program, but then that's also a lot of
-output formats that deal.II supports. You will realize that the output consists
-of first entries in the top-level section (sorted alphabetically), then a
-sorted list of subsections. Most of the parameters have been declared by the
-<code>DataOutBase</code> class, but there are also the dummy entries and
-sections we have added in the <code>declare_parameters()</code> function, along
-with their default values and documentations.
-
-
-
-Let us try to run this program on a set of input files generated by a modified
-step-18 run on 32 nodes of a
-cluster. The computation was rather big, with more
-than 350,000 cells and some 1.2M unknowns. That makes for 32 rather big
-intermediate files that we will try to merge using the present program. Here is
-the list of files, totaling some 245MB of data:
-@code
-examples/\step-19> ls -l *d2
--rw-r--r-- 1 bangerth wheeler 7982085 Aug 12 10:11 solution-0005.0000-000.d2
--rw-r--r-- 1 bangerth wheeler 7888316 Aug 12 10:13 solution-0005.0000-001.d2
--rw-r--r-- 1 bangerth wheeler 7715984 Aug 12 10:09 solution-0005.0000-002.d2
--rw-r--r-- 1 bangerth wheeler 7887648 Aug 12 10:06 solution-0005.0000-003.d2
--rw-r--r-- 1 bangerth wheeler 7833291 Aug 12 10:09 solution-0005.0000-004.d2
--rw-r--r-- 1 bangerth wheeler 7536394 Aug 12 10:07 solution-0005.0000-005.d2
--rw-r--r-- 1 bangerth wheeler 7817551 Aug 12 10:06 solution-0005.0000-006.d2
--rw-r--r-- 1 bangerth wheeler 7996660 Aug 12 10:07 solution-0005.0000-007.d2
--rw-r--r-- 1 bangerth wheeler 7761545 Aug 12 10:06 solution-0005.0000-008.d2
--rw-r--r-- 1 bangerth wheeler 7754027 Aug 12 10:07 solution-0005.0000-009.d2
--rw-r--r-- 1 bangerth wheeler 7607545 Aug 12 10:11 solution-0005.0000-010.d2
--rw-r--r-- 1 bangerth wheeler 7728039 Aug 12 10:07 solution-0005.0000-011.d2
--rw-r--r-- 1 bangerth wheeler 7577293 Aug 12 10:14 solution-0005.0000-012.d2
--rw-r--r-- 1 bangerth wheeler 7735626 Aug 12 10:10 solution-0005.0000-013.d2
--rw-r--r-- 1 bangerth wheeler 7629075 Aug 12 10:10 solution-0005.0000-014.d2
--rw-r--r-- 1 bangerth wheeler 7314459 Aug 12 10:09 solution-0005.0000-015.d2
--rw-r--r-- 1 bangerth wheeler 7414738 Aug 12 10:10 solution-0005.0000-016.d2
--rw-r--r-- 1 bangerth wheeler 7330518 Aug 12 10:05 solution-0005.0000-017.d2
--rw-r--r-- 1 bangerth wheeler 7418213 Aug 12 10:11 solution-0005.0000-018.d2
--rw-r--r-- 1 bangerth wheeler 7508715 Aug 12 10:08 solution-0005.0000-019.d2
--rw-r--r-- 1 bangerth wheeler 7747143 Aug 12 10:06 solution-0005.0000-020.d2
--rw-r--r-- 1 bangerth wheeler 7563548 Aug 12 10:05 solution-0005.0000-021.d2
--rw-r--r-- 1 bangerth wheeler 7846767 Aug 12 10:12 solution-0005.0000-022.d2
--rw-r--r-- 1 bangerth wheeler 7479576 Aug 12 10:12 solution-0005.0000-023.d2
--rw-r--r-- 1 bangerth wheeler 7925060 Aug 12 10:12 solution-0005.0000-024.d2
--rw-r--r-- 1 bangerth wheeler 7842034 Aug 12 10:13 solution-0005.0000-025.d2
--rw-r--r-- 1 bangerth wheeler 7585448 Aug 12 10:13 solution-0005.0000-026.d2
--rw-r--r-- 1 bangerth wheeler 7609698 Aug 12 10:10 solution-0005.0000-027.d2
--rw-r--r-- 1 bangerth wheeler 7576053 Aug 12 10:08 solution-0005.0000-028.d2
--rw-r--r-- 1 bangerth wheeler 7682418 Aug 12 10:08 solution-0005.0000-029.d2
--rw-r--r-- 1 bangerth wheeler 7544141 Aug 12 10:05 solution-0005.0000-030.d2
--rw-r--r-- 1 bangerth wheeler 7348899 Aug 12 10:04 solution-0005.0000-031.d2
-@endcode
-
-So let's see what happens if we attempt to merge all these files into a single
-one:
-@code
-examples/\step-19> time ./\step-19 solution-0005.0000-*.d2 -x gmv -o solution-0005.gmv
-real 2m08.35s
-user 1m26.61s
-system 0m05.74s
-
-examples/\step-19> ls -l solution-0005.gmv
--rw-r--r-- 1 bangerth wheeler 240680494 Sep 9 11:53 solution-0005.gmv
-@endcode
-So in roughly two minutes we have merged 240MB of data. Counting reading and
-writing, that averages a throughput of 3.8MB per second, not so bad.
-
-
-
-If visualized, the output looks very much like that shown for
-step-18. But that's not quite as
-important for the moment, rather we are interested in showing how to use the
-parameter file. To this end, remember that if no parameter file is given, or if
-it is empty, all the default values listed above are used. However, whatever we
-specify in the parameter file is used, unless overridden again by
-parameters found later on the command line.
-
-
-
-For example, let us use a simple parameter file named
-<code>solution-0005.prm</code> that contains only one line:
-@code
-set Output format = gnuplot
-@endcode
-If we run step-19 with it again, we obtain this (for simplicity, and because we
-don't want to visualize 240MB of data anyway, we only convert the one, the
-twelfth, intermediate file to gnuplot format):
-@code
-examples/\step-19> ./\step-19 solution-0005.0000-012.d2 -p solution-0005.prm -o solution-0005.gnuplot
-
-examples/\step-19> ls -l solution-0005.gnuplot
--rw-r--r-- 1 bangerth wheeler 20281669 Sep 9 12:15 solution-0005.gnuplot
-@endcode
-
-We can then visualize this one file with gnuplot, obtaining something like
-this:
-<img src="https://www.dealii.org/images/steps/developer/step-19.solution-0005.png" alt="">
-
-That's not particularly exciting, but the file we're looking at has only one
-32nd of the entire domain anyway, so we can't expect much.
-
-In more complicated situations, we would use parameter files that set more of
-the values to non-default values. A file for which this is the case could look
-like this, generating output for the OpenDX visualization program:
-@code
-set Output format = dx
-set Output file = my_output_file.dx
-
-set Dummy iterations = -13
-
-subsection Dummy subsection
- set Dummy color of output = blue
- set Dummy generate output = false
-end
-@endcode
-If one wanted to, one could write comments into the file using the
-same format as used above in the help text, i.e. everything on a line
-following a hashmark (<code>#</code>) is considered a comment.
-
-
-
-If one runs step-19 with this input file, this is what is going to happen:
-@code
-examples/\step-19> ./\step-19 solution-0005.0000-012.d2 -p solution-0005.prm
-Line 4:
- The entry value
- -13
- for the entry named
- Dummy iterations
- does not match the given pattern
- [Integer range 1...1000 (inclusive)]
-@endcode
-Ah, right: valid values for the iteration parameter needed to be within the
-range [1...1000]. We would fix that, then go back to run the program with
-correct parameters.
-
-
-
-This program should have given some insight into the input parameter file
-handling that deal.II provides. The <code>ParameterHandler</code> class has a
-few more goodies beyond what has been shown in this program, for those who want
-to use this class, it would be useful to read the documentation of that class
-to get the full picture.
-
+++ /dev/null
-/* ---------------------------------------------------------------------
- *
- * Copyright (C) 2005 - 2018 by the deal.II authors
- *
- * This file is part of the deal.II library.
- *
- * The deal.II library is free software; you can use it, redistribute
- * it, and/or modify it under the terms of the GNU Lesser General
- * Public License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * The full text of the license can be found in the file LICENSE.md at
- * the top level directory of deal.II.
- *
- * ---------------------------------------------------------------------
-
- *
- * Author: Luca Heltai, Wolfgang Bangerth, 2005
- */
-
-
-// @sect4{Preliminaries}
-
-// As usual, we start with include files. This program is content with really
-// few of these -- we only need two files from the library (one for input and
-// output of graphical data, one for parameter handling), and a few C++
-// standard headers:
-#include <deal.II/base/data_out_base.h>
-#include <deal.II/base/parameter_handler.h>
-
-#include <list>
-#include <iostream>
-#include <fstream>
-
-// As mentioned in the first few tutorial programs, all names in deal.II are
-// declared in a namespace <code>dealii</code>. To make using these function
-// and class names simpler, we import the entire content of that namespace
-// into the global scope. As done for all previous programs already, we'll
-// also place everything we do here into a namespace of its own:
-namespace Step19
-{
- using namespace dealii;
-
- // Before we start with the actual program, let us declare a few global
- // variables that will be used to hold the parameters this program is going
- // to use. Usually, global variables are frowned upon for a good reason, but
- // since we have such a short program here that does only a single thing, we
- // may stray from our usual line and make these variables global, rather
- // than passing them around to all functions or encapsulating them into a
- // class.
- //
- // The variables we have are: first, an object that will hold parameters of
- // operation, such as output format (unless given on the command line);
- // second, the names of input and output files; and third, the format in
- // which the output is to be written:
- ParameterHandler prm;
- std::vector<std::string> input_file_names;
- std::string output_file;
- std::string output_format;
-
-
- // All the stuff this program does can be done from here on. As described in
- // the introduction, what we have to do is declare what values the parameter
- // file can have, parse the command line, read the input files, then write
- // the output. We will do this in this order of operation, but before that
- // let us declare a function that prints a message about how this program is
- // to be used; the function first prints a general message, and then goes on
- // to list the parameters that are allowed in the parameter file (the
- // <code>ParameterHandler</code> class has a function to do exactly this;
- // see the results section for what it prints):
- void print_usage_message()
- {
- static const char *message =
- "\n"
- "Converter from deal.II intermediate format to other graphics formats.\n"
- "\n"
- "Usage:\n"
- " ./step-19 [-p parameter_file] list_of_input_files \n"
- " [-x output_format] [-o output_file]\n"
- "\n"
- "Parameter sequences in brackets can be omitted if a parameter file is\n"
- "specified on the command line and if it provides values for these\n"
- "missing parameters.\n"
- "\n"
- "The parameter file has the following format and allows the following\n"
- "values (you can cut and paste this and use it for your own parameter\n"
- "file):\n"
- "\n";
- std::cout << message;
-
- prm.print_parameters(std::cout, ParameterHandler::Text);
- }
-
-
- // @sect4{Declaring parameters for the input file}
-
- // The second function is used to declare the parameters this program
- // accepts from the input file. While we don't actually take many parameters
- // from the input file except for, possibly, the output file name and
- // format, we nevertheless want to show how to work with parameter files.
- //
- // In short, the <code>ParameterHandler</code> class works as follows: one
- // declares the entries of parameters that can be given in input files
- // together, and later on one can read an input file in which these
- // parameters are set to their values. If a parameter is not listed in the
- // input file, the default value specified in the declaration of that
- // parameter is used. After that, the program can query the values assigned
- // to certain parameters from the <code>ParameterHandler</code> object.
- //
- // Declaring parameters can be done using the
- // <code>ParameterHandler::declare_entry</code> function. It's arguments are
- // the name of a parameter, a default value (given as a string, even if the
- // parameter is numeric in nature, and thirdly an object that describes
- // constraints on values that may be passed to this parameter. In the
- // example below, we use an object of type <code>Patterns::Anything</code>
- // to denote that there are no constraints on file names (this is, of
- // course, not true -- the operating system does have constraints, but from
- // an application standpoint, almost all names are valid). In other cases,
- // one may, for example, use <code>Patterns::Integer</code> to make sure
- // that only parameters are accepted that can be interpreted as integer
- // values (it is also possible to specify bounds for integer values, and all
- // values outside this range are rejected), <code>Patterns::Double</code>
- // for floating point values, classes that make sure that the given
- // parameter value is a comma separated list of things, etc. Take a look at
- // the <code>Patterns</code> namespace to see what is possible.
- //
- // The fourth argument to <code>declare_entry</code> is a help string that
- // can be printed to document what this parameter is meant to be used for
- // and other information you may consider important when declaring this
- // parameter. The default value of this fourth argument is the empty string.
- //
- // I always wanted to have an example program describing the
- // <code>ParameterHandler</code> class, because it is so particularly
- // useful. It would have been useful in a number of previous example
- // programs (for example, in order to let the tolerance for linear solvers,
- // or the number of refinement steps be determined by a run-time parameter,
- // rather than hard-coding them into the program), but it turned out that
- // trying to explain this class there would have overloaded them with things
- // that would have distracted from the main purpose. However, while writing
- // this program, I realized that there aren't all that many parameters this
- // program can usefully ask for, or better, it turned out: declaring and
- // querying these parameters was already done centralized in one place of
- // the library, namely the <code>DataOutInterface</code> class that handles
- // exactly this -- managing parameters for input and output.
- //
- // So the second function call in this function is to let the
- // <code>DataOutInterface</code> declare a good number of parameters that
- // control everything from the output format to what kind of output should
- // be generated if output is written in a specific graphical format. For
- // example, when writing data in encapsulated postscript (EPS) format, the
- // result is just a 2d projection, not data that can be viewed and rotated
- // with a viewer. Therefore, one has to choose the viewing angle and a
- // number of other options up front, when output is generated, rather than
- // playing around with them later on. The call to
- // <code>DataOutInterface::declare_parameters</code> declares entries that
- // allow to specify them in the parameter input file during run-time. If the
- // parameter file does not contain entries for them, defaults are taken.
- //
- // As a final note: <code>DataOutInterface</code> is a template, because it
- // is usually used to write output for a specific space dimension. However,
- // this program is supposed to be used for all dimensions at the same time,
- // so we don't know at compile time what the right dimension is when
- // specifying the template parameter. Fortunately, declaring parameters is
- // something that is space dimension independent, so we can just pick one
- // arbitrarily. We pick <code>1</code>, but it could have been any other
- // number as well.
- void declare_parameters()
- {
- prm.declare_entry("Output file",
- "",
- Patterns::Anything(),
- "The name of the output file to be generated");
-
- DataOutInterface<1>::declare_parameters(prm);
-
- // Since everything that this program can usefully request in terms of
- // input parameters is already handled by now, let us nevertheless show
- // how to use input parameters in other circumstances. First, parameters
- // are like files in a directory tree: they can be in the top-level
- // directory, but you can also group them into subdirectories to make it
- // easier to find them or to be able to use the same parameter name in
- // different contexts.
- //
- // Let us first declare a dummy parameter in the top-level section; we
- // assume that it will denote the number of iterations, and that useful
- // numbers of iterations that a user should be able to specify are in the
- // range 1...1000, with a default value of 42:
- prm.declare_entry("Dummy iterations",
- "42",
- Patterns::Integer(1, 1000),
- "A dummy parameter asking for an integer");
-
- // Next, let us declare a sub-section (the equivalent to a
- // subdirectory). When entered, all following parameter declarations will
- // be within this subsection. To also visually group these declarations
- // with the subsection name, I like to use curly braces to force my editor
- // to indent everything that goes into this sub-section by one level of
- // indentation. In this sub-section, we shall have two entries, one that
- // takes a Boolean parameter and one that takes a selection list of
- // values, separated by the '|' character:
- prm.enter_subsection("Dummy subsection");
- {
- prm.declare_entry("Dummy generate output",
- "true",
- Patterns::Bool(),
- "A dummy parameter that can be fed with either "
- "'true' or 'false'");
- prm.declare_entry("Dummy color of output",
- "red",
- Patterns::Selection("red|black|blue"),
- "A dummy parameter that shows how one can define a "
- "parameter that can be assigned values from a finite "
- "set of values");
- }
- prm.leave_subsection();
- // After this, we have left the subsection again. You should have gotten
- // the idea by now how one can nest subsections to separate
- // parameters. There are a number of other possible patterns describing
- // possible values of parameters; in all cases, if you try to pass a
- // parameter to the program that does not match the expectations of the
- // pattern, it will reject the parameter file and ask you to fix it. After
- // all, it does not make much sense if you had an entry that contained the
- // entry "red" for the parameter "Generate output".
- }
-
-
- // @sect4{Parsing the command line}
-
- // Our next task is to see what information has been provided on the command
- // line. First, we need to be sure that there is at least one parameter: an
- // input file. The format and the output file can be specified in the
- // parameter file, but the list of input files can't, so at least one
- // parameter needs to be there. Together with the name of the program (the
- // zeroth parameter), <code>argc</code> must therefore be at least 2. If
- // this is not the case, we print an error message and exit:
- void parse_command_line(const int argc, char *const *argv)
- {
- if (argc < 2)
- {
- print_usage_message();
- exit(1);
- }
-
- // Next, collect all parameters in a list that will be somewhat simpler to
- // handle than the <code>argc</code>/<code>argv</code> mechanism. We omit
- // the name of the executable at the zeroth index:
- std::list<std::string> args;
- for (int i = 1; i < argc; ++i)
- args.emplace_back(argv[i]);
-
- // Then process all these parameters. If the parameter is <code>-p</code>,
- // then there must be a parameter file following (which we should then
- // read), in case of <code>-x</code> it is the name of an output
- // format. Finally, for <code>-o</code> it is the name of the output
- // file. In all cases, once we've treated a parameter, we remove it from
- // the list of parameters:
- while (args.size())
- {
- if (args.front() == std::string("-p"))
- {
- if (args.size() == 1)
- {
- std::cerr << "Error: flag '-p' must be followed by the "
- << "name of a parameter file." << std::endl;
- print_usage_message();
- exit(1);
- }
- args.pop_front();
- const std::string parameter_file = args.front();
- args.pop_front();
-
- // Now read the input file:
- prm.parse_input(parameter_file);
-
- // Both the output file name as well as the format can be
- // specified on the command line. We have therefore given them
- // global variables that hold their values, but they can also be
- // set in the parameter file. We therefore need to extract them
- // from the parameter file here, because they may be overridden by
- // later command line parameters:
- if (output_file == "")
- output_file = prm.get("Output file");
-
- if (output_format == "")
- output_format = prm.get("Output format");
-
- // Finally, let us note that if we were interested in the values
- // of the parameters declared above in the dummy subsection, we
- // would write something like this to extract the value of the
- // Boolean flag (the <code>prm.get</code> function returns the
- // value of a parameter as a string, whereas the
- // <code>prm.get_X</code> functions return a value already
- // converted to a different type):
- prm.enter_subsection("Dummy subsection");
- {
- prm.get_bool("Dummy generate output");
- }
- prm.leave_subsection();
- // We would assign the result to a variable, of course, but don't
- // here in order not to generate an unused variable that the
- // compiler might warn about.
- //
- // Alas, let's move on to handling of output formats:
- }
- else if (args.front() == std::string("-x"))
- {
- if (args.size() == 1)
- {
- std::cerr << "Error: flag '-x' must be followed by the "
- << "name of an output format." << std::endl;
- print_usage_message();
- exit(1);
- }
- args.pop_front();
- output_format = args.front();
- args.pop_front();
- }
- else if (args.front() == std::string("-o"))
- {
- if (args.size() == 1)
- {
- std::cerr << "Error: flag '-o' must be followed by the "
- << "name of an output file." << std::endl;
- print_usage_message();
- exit(1);
- }
- args.pop_front();
- output_file = args.front();
- args.pop_front();
- }
-
- // Otherwise, this is not a parameter that starts with a known minus
- // sequence, and we should consider it to be the name of an input
- // file. Let us therefore add this file to the list of input files:
- else
- {
- input_file_names.push_back(args.front());
- args.pop_front();
- }
- }
-
- // Next check a few things and create errors if the checks fail. Firstly,
- // there must be at least one input file
- if (input_file_names.size() == 0)
- {
- std::cerr << "Error: No input file specified." << std::endl;
- print_usage_message();
- exit(1);
- }
- }
-
-
- // @sect4{Generating output}
-
- // Now that we have all the information, we need to read all the input
- // files, merge them, and generate a single output file. This, after all,
- // was the motivation, borne from the necessity encountered in the step-18
- // tutorial program, to write this program in the first place.
- //
- // So what we do first is to declare an object into which we will merge the
- // data from all the input file, and read in the first file through a
- // stream. Note that every time we open a file, we use the
- // <code>AssertThrow</code> macro to check whether the file is really
- // readable -- if it isn't then this will trigger an exception and
- // corresponding output will be generated from the exception handler in
- // <code>main()</code>:
- template <int dim, int spacedim>
- void do_convert()
- {
- DataOutReader<dim, spacedim> merged_data;
-
- {
- std::ifstream input(input_file_names[0]);
- AssertThrow(input, ExcIO());
-
- merged_data.read(input);
- }
-
- // For all the other input files, we read their data into an intermediate
- // object, and then merge that into the first object declared above:
- for (unsigned int i = 1; i < input_file_names.size(); ++i)
- {
- std::ifstream input(input_file_names[i]);
- AssertThrow(input, ExcIO());
-
- DataOutReader<dim, spacedim> additional_data;
- additional_data.read(input);
- merged_data.merge(additional_data);
- }
-
- // Once we have this, let us open an output stream, and parse what we got
- // as the name of the output format into an identifier. Fortunately, the
- // <code>DataOutBase</code> class has a function that does this parsing
- // for us, i.e. it knows about all the presently supported output formats
- // and makes sure that they can be specified in the parameter file or on
- // the command line. Note that this ensures that if the library acquires
- // the ability to output in other output formats, this program will be
- // able to make use of this ability without having to be changed!
- std::ofstream output_stream(output_file);
- AssertThrow(output_stream, ExcIO());
-
- const DataOutBase::OutputFormat format =
- DataOutBase::parse_output_format(output_format);
-
- // Finally, write the merged data to the output:
- merged_data.write(output_stream, format);
- }
-
-
- // @sect4{Dispatching output generation}
-
- // The function above takes template parameters relating to the space
- // dimension of the output, and the dimension of the objects to be
- // output. (For example, when outputting whole cells, these two dimensions
- // are the same, but the intermediate files may contain only data pertaining
- // to the faces of cells, in which case the first parameter will be one less
- // than the space dimension.)
- //
- // The problem is: at compile time, we of course don't know the dimensions
- // used in the input files. We have to plan for all cases, therefore. This
- // is a little clumsy, since we need to specify the dimensions statically at
- // compile time, even though we will only know about them at run time.
- //
- // So here is what we do: from the first input file, we determine (using a
- // function in <code>DataOutBase</code> that exists for this purpose) these
- // dimensions. We then have a series of switches that dispatch, statically,
- // to the <code>do_convert</code> functions with different template
- // arguments. Not pretty, but works. Apart from this, the function does
- // nothing -- except making sure that it covered the dimensions for which it
- // was called, using the <code>AssertThrow</code> macro at places in the
- // code that shouldn't be reached:
- void convert()
- {
- AssertThrow(input_file_names.size() > 0,
- ExcMessage("No input files specified."));
-
- std::ifstream input(input_file_names[0]);
- AssertThrow(input, ExcIO());
-
- const std::pair<unsigned int, unsigned int> dimensions =
- DataOutBase::determine_intermediate_format_dimensions(input);
-
- switch (dimensions.first)
- {
- case 1:
- switch (dimensions.second)
- {
- case 1:
- do_convert<1, 1>();
- return;
-
- case 2:
- do_convert<1, 2>();
- return;
- }
- AssertThrow(false, ExcNotImplemented());
- break;
-
- case 2:
- switch (dimensions.second)
- {
- case 2:
- do_convert<2, 2>();
- return;
-
- case 3:
- do_convert<2, 3>();
- return;
- }
- AssertThrow(false, ExcNotImplemented());
- break;
-
- case 3:
- switch (dimensions.second)
- {
- case 3:
- do_convert<3, 3>();
- return;
- }
- AssertThrow(false, ExcNotImplemented());
- }
-
- AssertThrow(false, ExcNotImplemented());
- }
-} // namespace Step19
-
-
-
-// @sect4{main()}
-
-// Finally, the main program. There is not much more to do than to make sure
-// parameters are declared, the command line is parsed (which includes reading
-// parameter files), and finally making sure the input files are read and
-// output is generated. Everything else just has to do with handling
-// exceptions and making sure that appropriate output is generated if one is
-// thrown.
-int main(int argc, char **argv)
-{
- try
- {
- using namespace Step19;
-
- declare_parameters();
- parse_command_line(argc, argv);
-
- convert();
- }
- catch (std::exception &exc)
- {
- std::cerr << std::endl
- << std::endl
- << "----------------------------------------------------"
- << std::endl;
- std::cerr << "Exception on processing: " << std::endl
- << exc.what() << std::endl
- << "Aborting!" << std::endl
- << "----------------------------------------------------"
- << std::endl;
-
- return 1;
- }
- catch (...)
- {
- std::cerr << std::endl
- << std::endl
- << "----------------------------------------------------"
- << std::endl;
- std::cerr << "Unknown exception!" << std::endl
- << "Aborting!" << std::endl
- << "----------------------------------------------------"
- << std::endl;
- return 1;
- };
-
- return 0;
-}