SynthesisImagerMixin.h

Go to the documentation of this file.
00001 // -*- mode: c++ -*-
00002 //# SynthesisImagerMixin.h: Mixin for using SynthesisImager class in parallel
00003 //#                         imaging framework (ParallelImagerMixin)
00004 //# Copyright (C) 2016
00005 //# Associated Universities, Inc. Washington DC, USA.
00006 //#
00007 //# This library is free software; you can redistribute it and/or modify it
00008 //# under the terms of the GNU Library General Public License as published by
00009 //# the Free Software Foundation; either version 2 of the License, or (at your
00010 //# option) any later version.
00011 //#
00012 //# This library is distributed in the hope that it will be useful, but WITHOUT
00013 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00015 //# License for more details.
00016 //#
00017 //# You should have received a copy of the GNU Library General Public License
00018 //# along with this library; if not, write to the Free Software Foundation,
00019 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00020 //#
00021 //# Correspondence concerning AIPS++ should be addressed as follows:
00022 //#        Internet email: aips2-request@nrao.edu.
00023 //#        Postal address: AIPS++ Project Office
00024 //#                        National Radio Astronomy Observatory
00025 //#                        520 Edgemont Road
00026 //#                        Charlottesville, VA 22903-2475 USA
00027 //#
00028 #ifndef SYNTHESIS_IMAGER_MIXIN_H_
00029 #define SYNTHESIS_IMAGER_MIXIN_H_
00030 
00031 #include <casa/Containers/Record.h>
00032 #include <casa/Arrays/Array.h>
00033 #include <synthesis/ImagerObjects/MPIGlue.h>
00034 #include <synthesis/ImagerObjects/SynthesisImager.h>
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 #include <algorithm>
00038 #include <memory>
00039 #include <vector>
00040 #include <unistd.h>
00041 #include <cerrno>
00042 #include <cstring>
00043 #include <string>
00044 #include <dirent.h>
00045 #include <system_error>
00046 
00047 namespace casa {
00048 
00052 template <class T>
00053 class SynthesisImagerMixin
00054         : public T {
00055 
00056 private:
00057         std::unique_ptr<SynthesisImager> si;
00058 
00059         static Quantity asQuantity(const Record &rec, const char *field_name);
00060 
00061         static Quantity asQuantity(const String &field_name);
00062 
00063         static bool haveCFCache(const std::string &dirname);
00064 
00065         static int isCFS(const struct dirent *d);
00066 
00067         static std::vector<std::string> getCFCacheList(
00068                 const SynthesisParamsGrid &grid_pars, int size, int rank);
00069 
00070         void
00071         set_weighting(const Record &weight_pars, 
00072                       const std::vector<SynthesisParamsImage> &image_pars) {
00073                 String type =
00074                         ((weight_pars.fieldNumber("type") != -1)
00075                          ? weight_pars.asString("type")
00076                          : String("natural"));
00077                 String rmode =
00078                         ((weight_pars.fieldNumber("rmode") != -1)
00079                          ? weight_pars.asString("rmode")
00080                          : String("norm"));
00081                 Double robust =
00082                         ((weight_pars.fieldNumber("robust") != -1)
00083                          ? weight_pars.asDouble("robust")
00084                          : 0.0);
00085                 Int npixels =
00086                         ((weight_pars.fieldNumber("npixels") != -1)
00087                          ? weight_pars.asInt("npixels")
00088                          : 0);
00089                 Bool multifield =
00090                         ((weight_pars.fieldNumber("multifield") != -1)
00091                          ? weight_pars.asBool("multifield")
00092                          : false);
00093                 Quantity noise =
00094                         ((weight_pars.fieldNumber("noise") != -1)
00095                          ? asQuantity(weight_pars, "noise")
00096                          : Quantity(0.0, "Jy"));
00097                 Quantity field_of_view =
00098                         ((weight_pars.fieldNumber("fieldofview") != -1)
00099                          ? asQuantity(weight_pars, "fieldofview")
00100                          : Quantity(0.0, "arcsec"));
00101                 const Array<String> &uv_taper_pars =
00102                         ((weight_pars.fieldNumber("uvtaper") != -1)
00103                          ? weight_pars.asArrayString("uvtaper")
00104                          : Array<String>());
00105                 Quantity bmaj(0.0, "deg"), bmin(0.0, "deg"), bpa(0.0, "deg");
00106                 String filter_type("");
00107                 if (uv_taper_pars.nelements() > 0) {
00108                         bmaj = asQuantity(uv_taper_pars(IPosition(1, 0)));
00109                         filter_type = String("gaussian");
00110                         if (uv_taper_pars.nelements() > 1) {
00111                                 bmin = asQuantity(uv_taper_pars(IPosition(1, 1)));
00112                                 if (uv_taper_pars.nelements() > 2)
00113                                         bpa = asQuantity(uv_taper_pars(IPosition(1, 2)));
00114                         } else /* uv_taper_pars.nelements() == 1 */ {
00115                                 bmin = bmaj;
00116                         }
00117                 }
00118                 // TODO: the following is the logic for setting 'filter_type' in
00119                 // synthesisimager_cmpt.cc...verify that the check on uv_taper_pars[0]
00120                 // length is not required here
00121                 //
00122                 // if (uv_taper_pars.nelements() > 0 && uv_taper_pars[0].length() > 0)
00123                 //     filter_type = String("gaussian");
00124                 si->weight(type, rmode, noise, robust, field_of_view, npixels,
00125                            multifield, filter_type, bmaj, bmin, bpa);
00126                 if (image_pars.size() == 1
00127                     && image_pars[0].stokes == String("I")
00128                     && weight_pars.asString("type") != String("natural")) {
00129                         si->getWeightDensity();
00130                         T::reduce_weight_density();
00131                         si->setWeightDensity();
00132                 }
00133         };
00134 
00135 protected:
00136         void
00137         setup_imager(MPI_Comm comm,
00138                      std::vector<SynthesisParamsSelect> &select_pars,
00139                      std::vector<SynthesisParamsImage> &image_pars,
00140                      std::vector<SynthesisParamsGrid> &grid_pars,
00141                      Record &weight_pars) {
00142                 // Create a single imager component for every rank in comm.
00143 
00144                 teardown_imager();
00145                 int imaging_rank = T::effective_rank(comm);
00146                 if (imaging_rank == 0) {
00147                         si = std::unique_ptr<SynthesisImager>(new SynthesisImager());
00148                         for (auto s : select_pars)
00149                                 si->selectData(s);
00150                         for (size_t i = 0;
00151                              i < std::min(image_pars.size(), grid_pars.size());
00152                              ++i)
00153                                 si->defineImage(image_pars[i], grid_pars[i]);
00154                 }
00155                 int imaging_size = T::effective_size(comm);
00156                 if (imaging_rank >= 0 && imaging_size > 1) {
00157                         SynthesisParamsGrid &grid_pars0 = grid_pars.at(0);
00158                         if (!haveCFCache(grid_pars0.cfCache)) {
00159                                 if (imaging_rank == 0) {
00160                                         std::vector<std::string> empty;
00161                                         si->dryGridding(empty);
00162                                 }
00163                                 std::vector<std::string> cf_list =
00164                                         getCFCacheList(grid_pars0, imaging_size, imaging_rank);
00165                                 if (cf_list.size() > 0) {
00166                                         if (si == nullptr)
00167                                                 si = std::unique_ptr<SynthesisImager>(
00168                                                         new SynthesisImager());
00169                                         si->fillCFCache(
00170                                                 cf_list, grid_pars0.ftmachine, grid_pars0.cfCache,
00171                                                 grid_pars0.psTermOn, grid_pars0.aTermOn);
00172                                 }
00173                         }
00174                         // create new imager instance, scrapping any that already exists
00175                         si = std::unique_ptr<SynthesisImager>(new SynthesisImager());
00176                         si->selectData(select_pars.at(imaging_rank));
00177                         si->defineImage(image_pars.at(imaging_rank),
00178                                         grid_pars.at(imaging_rank));
00179                 }
00180                 if (imaging_rank >= 0)
00181                         set_weighting(weight_pars, image_pars);
00182         };
00183 
00184         void teardown_imager() {
00185                 si.reset();
00186         };
00187 
00188 public:
00189         void
00190         make_psf() {
00191                 // TODO: verify this is correct for all ranks
00192                 if (si != nullptr) si->makePSF();
00193         };
00194 
00195         void
00196         execute_major_cycle() {
00197                 Record rec;
00198                 rec.define("lastcycle", T::is_clean_complete());
00199                 // TODO: verify this is correct for all ranks
00200                 if (si != nullptr) si->executeMajorCycle(rec);
00201                 T::end_major_cycle();
00202         };
00203 
00204         void
00205         predict_model() {
00206                 // TODO: verify this is correct for all ranks
00207                 if (si != nullptr) si->predictModel();
00208         };
00209 };
00210 
00211 // TODO: this method is a utility function...move it into another module?
00212 template <class T>
00213 Quantity
00214 SynthesisImagerMixin<T>::asQuantity(
00215         const Record &rec, const char *field_name) {
00216         Bool success = false;
00217         QuantumHolder qh;
00218         String err_str;
00219         switch (rec.dataType(field_name)) {
00220         case DataType::TpRecord:
00221                 success = qh.fromRecord(err_str, rec.subRecord(field_name));
00222                 break;
00223         case DataType::TpString:
00224                 success = qh.fromString(err_str, rec.asString(field_name));
00225                 break;
00226         default:
00227                 break;
00228         }
00229         if (!(success && qh.isQuantity())) {
00230                 ostringstream oss;
00231                 oss << "Error in converting quantity: " << err_str;
00232                 throw (AipsError(oss.str()));
00233         }
00234         return qh.asQuantity();
00235 };
00236 
00237 // TODO: this method is a utility function...move it into another module?
00238 template <class T>
00239 Quantity
00240 SynthesisImagerMixin<T>::asQuantity(const String &field_name) {
00241         QuantumHolder qh;
00242         String err_str;
00243         Bool success = qh.fromString(err_str, field_name);
00244         if (!(success && qh.isQuantity())) {
00245                 ostringstream oss;
00246                 oss << "Error in converting quantity: " << err_str;
00247                 throw (AipsError(oss.str()));
00248         }
00249         return qh.asQuantity();
00250 };
00251 
00252 template <class T>
00253 bool
00254 SynthesisImagerMixin<T>::haveCFCache(const std::string &dirname) {
00255         struct stat stat_buf;
00256         return (stat(dirname.c_str(), &stat_buf) == 0
00257                 && S_ISDIR(stat_buf.st_mode));
00258 };
00259 
00260 template <class T>
00261 int
00262 SynthesisImagerMixin<T>::isCFS(const struct dirent *d) {
00263         std::string name(d->d_name);
00264         return name.find("CFS") == 0;
00265 };
00266 
00267 template <class T>
00268 std::vector<std::string>
00269 SynthesisImagerMixin<T>::getCFCacheList(
00270         const SynthesisParamsGrid &grid_pars, int size, int rank) {
00271         // return vector for all ranks, even if it's empty
00272         std::vector<std::string> result;
00273         struct dirent **namelist;
00274         int nCFS = scandir(grid_pars.cfCache.c_str(), &namelist, 
00275                            SynthesisImagerMixin::isCFS, alphasort);
00276         if (nCFS >= 0) {
00277                 size = std::min(size, nCFS);
00278                 // Note that with size having been redefined as the minimum of the
00279                 // original size value and nCFS, if rank >= size, then no strings
00280                 // are added to the result vector in the following loop.
00281                 for (int n = rank; n < nCFS; n += size) {
00282                         std::string name(namelist[n]->d_name);
00283                         result.push_back(name);
00284                 }
00285                 free(namelist);
00286         } else {
00287                 // errno == ENOMEM
00288                 std::error_condition ec(errno, std::generic_category());
00289                 throw AipsError(String("Failed to scan cf cache directory '")
00290                                 + grid_pars.cfCache + String("': ")
00291                                 + String(ec.message()));
00292         }
00293         return result;
00294 };
00295 
00296 } // namespace casa
00297 
00298 #endif // SYNTHESIS_IMAGER_MIXIN_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 31 Aug 2016 for casa by  doxygen 1.6.1