diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a2c93c..a41c27d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,7 +154,10 @@ target_link_libraries( set(ASIBFM700_PCM_FIT_APP asibfm700_pcm_fit) add_executable(${ASIBFM700_PCM_FIT_APP} asibfm700_pcm_fit.cpp) -target_link_libraries(${ASIBFM700_PCM_FIT_APP} PUBLIC cxxopts::cxxopts mcc) +target_link_libraries( + ${ASIBFM700_PCM_FIT_APP} + PUBLIC cxxopts::cxxopts ${ASIBFM700_LIB} +) # include(CMakePrintHelpers) # cmake_print_properties( diff --git a/asibfm700_pcm_fit.cpp b/asibfm700_pcm_fit.cpp index e45b4b3..75a54c8 100644 --- a/asibfm700_pcm_fit.cpp +++ b/asibfm700_pcm_fit.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -8,9 +8,9 @@ #include #include -static constexpr mcc::MccMountType MOUNT_TYPE{mcc::MccMountType::CROSSAXIS_TYPE}; +#include "asibfm700_configfile.h" -// #include "asibfm700_configfile.h" +// static constexpr mcc::MccMountType MOUNT_TYPE{mcc::MccMountType::CROSSAXIS_TYPE}; int main(int argc, char* argv[]) { @@ -24,42 +24,63 @@ int main(int argc, char* argv[]) options.add_options()("v,verbose", "Verbose output"); options.add_options()("input_file", "Input encoder-celestial coordinate pairs file", - cxxopts::value()->default_value("pcm_coords.dat")); + cxxopts::value>()->default_value("")); - options.add_options()("c,config", "Mount configuration filename (by default use of hardcoded one)", - cxxopts::value()->default_value("")); + options.add_options()("niter", "Max number of iterations for robust linear regression method", + cxxopts::value()->default_value("100")); - options.positional_help("[input_encoder-celestial_pair_filename]"); + // options.positional_help("[input_encoder-celestial_pair_filename]"); + options.positional_help("mount-server-config-filename input-pcm-data-filename results-filename"); options.parse_positional({"input_file"}); - mcc::impl::MccPCMFitter pcm_fitter; + mcc::impl::MccPCMFitter pcm_fitter; + mcc::impl::MccPCMFitter::compute_params_t comp_pars; + + asibfm700::Asibfm700MountConfig mount_cfg; try { auto opt_result = options.parse(argc, argv); - if (opt_result["help"].count() || argc == 1) { + auto pos_args = opt_result["input_file"].as>(); + + if (opt_result["help"].count() || argc == 1 || (pos_args.size() < 3)) { std::println("{}", options.help()); std::println( - "[input_encoder-celestial_pair_filename] - Input encoder-celestial coordinate pairs filename. " - "It must be in the format: ENCODER_HA ENCODER_DEC ENCODER_EPOCH RA_ICRS DEC_ICRS TEMP(C) PRESSURE(hPa) " - "HUMIDITY([0-1])", - options.help()); + "\tmount-server-config-filename - filename of the ASIB FM-700 mount server configuration\n" + "\tinput-pcm-data-filename - filename of the input encoder-celestial coordinate pairs data\n" + "\tresults-filename - filename of the fitting results\n"); + + // std::println( + // "[input_encoder-celestial_pair_filename] - Input encoder-celestial coordinate pairs filename. " + // "It must be in the format: ENCODER_HA ENCODER_DEC ENCODER_EPOCH RA_ICRS DEC_ICRS TEMP(C) + // PRESSURE(hPa) " "HUMIDITY([0-1])", options.help()); return 0; } + std::string cfg_fname = pos_args[0]; + std::string pcm_data_fname = pos_args[1]; + std::string result_fname = pos_args[2]; + bool verbose = false; if (opt_result["verbose"].count()) { verbose = true; } + auto l_err = mount_cfg.load(cfg_fname); + if (l_err) { + std::println("Cannot load mount config: {}", l_err.message()); + return 2; + } + + asibfm700::Asibfm700PCM::pcm_data_t pcm_data = mount_cfg.pcmData(); + std::ifstream fst; - auto fname = opt_result["input_file"].as(); - fst.open(fname); + fst.open(pcm_data_fname); if (!fst.is_open()) { - std::println("Cannot open input file {}", fname); + std::println("Cannot open input file {}", pcm_data_fname); return 2; } @@ -67,6 +88,10 @@ int main(int argc, char* argv[]) double temp, press, humi; std::optional num; std::string str; + std::string fmt_head; + + std::string_view delim{" "}; + std::string_view sv; std::array tokens; @@ -79,8 +104,39 @@ int main(int argc, char* argv[]) mcc::impl::MccSkyPoint sp; mcc::impl::MccError err; - while (!fst.eof()) { - std::getline(fst, str); + if (verbose) { + std::format_to(std::back_inserter(fmt_head), "{:^12}{}{:^12}{}{:^11}{}{:^11}{}{:^12}{}{:^6}{}{:^7}{}{:^4}", + "ENC_HA", delim, "ENC_DEC", delim, "ENC_MJD", delim, "RA_ICRS", delim, "DEC_ICRS", delim, + "TEMP", delim, "PRESS", delim, "HUMI"); + + str = std::string(fmt_head.size(), '*'); + std::println("{}", str); + + auto fmt = std::format("*{{:^{}}}*", fmt_head.size() - 2); + std::println("{}", std::vformat(std::string_view(fmt.begin(), fmt.end()), + std::make_format_args(" INPUT HARDWARE-CELESTIAL COORDINATE PAIRS "))); + + fmt = std::format("*{{:<{}}}*", fmt_head.size() - 2); + auto fmt_sv = std::string_view(fmt.begin(), fmt.end()); + std::println("{}", std::vformat(fmt_sv, std::make_format_args(""))); + auto s = std::format("{} {}", " SITE LAT:", mount_cfg.siteLatitude().sexagesimal()); + std::println("{}", std::vformat(fmt_sv, std::make_format_args(s))); + s = std::format("{} {}", " SITE LON:", mount_cfg.siteLongitude().sexagesimal()); + std::println("{}", std::vformat(fmt_sv, std::make_format_args(s))); + s = std::format("{} {} meters", " SITE ELEV:", mount_cfg.siteElevation()); + std::println("{}", std::vformat(fmt_sv, std::make_format_args(s))); + + s = std::format("{} {} ", " PCM TYPE:", mcc::impl::mccDefaultPCMTypeString(pcm_data.type)); + std::println("{}", std::vformat(fmt_sv, std::make_format_args(s))); + + std::println("{}", str); + std::println("{}", fmt_head); + std::println("{}", std::string(fmt_head.size(), '-')); + } + + while (std::getline(fst, str)) { + // while (!fst.eof()) { + // std::getline(fst, str); sv = mcc::utils::trimSpaces(str); if (!sv.size()) { // an empty string @@ -143,11 +199,13 @@ int main(int argc, char* argv[]) } humi = num.value(); + // update meteo parameters here mcc::impl::MccSkyPoint::cctEngine.updateMeteoERFA( {.temperature = temp, .humidity = humi, .pressure = press}); sp.from(mcc::impl::MccSkyRADEC_ICRS{ra, dec}); + // astrometric transformations are here (and it needs meteo updated above!!!) err = pcm_fitter.addPoint(sp, mcc::impl::MccGenXY{enc_ha, enc_dec, ep}); if (err) { std::println("An error occured: {}", err.message()); @@ -155,14 +213,66 @@ int main(int argc, char* argv[]) } if (verbose) { - std::println("{} {} {:.5f} {} {} {:.1f} {:.2f} {:.2f}", enc_ha.sexagesimal(true), - enc_dec.sexagesimal(), ep.MJD(), ra.sexagesimal(true), dec.sexagesimal(), temp, press, - humi); + std::println("{:>12}{}{:>12}{}{:>11.5f}{}{:>11}{}{:>12}{}{:>5.1f}{}{:>7.2f}{}{:>4.2f}", + enc_ha.sexagesimal(true), delim, enc_dec.sexagesimal(), delim, ep.MJD(), delim, + ra.sexagesimal(true), delim, dec.sexagesimal(), delim, temp, delim, press, delim, humi); } } fst.close(); + // fitting + + if (verbose) { + std::println("\n"); + + fmt_head.clear(); + std::format_to(std::back_inserter(fmt_head), "{:^12}{}{:^12}{}{:^12}{}{:^12}{}{:^14}{}{:^14}", "ENC_HA", + delim, "ENC_DEC", delim, "OBS_HA", delim, "OBS_DEC", delim, "dHA(OBS-ENC)", delim, + "dDEC(OBS-ENC)"); + + str = std::string(fmt_head.size(), '*'); + std::println("{}", str); + + auto fmt = std::format("*{{:^{}}}*", fmt_head.size() - 2); + std::println("{}", std::vformat(std::string_view(fmt.begin(), fmt.end()), + std::make_format_args(" FITTED HARDWARE-CELESTIAL COORDINATE PAIRS "))); + + std::println("{}", str); + + std::println("{}", fmt_head); + std::println("{}", std::string(fmt_head.size(), '-')); + + + fmt = std::format("*{{:<{}}}*", fmt_head.size() - 2); + + auto tab = pcm_fitter.getPCMTable(); + + for (auto const& el : tab) { + std::println("{:>12}{}{:>12}{}{:>12}{}{:>12}{}{:>14}{}{:>14}", el.hw.x().sexagesimal(true), delim, + el.hw.y().sexagesimal(), delim, el.target.x().sexagesimal(true), delim, + el.target.y().sexagesimal(), delim, mcc::impl::MccAngleFancyString(el.res.x()), delim, + mcc::impl::MccAngleFancyString(el.res.y())); + } + } + + return 0; + + if (pcm_data.type == mcc::impl::MccDefaultPCMType::PCM_TYPE_GEOMETRY || + pcm_data.type == mcc::impl::MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE) { + if (opt_result["niter"].count()) { + comp_pars.max_iter = opt_result["niter"].as() ? opt_result["niter"].as() : 100; + } + } + + auto comp_result = pcm_fitter.computeModel(pcm_data, comp_pars); + + if (comp_result.error) { + std::println("An error occured while fit PCM data: {}", comp_result.error.message()); + return 200; + } + + } catch (cxxopts::exceptions::parsing& ex) { std::println("An error occured while parsing input options: {}", ex.what());