#include #include #include #include #include #include #include #include "asibfm700_configfile.h" // static constexpr mcc::MccMountType MOUNT_TYPE{mcc::MccMountType::CROSSAXIS_TYPE}; int main(int argc, char* argv[]) { /* COMMANDLINE OPTS */ cxxopts::Options options(argv[0], "Astrosib (c) FM700 mount PCM fitter\n"); options.allow_unrecognised_options(); options.add_options()("h,help", "Print usage"); options.add_options()("v,verbose", "Verbose output"); options.add_options()("input_file", "Input encoder-celestial coordinate pairs file", 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("mount-server-config-filename input-pcm-data-filename results-filename"); options.parse_positional({"input_file"}); 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); 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( "\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; fst.open(pcm_data_fname); if (!fst.is_open()) { std::println("Cannot open input file {}", pcm_data_fname); return 2; } size_t sz; 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; mcc::impl::MccCelestialCoordEpoch ep; mcc::impl::MccAngleX enc_ha; mcc::impl::MccAngleY enc_dec; mcc::impl::MccAngleRA_ICRS ra; mcc::impl::MccAngleDEC_ICRS dec; mcc::impl::MccSkyPoint sp; mcc::impl::MccError err; 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 continue; } if (sv[0] == '#') { // comment continue; } auto toks = std::views::split(sv, std::string_view(" ")) | std::views::filter([](auto const& r) { return std::ranges::size(r); }); sz = std::ranges::distance(toks.begin(), toks.end()); if (sz < 8) { std::println("Invalid input file format! Number of tokens must be at least 8: {}", str); return 3; } size_t i = 0; for (auto const& t : toks) { tokens[i++] = {t.begin(), t.end()}; } // degrees or sexagesimal hours representations enc_ha = {tokens[0], mcc::impl::mcc_hms}; // degrees or sexagesimal degrees representations enc_dec = {tokens[1]}; if (!ep.fromCharRange(tokens[2])) { std::println("Invalid input file format! Invalid encoder coordinates epoch representation: {}", tokens[2]); return 4; } // degrees or sexagesimal hours representations ra = {tokens[3], mcc::impl::mcc_hms}; // degrees or sexagesimal degrees representations dec = {tokens[4]}; num = mcc::utils::numFromStr(tokens[5]); if (!num) { std::println("Invalid input file format! Non-numeric representation of temperature: {}", tokens[5]); return 5; } temp = num.value(); num = mcc::utils::numFromStr(tokens[6]); if (!num) { std::println("Invalid input file format! Non-numeric representation of pressure: {}", tokens[6]); return 6; } press = num.value(); num = mcc::utils::numFromStr(tokens[7]); if (!num) { std::println("Invalid input file format! Non-numeric representation of humidity: {}", tokens[7]); return 7; } 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()); return 8; } if (verbose) { 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()); return 1; } catch (std::exception& ex) { std::println("An exception occured: {}", ex.what()); return 10; } catch (...) { std::println("An unhandled exception occured!"); return 100; } return 0; }