SourceXtractorPlusPlus
0.11
Please provide a description of the project.
|
The structure of this tutorial is identical to that of two previous HowTo add a new source property computation and HowTo add a new source property computation with configuration. Readers are assumed to have a good knowledge of these previous tutorials. We continue to follow a kind of munimum example, in which we add the possible generation of multiple instances of a given property.
Our example is that of a (dummy) flag image processing. A arbitrary-sized vector of flag files and corresponding flag identifiers can be provided through the program options. The same source property (i.e., the sum of the flag values over the pixel footprint of the source) is computed for all input files provided. For each flag file, a different column (which name is constructed from the concatenation of a root name and of the identifier provided through configuration) is extracted from the corresponding property and output to the catalog.
To mark the similarities (and the differences), the same class names are used with a WithInst post-fix. Note again that not much effort is made here to make a smart example. It is only thought for illustration purposes.
Below is our minimum ExamplePropertyWithInst class.
This class is fully analogous to the previous ExampleProperty and we refer to it for explanation.
Below is the configuration class, this time the code is separated in a header and an implementation files.
Here is the ExampleConfWithInst.h header file:
And the ExampleConfWithInst.cpp implementation file:
This code is somewhat similar to the previous example. The getProgramOptions() method is again used to define the specific options with the Boost program option syntax described before. In the current example, vector options are defined which allows to enter an arbitrary number of flag filenames and identifiers.
The preInitialize(args) method was not implemented in the previous example. Its purpose is to define quick checks, which allow to interrupt the program execution as early as possible, if the provided options are not fully valid. The checks are recursive over the possible multiple elements of the vectors and they are carried out only if at least a filename is provided.
The initialize(args) method is also more involved in this example. FITs files are read into an appropriate FlagImage data structure and they are stored into a map compose of an arbitrary number (as many as input configuration vector elements) of elements, together with the flag image identifiers used as the map key.
Again, files are opened and stored only if valid filenames are provided through the configuration. This makes this configuration optional. Nothing happens if the option "ex-flag-images-files" is not provided.
Below is the ExampleSourceTaskWithInst example analogous to the ExampleSourceTask. The main method is again computeProperties(source), but now there are two member variables (they were none before), which will be filled through a constructor call with information coming from the configuration. There is however no directed connection between the task and the configuration classes. Things will be tied together through the task factory (see next section).
Another important difference, the method source.setIndexedProperty<ExamplePropertyWithInst>(m_flag_instance, sum) now replaces the previous source.setProperty<...>(...). This method takes care of calling the property constructor ignoring the first m_flag_instance parameter, i.e., ExamplePropertyWithInst(sum). It then attaches the new property to the source using the m_flag_instance integer. In this way, an arbitrary number of ExamplePropertyWithInst properties can be stored in the source providing they have been attached with different m_flag_instance. They can later be retrieved with a source.getProperty(instance_num) method call.
The task factory is analogous to the previous example, but with extra complications to manage the possible property multiplicity. The flag identifiers coming from the configuration are stored in a vector of string, while the different FlagImage are put in a map. The map key is a PropertyId object which is built from the property type and instance index.
The createTask(property_id) now has a property instance index dimension. Different tasks can be created for different PropertyId (i.e., different property indices for a given type).
The reportConfigDependencies(...) method must be implemented to declare configuration dependencies. Here, there is no other dependency than the ExampleConfWithConf itself.
Although it is belwo seperated in a header and implementation files, the plugin is again almost identical to those of the previous two examples (see ExamplePlugin and ExamplePluginWithConf. There is only one registered catalog column output, but the main difference is the plugin_api.getOutputRegistry().enableOutput<ExamplePropertyWithInst>();, which specifies that this column will always be an output (unlike the two previous cases where the output columns were optional, i.e., to be specifically requested with a ad hoc option). The logic in the current example is that when a flag file is input through the configuration, the output column is always produced. But if no flag files are provided nothing is computed and output.
Here is the ExamplePluginWithInst.h header file:
And the ExamplePluginWithInst.cpp implementation file:
The statement static StaticPlugin<ExamplePluginWithConf> example_plugin_with_conf; must appear to registers our example plugin as a static plugin (i.e., which must be compiled with SExtractor). Other types of plugin will be described later.