LCOV - code coverage report
Current view: top level - synthesis/ImagerObjects - SynthesisImagerMixin.h (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 147 0.0 %
Date: 2024-12-11 20:54:31 Functions: 0 11 0.0 %

          Line data    Source code
       1             : // -*- mode: c++ -*-
       2             : //# SynthesisImagerMixin.h: Mixin for using SynthesisImager class in parallel
       3             : //#                         imaging framework (ParallelImagerMixin)
       4             : //# Copyright (C) 2016
       5             : //# Associated Universities, Inc. Washington DC, USA.
       6             : //#
       7             : //# This library is free software; you can redistribute it and/or modify it
       8             : //# under the terms of the GNU Library General Public License as published by
       9             : //# the Free Software Foundation; either version 2 of the License, or (at your
      10             : //# option) any later version.
      11             : //#
      12             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      13             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      15             : //# License for more details.
      16             : //#
      17             : //# You should have received a copy of the GNU Library General Public License
      18             : //# along with this library; if not, write to the Free Software Foundation,
      19             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      20             : //#
      21             : //# Correspondence concerning AIPS++ should be addressed as follows:
      22             : //#        Internet email: casa-feedback@nrao.edu.
      23             : //#        Postal address: AIPS++ Project Office
      24             : //#                        National Radio Astronomy Observatory
      25             : //#                        520 Edgemont Road
      26             : //#                        Charlottesville, VA 22903-2475 USA
      27             : //#
      28             : #ifndef SYNTHESIS_IMAGER_MIXIN_H_
      29             : #define SYNTHESIS_IMAGER_MIXIN_H_
      30             : 
      31             : #include <casacore/casa/Containers/Record.h>
      32             : #include <casacore/casa/Arrays/Array.h>
      33             : #include <synthesis/ImagerObjects/MPIGlue.h>
      34             : #include <synthesis/ImagerObjects/SynthesisImager.h>
      35             : #include <sys/types.h>
      36             : #include <sys/stat.h>
      37             : #include <algorithm>
      38             : #include <memory>
      39             : #include <vector>
      40             : #include <unistd.h>
      41             : #include <cerrno>
      42             : #include <cstring>
      43             : #include <string>
      44             : #include <dirent.h>
      45             : #include <system_error>
      46             : 
      47             : namespace casa {
      48             : 
      49             : /**
      50             :  * Simple mixin class to put SynthesisImager into ParallelImagerMixin framework.
      51             :  */
      52             : template <class T>
      53             : class SynthesisImagerMixin
      54             :         : public T {
      55             : 
      56             : private:
      57             :         std::unique_ptr<SynthesisImager> si;
      58             : 
      59             :         static casacore::Quantity asQuantity(const casacore::Record &rec, const char *field_name);
      60             : 
      61             :         static casacore::Quantity asQuantity(const casacore::String &field_name);
      62             : 
      63             :         static bool haveCFCache(const std::string &dirname);
      64             : 
      65             :         static int isCFS(const struct dirent *d);
      66             : 
      67             :         static std::vector<std::string> getCFCacheList(
      68             :                 const SynthesisParamsGrid &grid_pars, int size, int rank);
      69             : 
      70             :         void
      71           0 :         set_weighting(const casacore::Record &weight_pars, 
      72             :                       const std::vector<SynthesisParamsImage> &image_pars) {
      73           0 :                 casacore::String type =
      74           0 :                         ((weight_pars.fieldNumber("type") != -1)
      75             :                          ? weight_pars.asString("type")
      76             :                          : casacore::String("natural"));
      77           0 :                 casacore::String rmode =
      78           0 :                         ((weight_pars.fieldNumber("rmode") != -1)
      79             :                          ? weight_pars.asString("rmode")
      80             :                          : casacore::String("norm"));
      81           0 :                 casacore::Double robust =
      82           0 :                         ((weight_pars.fieldNumber("robust") != -1)
      83           0 :                          ? weight_pars.asDouble("robust")
      84             :                          : 0.0);
      85           0 :                 casacore::Int npixels =
      86           0 :                         ((weight_pars.fieldNumber("npixels") != -1)
      87           0 :                          ? weight_pars.asInt("npixels")
      88             :                          : 0);
      89           0 :                 casacore::Bool multifield =
      90           0 :                         ((weight_pars.fieldNumber("multifield") != -1)
      91           0 :                          ? weight_pars.asBool("multifield")
      92             :                          : false);
      93           0 :                 casacore::Bool usecubebriggs =
      94           0 :                         ((weight_pars.fieldNumber("usecubebrigss") != -1)
      95           0 :                          ? weight_pars.asBool("usecubebriggs")
      96             :                          : false);
      97           0 :                 casacore::Quantity noise =
      98           0 :                         ((weight_pars.fieldNumber("noise") != -1)
      99             :                          ? asQuantity(weight_pars, "noise")
     100           0 :                          : casacore::Quantity(0.0, "Jy"));
     101           0 :                 casacore::Quantity field_of_view =
     102           0 :                         ((weight_pars.fieldNumber("fieldofview") != -1)
     103             :                          ? asQuantity(weight_pars, "fieldofview")
     104           0 :                          : casacore::Quantity(0.0, "arcsec"));
     105           0 :                 const casacore::Array<casacore::String> &uv_taper_pars =
     106           0 :                         ((weight_pars.fieldNumber("uvtaper") != -1)
     107             :                          ? weight_pars.asArrayString("uvtaper")
     108             :                          : casacore::Array<casacore::String>());
     109           0 :                 casacore::Quantity bmaj(0.0, "deg"), bmin(0.0, "deg"), bpa(0.0, "deg");
     110           0 :                 casacore::String filter_type("");
     111           0 :                 if (uv_taper_pars.nelements() > 0) {
     112           0 :                         bmaj = asQuantity(uv_taper_pars(casacore::IPosition(1, 0)));
     113           0 :                         filter_type = casacore::String("gaussian");
     114           0 :                         if (uv_taper_pars.nelements() > 1) {
     115           0 :                                 bmin = asQuantity(uv_taper_pars(casacore::IPosition(1, 1)));
     116           0 :                                 if (uv_taper_pars.nelements() > 2)
     117           0 :                                         bpa = asQuantity(uv_taper_pars(casacore::IPosition(1, 2)));
     118             :                         } else /* uv_taper_pars.nelements() == 1 */ {
     119           0 :                                 bmin = bmaj;
     120             :                         }
     121             :                 }
     122             :                 // TODO: the following is the logic for setting 'filter_type' in
     123             :                 // synthesisimager_cmpt.cc...verify that the check on uv_taper_pars[0]
     124             :                 // length is not required here
     125             :                 //
     126             :                 // if (uv_taper_pars.nelements() > 0 && uv_taper_pars[0].length() > 0)
     127             :                 //     filter_type = casacore::String("gaussian");
     128           0 :                 si->weight(type, rmode, noise, robust, field_of_view, npixels,
     129             :                            multifield, usecubebriggs, filter_type, bmaj, bmin, bpa);
     130           0 :                 if (image_pars.size() == 1
     131           0 :                     && image_pars[0].stokes == casacore::String("I")
     132           0 :                     && weight_pars.asString("type") != casacore::String("natural")) {
     133           0 :                         si->getWeightDensity();
     134           0 :                         T::reduce_weight_density();
     135           0 :                         si->setWeightDensity();
     136             :                 }
     137           0 :         };
     138             : 
     139             : protected:
     140             :         void
     141           0 :         setup_imager(MPI_Comm comm,
     142             :                      std::vector<SynthesisParamsSelect> &select_pars,
     143             :                      std::vector<SynthesisParamsImage> &image_pars,
     144             :                      std::vector<SynthesisParamsGrid> &grid_pars,
     145             :                      casacore::Record &weight_pars) {
     146             :                 // Create a single imager component for every rank in comm.
     147             : 
     148           0 :                 teardown_imager();
     149           0 :                 int imaging_rank = T::effective_rank(comm);
     150           0 :                 if (imaging_rank == 0) {
     151           0 :                         si = std::unique_ptr<SynthesisImager>(new SynthesisImager());
     152           0 :                         for (auto s : select_pars)
     153           0 :                                 si->selectData(s);
     154           0 :                         for (size_t i = 0;
     155           0 :                              i < std::min(image_pars.size(), grid_pars.size());
     156             :                              ++i)
     157           0 :                                 si->defineImage(image_pars[i], grid_pars[i]);
     158             :                 }
     159           0 :                 int imaging_size = T::effective_size(comm);
     160           0 :                 if (imaging_rank >= 0 && imaging_size > 1) {
     161           0 :                         SynthesisParamsGrid &grid_pars0 = grid_pars.at(0);
     162           0 :                         if (!haveCFCache(grid_pars0.cfCache)) {
     163           0 :                                 if (imaging_rank == 0) {
     164           0 :                                         Vector<String> const empty;
     165           0 :                                         si->dryGridding(empty);
     166           0 :                                 }
     167           0 :                                 std::vector<std::string> cf_list =
     168             :                                         getCFCacheList(grid_pars0, imaging_size, imaging_rank);
     169           0 :                                 if (cf_list.size() > 0) {
     170           0 :                                         if (si == nullptr)
     171           0 :                                                 si = std::unique_ptr<SynthesisImager>(
     172           0 :                                                         new SynthesisImager());
     173           0 :                     casacore::Vector<casacore::String> const cf_list_casavec(cf_list);
     174           0 :                                         si->fillCFCache(
     175           0 :                                                 cf_list_casavec, grid_pars0.ftmachine, grid_pars0.cfCache,
     176           0 :                                                 grid_pars0.psTermOn, grid_pars0.aTermOn,grid_pars0.conjBeams);
     177           0 :                                 }
     178           0 :                         }
     179             :                         // create new imager instance, scrapping any that already exists
     180           0 :                         si = std::unique_ptr<SynthesisImager>(new SynthesisImager());
     181           0 :                         si->selectData(select_pars.at(imaging_rank));
     182           0 :                         si->defineImage(image_pars.at(imaging_rank),
     183           0 :                                         grid_pars.at(imaging_rank));
     184             :                 }
     185           0 :                 if (imaging_rank >= 0)
     186           0 :                         set_weighting(weight_pars, image_pars);
     187           0 :         };
     188             : 
     189           0 :         void teardown_imager() {
     190           0 :                 si.reset();
     191           0 :         };
     192             : 
     193             : public:
     194             :         void
     195           0 :         make_psf() {
     196             :                 // TODO: verify this is correct for all ranks
     197           0 :                 if (si != nullptr) si->makePSF();
     198           0 :         };
     199             : 
     200             :         void
     201           0 :         execute_major_cycle() {
     202           0 :                 casacore::Record rec;
     203           0 :                 rec.define("lastcycle", T::is_clean_complete());
     204             :                 // TODO: verify this is correct for all ranks
     205           0 :                 if (si != nullptr) si->executeMajorCycle(rec);
     206           0 :                 T::end_major_cycle();
     207           0 :         };
     208             : 
     209             :         void
     210           0 :         predict_model() {
     211             :                 // TODO: verify this is correct for all ranks
     212           0 :                 if (si != nullptr) si->predictModel();
     213           0 :         };
     214             : };
     215             : 
     216             : // TODO: this method is a utility function...move it into another module?
     217             : template <class T>
     218             : casacore::Quantity
     219           0 : SynthesisImagerMixin<T>::asQuantity(
     220             :         const casacore::Record &rec, const char *field_name) {
     221           0 :         casacore::Bool success = false;
     222           0 :         casacore::QuantumHolder qh;
     223           0 :         casacore::String err_str;
     224           0 :         switch (rec.dataType(field_name)) {
     225           0 :         case casacore::DataType::TpRecord:
     226           0 :                 success = qh.fromRecord(err_str, rec.subRecord(field_name));
     227           0 :                 break;
     228           0 :         case casacore::DataType::TpString:
     229           0 :                 success = qh.fromString(err_str, rec.asString(field_name));
     230           0 :                 break;
     231           0 :         default:
     232           0 :                 break;
     233             :         }
     234           0 :         if (!(success && qh.isQuantity())) {
     235           0 :                 ostringstream oss;
     236           0 :                 oss << "Error in converting quantity: " << err_str;
     237           0 :                 throw (casacore::AipsError(oss.str()));
     238           0 :         }
     239           0 :         return qh.asQuantity();
     240           0 : };
     241             : 
     242             : // TODO: this method is a utility function...move it into another module?
     243             : template <class T>
     244             : casacore::Quantity
     245           0 : SynthesisImagerMixin<T>::asQuantity(const casacore::String &field_name) {
     246           0 :         casacore::QuantumHolder qh;
     247           0 :         casacore::String err_str;
     248           0 :         casacore::Bool success = qh.fromString(err_str, field_name);
     249           0 :         if (!(success && qh.isQuantity())) {
     250           0 :                 ostringstream oss;
     251           0 :                 oss << "Error in converting quantity: " << err_str;
     252           0 :                 throw (casacore::AipsError(oss.str()));
     253           0 :         }
     254           0 :         return qh.asQuantity();
     255           0 : };
     256             : 
     257             : template <class T>
     258             : bool
     259           0 : SynthesisImagerMixin<T>::haveCFCache(const std::string &dirname) {
     260             :         struct stat stat_buf;
     261           0 :         return (stat(dirname.c_str(), &stat_buf) == 0
     262           0 :                 && S_ISDIR(stat_buf.st_mode));
     263             : };
     264             : 
     265             : template <class T>
     266             : int
     267           0 : SynthesisImagerMixin<T>::isCFS(const struct dirent *d) {
     268           0 :         std::string name(d->d_name);
     269           0 :         return name.find("CFS") == 0;
     270           0 : };
     271             : 
     272             : template <class T>
     273             : std::vector<std::string>
     274           0 : SynthesisImagerMixin<T>::getCFCacheList(
     275             :         const SynthesisParamsGrid &grid_pars, int size, int rank) {
     276             :         // return vector for all ranks, even if it's empty
     277           0 :         std::vector<std::string> result;
     278             :         struct dirent **namelist;
     279           0 :         int nCFS = scandir(grid_pars.cfCache.c_str(), &namelist, 
     280             :                            SynthesisImagerMixin::isCFS, alphasort);
     281           0 :         if (nCFS >= 0) {
     282           0 :                 size = std::min(size, nCFS);
     283             :                 // Note that with size having been redefined as the minimum of the
     284             :                 // original size value and nCFS, if rank >= size, then no strings
     285             :                 // are added to the result vector in the following loop.
     286           0 :                 for (int n = rank; n < nCFS; n += size) {
     287           0 :                         std::string name(namelist[n]->d_name);
     288           0 :                         result.push_back(name);
     289             :                 }
     290           0 :                 free(namelist);
     291             :         } else {
     292             :                 // errno == ENOMEM
     293           0 :                 std::error_condition ec(errno, std::generic_category());
     294           0 :                 throw casacore::AipsError(casacore::String("Failed to scan cf cache directory '")
     295           0 :                                 + grid_pars.cfCache + casacore::String("': ")
     296           0 :                                 + casacore::String(ec.message()));
     297             :         }
     298           0 :         return result;
     299           0 : };
     300             : 
     301             : } // namespace casa
     302             : 
     303             : #endif // SYNTHESIS_IMAGER_MIXIN_H_

Generated by: LCOV version 1.16