LCOV - code coverage report
Current view: top level - synthesis/ImagerObjects - ParallelImagerMixin.h (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 83 0.0 %
Date: 2024-10-12 00:35:29 Functions: 0 57 0.0 %

          Line data    Source code
       1             : /* -*- mode: c++ -*- */
       2             : //# ParallelImagerMixin.h: Main class for parallel imaging
       3             : //# Copyright (C) 2016
       4             : //# Associated Universities, Inc. Washington DC, USA.
       5             : //#
       6             : //# This library is free software; you can redistribute it and/or modify it
       7             : //# under the terms of the GNU Library General Public License as published by
       8             : //# the Free Software Foundation; either version 2 of the License, or (at your
       9             : //# option) any later version.
      10             : //#
      11             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      12             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      14             : //# License for more details.
      15             : //#
      16             : //# You should have received a copy of the GNU Library General Public License
      17             : //# along with this library; if not, write to the Free Software Foundation,
      18             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      19             : //#
      20             : //# Correspondence concerning AIPS++ should be addressed as follows:
      21             : //#        Internet email: casa-feedback@nrao.edu.
      22             : //#        Postal address: AIPS++ Project Office
      23             : //#                        National Radio Astronomy Observatory
      24             : //#                        520 Edgemont Road
      25             : //#                        Charlottesville, VA 22903-2475 USA
      26             : //#
      27             : #ifndef PARALLEL_IMAGER_MIXIN_H_
      28             : #define PARALLEL_IMAGER_MIXIN_H_
      29             : 
      30             : #include <string>
      31             : #include <vector>
      32             : 
      33             : #include <synthesis/ImagerObjects/MPIGlue.h>
      34             : #include <casacore/casa/Containers/Record.h>
      35             : #include <synthesis/ImagerObjects/ParallelImagerParams.h>
      36             : #include <synthesis/ImagerObjects/ParamFieldIterator.h>
      37             : #include <synthesis/ImagerObjects/SynthesisUtilMethods.h>
      38             : #include <synthesis/ImagerObjects/SynthesisDeconvolverMixin.h>
      39             : #include <synthesis/ImagerObjects/SynthesisNormalizerMixin.h>
      40             : #include <synthesis/ImagerObjects/SynthesisImagerMixin.h>
      41             : #include <synthesis/ImagerObjects/IterationControl.h>
      42             : #include <synthesis/ImagerObjects/ContinuumPartitionMixin.h>
      43             : #include <synthesis/ImagerObjects/CubePartitionMixin.h>
      44             : #include <synthesis/ImagerObjects/SerialPartitionMixin.h>
      45             : 
      46             : namespace casa {
      47             : 
      48             : /**
      49             :  * ParallelImagerMixin
      50             :  *
      51             :  * This class ties together mixin classes for imager, normalizer, deconvolver,
      52             :  * iteration control and data partitioning to provide the high level
      53             :  * functionality of synthesis imaging. The functionality embodied by this class,
      54             :  * together with its parent mixin classes, replaces all of the functionality in
      55             :  * task_tclean.py, refimagerhelper.py, synthesisimager_cmpt.cc,
      56             :  * synthesisnormalizer_cmpt.cc, synthesisdeconvolver_cmpt.cc (and maybe
      57             :  * others). Some rearrangement of the method calls spread across task_tclean.py
      58             :  * and refimagerhelper.py was necessary to create a single class embodying only
      59             :  * the highest level algorithmic structure common to the three cases of serial,
      60             :  * continuum parallel and cube parallel imaging.
      61             :  *
      62             :  * Various implementation classes are defined via typedefs at the end of this
      63             :  * file. The ParallelImagerMixin implementation classes are all defined using
      64             :  * other mixin classes that simply wrap pre-existing, non-mixin imager,
      65             :  * normalizer, and deconvolver component instances for use in this
      66             :  * framework. [We refer to classes such as SynthesisNormalizer as "component"
      67             :  * classes, and the mixin classes that wrap such components as "component mixin"
      68             :  * classes]. These component mixin classes are intended to provide a sufficient
      69             :  * design that will support changes in the component classes transparently; if
      70             :  * this proves insufficient, new implementations of the component mixin classes
      71             :  * could be supported with minimal refactoring.
      72             :  */
      73             : template <class T>
      74             : class ParallelImagerMixin
      75             :         : public T {
      76             : 
      77             : public:
      78             : 
      79             :         // ParallelImagerMixin constructor
      80             :         //
      81             :         // The various MPI communicators passed to the constructor are intended to
      82             :         // represent the following process groups:
      83             :         //
      84             :     // * worker_comm: all processes used for significant computation (likely
      85             :     //   just excluding a "front-end" or user-facing process).
      86             :         //
      87             :         // * imaging/normalization/deconvolution_comm: the groups of processes for
      88             :         //   each of these components. Note that the scope of each of these
      89             :         //   communicators defines the set of communicating processes that comprise
      90             :         //   the component; for example, in cube imaging each imaging_comm comprises
      91             :         //   a single process, whereas in continuum imaging a single imaging_comm
      92             :         //   comprises all (worker) processes. Such differences are determined by
      93             :         //   design decisions, and do not reflect inherent features of the
      94             :         //   framework.
      95             :         //
      96             :         // * iteration_comm: processes taking part in iteration control, should be
      97             :         //   those processes in worker_comm with the possible addition of a process
      98             :         //   for the tclean "front-end".
      99             :         //
     100             :         // Note that there may be overlap in the process groups for each of these
     101             :         // communicators. The mixin classes in this framework support such usage,
     102             :         // although the viability of that support depends on the usage of these
     103             :         // communicators by the wrapped components in addition to the mixin
     104             :         // classes. The current component classes make no use of these
     105             :         // communicators, so overlapping process groups are supported. When
     106             :         // component classes are using their respective communicators, it is
     107             :         // sufficient for safely calling MPI routines from component code to ensure
     108             :         // that concurrent access to a communicator by this framework and any
     109             :         // component threads is avoided. [One way this can be achieved is by
     110             :         // limiting calls to MPI routines on the provided communicator only to
     111             :         // methods directly called by this framework.]
     112             :         //
     113           0 :         ParallelImagerMixin(MPI_Comm worker_comm,
     114             :                             MPI_Comm imaging_comm,
     115             :                             MPI_Comm normalization_comm,
     116             :                             MPI_Comm deconvolution_comm,
     117             :                             MPI_Comm iteration_comm,
     118             :                             int niter,
     119             :                             bool calculate_psf,
     120             :                             bool calculate_residual,
     121             :                             string save_model,
     122             :                             ParallelImagerParams &params)
     123           0 :         : niter(niter)
     124           0 :         , calculate_psf(calculate_psf)
     125           0 :         , calculate_residual(calculate_residual)
     126           0 :         , save_model(save_model)
     127           0 :         , worker_comm(worker_comm)
     128           0 :         , imaging_comm(imaging_comm)
     129           0 :         , deconvolution_comm(deconvolution_comm)
     130           0 :         , normalization_comm(normalization_comm)
     131           0 :         , iteration_comm(iteration_comm) {
     132             :                 // Get parameters for this process
     133           0 :                 ParallelImagerParams my_params = T::get_params(worker_comm, params);
     134             : 
     135             :                 // Convert parameters to other formats used by synthesis imaging
     136             :                 // components, putting them into vectors by field index (not field key
     137             :                 // as used by the Records).
     138           0 :                 auto to_synthesis_params_select = [] (const casacore::Record &r) {
     139           0 :                         SynthesisParamsSelect pars;
     140           0 :                         pars.fromRecord(r);
     141           0 :                         return pars;
     142           0 :                 };
     143           0 :                 std::vector<SynthesisParamsSelect> selection_params =
     144             :                         transformed_by_field<SynthesisParamsSelect>(
     145             :                                 my_params.selection, to_synthesis_params_select, "ms");
     146             : 
     147           0 :                 auto to_synthesis_params_image = [] (const casacore::Record &r) {
     148           0 :                         SynthesisParamsImage pars;
     149           0 :                         pars.fromRecord(r);
     150           0 :                         return pars;
     151           0 :                 };
     152           0 :                 std::vector<SynthesisParamsImage> image_params =
     153             :                         transformed_by_field<SynthesisParamsImage>(
     154             :                                 my_params.image, to_synthesis_params_image);
     155             : 
     156           0 :                 auto to_synthesis_params_grid = [] (const casacore::Record &r) {
     157           0 :                         SynthesisParamsGrid pars;
     158           0 :                         pars.fromRecord(r);
     159           0 :                         return pars;
     160           0 :                 };
     161           0 :                 std::vector<SynthesisParamsGrid> grid_params =
     162             :                         transformed_by_field<SynthesisParamsGrid>(
     163             :                                 my_params.grid, to_synthesis_params_grid);
     164             : 
     165           0 :                 auto to_synthesis_params_deconv = [] (const casacore::Record &r) {
     166           0 :                         SynthesisParamsDeconv pars;
     167           0 :                         pars.fromRecord(r);
     168           0 :                         return pars;
     169           0 :                 };
     170           0 :                 std::vector<SynthesisParamsDeconv> deconvolution_params =
     171             :                         transformed_by_field<SynthesisParamsDeconv>(
     172             :                                 my_params.deconvolution, to_synthesis_params_deconv);
     173             : 
     174           0 :                 auto to_vector_params = [] (const casacore::Record &r) {
     175           0 :                         casacore::Record result = r;
     176           0 :                         return result;
     177             :                 };
     178           0 :                 std::vector<casacore::Record> normalization_params =
     179             :                         transformed_by_field<casacore::Record>(my_params.normalization, to_vector_params);
     180             : 
     181             :                 // Configure components
     182           0 :                 T::setup_imager(imaging_comm, selection_params, image_params,
     183             :                                 grid_params, my_params.weight);
     184           0 :                 T::setup_normalizer(normalization_comm, normalization_params);
     185           0 :                 T::setup_deconvolver(deconvolution_comm, deconvolution_params);
     186             :                 // don't initialize iteration control on any rank until all workers have
     187             :                 // completed initialization (need second barrier for case in which there
     188             :                 // are processes in iteration_comm that are not in worker_comm)
     189           0 :                 MPI_Barrier(worker_comm);
     190           0 :                 MPI_Barrier(iteration_comm);
     191           0 :                 T::setup_iteration_controller(iteration_comm, my_params.iteration);
     192           0 :         }
     193             : 
     194             :         ~ParallelImagerMixin() {
     195             :                 T::teardown_imager();
     196             :                 T::teardown_normalizer();
     197             :                 T::teardown_deconvolver();
     198             :                 T::teardown_iteration_controller();
     199             :                 auto free_comm = [](MPI_Comm *comm) {
     200             :                         if (*comm != MPI_COMM_NULL
     201             :                             && *comm != MPI_COMM_SELF
     202             :                             && *comm != MPI_COMM_WORLD)
     203             :                                 MPI_Comm_free(comm);
     204             :                 };
     205             :                 free_comm(&worker_comm);
     206             :                 free_comm(&imaging_comm);
     207             :                 free_comm(&normalization_comm);
     208             :                 free_comm(&deconvolution_comm);
     209             :                 free_comm(&iteration_comm);
     210             :         }
     211             : 
     212             :         // Top level imaging method. Note that differences in parallel continuum,
     213             :         // parallel cube, and serial imaging are not apparent at this level.
     214           0 :         casacore::Record clean() {
     215           0 :                 if (calculate_psf) {
     216           0 :                         T::make_psf();
     217           0 :                         T::normalize_psf();
     218             :                 }
     219           0 :                 if (niter >= 0) {
     220           0 :                         if (calculate_residual) {
     221           0 :                                 run_major_cycle();
     222             :                         }
     223           0 :                         else if (niter == 0 && save_model != "none") {
     224           0 :                                 T::normalize_model();
     225           0 :                                 T::predict_model();
     226             :                         }
     227           0 :                         if (niter > 0)
     228           0 :                                 while (run_minor_cycle())
     229           0 :                                         run_major_cycle();
     230             :                 }
     231           0 :                 T::restore_images();
     232           0 :                 T::concat_images("virtualnomove");
     233           0 :                 casacore::Record result = T::get_summary(); // includes plot_report
     234           0 :                 MPI_Barrier(worker_comm);
     235           0 :                 return result;
     236           0 :         }
     237             : 
     238             : protected:
     239             : 
     240           0 :         void run_major_cycle() {
     241           0 :                 T::normalize_model();
     242           0 :                 T::execute_major_cycle();
     243           0 :                 T::normalize_residual();
     244           0 :                 T::denormalize_model();
     245           0 :         }
     246             : 
     247           0 :         bool run_minor_cycle() {
     248           0 :                 T::initialize_minor_cycle();
     249           0 :                 bool result = !T::is_clean_complete();
     250           0 :                 if (result) T::execute_minor_cycle();
     251           0 :                 return result;
     252             :         }
     253             : 
     254             :         int niter;
     255             : 
     256             :         bool calculate_psf;
     257             : 
     258             :         bool calculate_residual;
     259             : 
     260             :         string save_model;
     261             : 
     262             :         MPI_Comm worker_comm;
     263             : 
     264             :         MPI_Comm imaging_comm;
     265             : 
     266             :         MPI_Comm deconvolution_comm;
     267             : 
     268             :         MPI_Comm normalization_comm;
     269             : 
     270             :         MPI_Comm iteration_comm;
     271             : 
     272             :         // Convenience function for transforming input parameter casacore::Record fields.
     273             :         template<class T1>
     274           0 :         static std::vector<T1> transformed_by_field(casacore::Record &rec,
     275             :                                                T1 (*fn)(const casacore::Record &),
     276             :                                                const string &prefix = "") {
     277           0 :                 std::vector<T1> result;
     278           0 :                 auto add_to_result = [&](const casacore::Record &rec) {
     279           0 :                         result.push_back(fn(rec));
     280             :                 };
     281           0 :                 std::for_each(ParamFieldIterator::begin(&rec, prefix),
     282             :                               ParamFieldIterator::end(&rec, prefix),
     283             :                               add_to_result);
     284           0 :                 return result;
     285           0 :         };
     286             : };
     287             : 
     288             : // Parallel continuum imager class
     289             : typedef ParallelImagerMixin<
     290             :         ContinuumPartitionMixin<
     291             :                 SynthesisImagerMixin<
     292             :                         SynthesisNormalizerMixin<
     293             :                                 SynthesisDeconvolverMixin<
     294             :                                         IterationControl> > > > >
     295             : ContinuumParallelImagerImpl;
     296             : 
     297             : // Parallel cube imager class
     298             : typedef ParallelImagerMixin<
     299             :         CubePartitionMixin<
     300             :                 SynthesisImagerMixin<
     301             :                         SynthesisNormalizerMixin<
     302             :                                 SynthesisDeconvolverMixin<
     303             :                                         IterationControl> > > > >
     304             : CubeParallelImagerImpl;
     305             : 
     306             : // Serial (non-MPI) imager class -- allows ParallelImagerMixin type to be used
     307             : // regardless of serial vs parallel CASA. However, the naming is
     308             : // unfortunate...suggestions are welcome!
     309             : typedef ParallelImagerMixin<
     310             :         SerialPartitionMixin<
     311             :                 SynthesisImagerMixin<
     312             :                         SynthesisNormalizerMixin<
     313             :                                 SynthesisDeconvolverMixin<
     314             :                                         IterationControl> > > > >
     315             : SerialParallelImagerImpl;
     316             : 
     317             : } // namespace casa
     318             : 
     319             : #endif // PARALLEL_IMAGER_H_

Generated by: LCOV version 1.16