00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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 {
00115 bmin = bmaj;
00116 }
00117 }
00118
00119
00120
00121
00122
00123
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
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
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
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
00200 if (si != nullptr) si->executeMajorCycle(rec);
00201 T::end_major_cycle();
00202 };
00203
00204 void
00205 predict_model() {
00206
00207 if (si != nullptr) si->predictModel();
00208 };
00209 };
00210
00211
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
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
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
00279
00280
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
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 }
00297
00298 #endif // SYNTHESIS_IMAGER_MIXIN_H_